4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
775 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
777 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
778 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
779 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
780 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
783 * @cfg {Boolean} hidden (true|false) hide the element
784 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
785 * @cfg {String} fa (ban|check|...) font awesome icon
786 * @cfg {Number} fasize (1|2|....) font awsome size
788 * @cfg {String} icon (info-sign|check|...) glyphicon name
790 * @cfg {String} html content of column.
793 * Create a new Column
794 * @param {Object} config The config object
797 Roo.bootstrap.Column = function(config){
798 Roo.bootstrap.Column.superclass.constructor.call(this, config);
801 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
819 getAutoCreate : function(){
820 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
828 ['xs','sm','md','lg'].map(function(size){
829 //Roo.log( size + ':' + settings[size]);
831 if (settings[size+'off'] !== false) {
832 cfg.cls += ' col-' + settings[size+'off'] + '-offset';
835 if (settings[size] === false) {
838 Roo.log(settings[size]);
839 if (!settings[size]) { // 0 = hidden
840 cfg.cls += ' hidden-' + size;
843 cfg.cls += ' col-' + size + '-' + settings[size];
848 cfg.cls += ' hidden';
851 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
852 cfg.cls +=' alert alert-' + this.alert;
856 if (this.html.length) {
857 cfg.html = this.html;
861 if (this.fasize > 1) {
862 fasize = ' fa-' + this.fasize + 'x';
864 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
869 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
888 * @class Roo.bootstrap.Container
889 * @extends Roo.bootstrap.Component
890 * Bootstrap Container class
891 * @cfg {Boolean} jumbotron is it a jumbotron element
892 * @cfg {String} html content of element
893 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
894 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
895 * @cfg {String} header content of header (for panel)
896 * @cfg {String} footer content of footer (for panel)
897 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
898 * @cfg {String} tag (header|aside|section) type of HTML tag.
899 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
900 * @cfg {String} fa (ban|check|...) font awesome icon
901 * @cfg {String} icon (info-sign|check|...) glyphicon name
902 * @cfg {Boolean} hidden (true|false) hide the element
906 * Create a new Container
907 * @param {Object} config The config object
910 Roo.bootstrap.Container = function(config){
911 Roo.bootstrap.Container.superclass.constructor.call(this, config);
914 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
928 getChildContainer : function() {
934 if (this.panel.length) {
935 return this.el.select('.panel-body',true).first();
942 getAutoCreate : function(){
945 tag : this.tag || 'div',
949 if (this.jumbotron) {
950 cfg.cls = 'jumbotron';
955 // - this is applied by the parent..
957 // cfg.cls = this.cls + '';
960 if (this.sticky.length) {
962 var bd = Roo.get(document.body);
963 if (!bd.hasClass('bootstrap-sticky')) {
964 bd.addClass('bootstrap-sticky');
965 Roo.select('html',true).setStyle('height', '100%');
968 cfg.cls += 'bootstrap-sticky-' + this.sticky;
972 if (this.well.length) {
976 cfg.cls +=' well well-' +this.well;
985 cfg.cls += ' hidden';
989 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
990 cfg.cls +=' alert alert-' + this.alert;
995 if (this.panel.length) {
996 cfg.cls += ' panel panel-' + this.panel;
998 if (this.header.length) {
1001 cls : 'panel-heading',
1004 cls : 'panel-title',
1017 if (this.footer.length) {
1019 cls : 'panel-footer',
1028 body.html = this.html || cfg.html;
1029 // prefix with the icons..
1031 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1034 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1039 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1040 cfg.cls = 'container';
1046 titleEl : function()
1048 if(!this.el || !this.panel.length || !this.header.length){
1052 return this.el.select('.panel-title',true).first();
1055 setTitle : function(v)
1057 var titleEl = this.titleEl();
1063 titleEl.dom.innerHTML = v;
1066 getTitle : function()
1069 var titleEl = this.titleEl();
1075 return titleEl.dom.innerHTML;
1089 * @class Roo.bootstrap.Img
1090 * @extends Roo.bootstrap.Component
1091 * Bootstrap Img class
1092 * @cfg {Boolean} imgResponsive false | true
1093 * @cfg {String} border rounded | circle | thumbnail
1094 * @cfg {String} src image source
1095 * @cfg {String} alt image alternative text
1096 * @cfg {String} href a tag href
1097 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1100 * Create a new Input
1101 * @param {Object} config The config object
1104 Roo.bootstrap.Img = function(config){
1105 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1111 * The img click event for the img.
1112 * @param {Roo.EventObject} e
1118 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1120 imgResponsive: true,
1126 getAutoCreate : function(){
1130 cls: (this.imgResponsive) ? 'img-responsive' : '',
1134 cfg.html = this.html || cfg.html;
1136 cfg.src = this.src || cfg.src;
1138 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1139 cfg.cls += ' img-' + this.border;
1156 a.target = this.target;
1162 return (this.href) ? a : cfg;
1165 initEvents: function() {
1168 this.el.on('click', this.onClick, this);
1172 onClick : function(e)
1174 Roo.log('img onclick');
1175 this.fireEvent('click', this, e);
1189 * @class Roo.bootstrap.Link
1190 * @extends Roo.bootstrap.Component
1191 * Bootstrap Link Class
1192 * @cfg {String} alt image alternative text
1193 * @cfg {String} href a tag href
1194 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1195 * @cfg {String} html the content of the link.
1196 * @cfg {Boolean} preventDefault (true | false) default false
1200 * Create a new Input
1201 * @param {Object} config The config object
1204 Roo.bootstrap.Link = function(config){
1205 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1211 * The img click event for the img.
1212 * @param {Roo.EventObject} e
1218 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1222 preventDefault: false,
1224 getAutoCreate : function(){
1228 html : this.html || 'html-missing'
1235 cfg.href = this.href || '#';
1237 cfg.target = this.target;
1243 initEvents: function() {
1245 if(!this.href || this.preventDefault){
1246 this.el.on('click', this.onClick, this);
1250 onClick : function(e)
1252 if(this.preventDefault){
1255 //Roo.log('img onclick');
1256 this.fireEvent('click', this, e);
1269 * @class Roo.bootstrap.Header
1270 * @extends Roo.bootstrap.Component
1271 * Bootstrap Header class
1272 * @cfg {String} html content of header
1273 * @cfg {Number} level (1|2|3|4|5|6) default 1
1276 * Create a new Header
1277 * @param {Object} config The config object
1281 Roo.bootstrap.Header = function(config){
1282 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1285 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1293 getAutoCreate : function(){
1296 tag: 'h' + (1 *this.level),
1297 html: this.html || 'fill in html'
1309 * Ext JS Library 1.1.1
1310 * Copyright(c) 2006-2007, Ext JS, LLC.
1312 * Originally Released Under LGPL - original licence link has changed is not relivant.
1315 * <script type="text/javascript">
1319 * @class Roo.bootstrap.MenuMgr
1320 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1323 Roo.bootstrap.MenuMgr = function(){
1324 var menus, active, groups = {}, attached = false, lastShow = new Date();
1326 // private - called when first menu is created
1329 active = new Roo.util.MixedCollection();
1330 Roo.get(document).addKeyListener(27, function(){
1331 if(active.length > 0){
1339 if(active && active.length > 0){
1340 var c = active.clone();
1350 if(active.length < 1){
1351 Roo.get(document).un("mouseup", onMouseDown);
1359 var last = active.last();
1360 lastShow = new Date();
1363 Roo.get(document).on("mouseup", onMouseDown);
1368 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1369 m.parentMenu.activeChild = m;
1370 }else if(last && last.isVisible()){
1371 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1376 function onBeforeHide(m){
1378 m.activeChild.hide();
1380 if(m.autoHideTimer){
1381 clearTimeout(m.autoHideTimer);
1382 delete m.autoHideTimer;
1387 function onBeforeShow(m){
1388 var pm = m.parentMenu;
1389 if(!pm && !m.allowOtherMenus){
1391 }else if(pm && pm.activeChild && active != m){
1392 pm.activeChild.hide();
1397 function onMouseDown(e){
1398 Roo.log("on MouseDown");
1399 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1407 function onBeforeCheck(mi, state){
1409 var g = groups[mi.group];
1410 for(var i = 0, l = g.length; i < l; i++){
1412 g[i].setChecked(false);
1421 * Hides all menus that are currently visible
1423 hideAll : function(){
1428 register : function(menu){
1432 menus[menu.id] = menu;
1433 menu.on("beforehide", onBeforeHide);
1434 menu.on("hide", onHide);
1435 menu.on("beforeshow", onBeforeShow);
1436 menu.on("show", onShow);
1438 if(g && menu.events["checkchange"]){
1442 groups[g].push(menu);
1443 menu.on("checkchange", onCheck);
1448 * Returns a {@link Roo.menu.Menu} object
1449 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1450 * be used to generate and return a new Menu instance.
1452 get : function(menu){
1453 if(typeof menu == "string"){ // menu id
1455 }else if(menu.events){ // menu instance
1458 /*else if(typeof menu.length == 'number'){ // array of menu items?
1459 return new Roo.bootstrap.Menu({items:menu});
1460 }else{ // otherwise, must be a config
1461 return new Roo.bootstrap.Menu(menu);
1468 unregister : function(menu){
1469 delete menus[menu.id];
1470 menu.un("beforehide", onBeforeHide);
1471 menu.un("hide", onHide);
1472 menu.un("beforeshow", onBeforeShow);
1473 menu.un("show", onShow);
1475 if(g && menu.events["checkchange"]){
1476 groups[g].remove(menu);
1477 menu.un("checkchange", onCheck);
1482 registerCheckable : function(menuItem){
1483 var g = menuItem.group;
1488 groups[g].push(menuItem);
1489 menuItem.on("beforecheckchange", onBeforeCheck);
1494 unregisterCheckable : function(menuItem){
1495 var g = menuItem.group;
1497 groups[g].remove(menuItem);
1498 menuItem.un("beforecheckchange", onBeforeCheck);
1510 * @class Roo.bootstrap.Menu
1511 * @extends Roo.bootstrap.Component
1512 * Bootstrap Menu class - container for MenuItems
1513 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1517 * @param {Object} config The config object
1521 Roo.bootstrap.Menu = function(config){
1522 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1523 if (this.registerMenu) {
1524 Roo.bootstrap.MenuMgr.register(this);
1529 * Fires before this menu is displayed
1530 * @param {Roo.menu.Menu} this
1535 * Fires before this menu is hidden
1536 * @param {Roo.menu.Menu} this
1541 * Fires after this menu is displayed
1542 * @param {Roo.menu.Menu} this
1547 * Fires after this menu is hidden
1548 * @param {Roo.menu.Menu} this
1553 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1554 * @param {Roo.menu.Menu} this
1555 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1556 * @param {Roo.EventObject} e
1561 * Fires when the mouse is hovering over this menu
1562 * @param {Roo.menu.Menu} this
1563 * @param {Roo.EventObject} e
1564 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1569 * Fires when the mouse exits this menu
1570 * @param {Roo.menu.Menu} this
1571 * @param {Roo.EventObject} e
1572 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1577 * Fires when a menu item contained in this menu is clicked
1578 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1579 * @param {Roo.EventObject} e
1583 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1586 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1590 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1593 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1595 registerMenu : true,
1597 menuItems :false, // stores the menu items..
1603 getChildContainer : function() {
1607 getAutoCreate : function(){
1609 //if (['right'].indexOf(this.align)!==-1) {
1610 // cfg.cn[1].cls += ' pull-right'
1616 cls : 'dropdown-menu' ,
1617 style : 'z-index:1000'
1621 if (this.type === 'submenu') {
1622 cfg.cls = 'submenu active';
1624 if (this.type === 'treeview') {
1625 cfg.cls = 'treeview-menu';
1630 initEvents : function() {
1632 // Roo.log("ADD event");
1633 // Roo.log(this.triggerEl.dom);
1634 this.triggerEl.on('click', this.onTriggerPress, this);
1635 this.triggerEl.addClass('dropdown-toggle');
1636 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1638 this.el.on("mouseover", this.onMouseOver, this);
1639 this.el.on("mouseout", this.onMouseOut, this);
1643 findTargetItem : function(e){
1644 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1648 //Roo.log(t); Roo.log(t.id);
1650 //Roo.log(this.menuitems);
1651 return this.menuitems.get(t.id);
1653 //return this.items.get(t.menuItemId);
1658 onClick : function(e){
1659 Roo.log("menu.onClick");
1660 var t = this.findTargetItem(e);
1666 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1667 if(t == this.activeItem && t.shouldDeactivate(e)){
1668 this.activeItem.deactivate();
1669 delete this.activeItem;
1673 this.setActiveItem(t, true);
1680 Roo.log('pass click event');
1684 this.fireEvent("click", this, t, e);
1688 onMouseOver : function(e){
1689 var t = this.findTargetItem(e);
1692 // if(t.canActivate && !t.disabled){
1693 // this.setActiveItem(t, true);
1697 this.fireEvent("mouseover", this, e, t);
1699 isVisible : function(){
1700 return !this.hidden;
1702 onMouseOut : function(e){
1703 var t = this.findTargetItem(e);
1706 // if(t == this.activeItem && t.shouldDeactivate(e)){
1707 // this.activeItem.deactivate();
1708 // delete this.activeItem;
1711 this.fireEvent("mouseout", this, e, t);
1716 * Displays this menu relative to another element
1717 * @param {String/HTMLElement/Roo.Element} element The element to align to
1718 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1719 * the element (defaults to this.defaultAlign)
1720 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1722 show : function(el, pos, parentMenu){
1723 this.parentMenu = parentMenu;
1727 this.fireEvent("beforeshow", this);
1728 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1731 * Displays this menu at a specific xy position
1732 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1733 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1735 showAt : function(xy, parentMenu, /* private: */_e){
1736 this.parentMenu = parentMenu;
1741 this.fireEvent("beforeshow", this);
1743 //xy = this.el.adjustForConstraints(xy);
1745 //this.el.setXY(xy);
1747 this.hideMenuItems();
1748 this.hidden = false;
1749 this.triggerEl.addClass('open');
1751 this.fireEvent("show", this);
1757 this.doFocus.defer(50, this);
1761 doFocus : function(){
1763 this.focusEl.focus();
1768 * Hides this menu and optionally all parent menus
1769 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1771 hide : function(deep){
1773 this.hideMenuItems();
1774 if(this.el && this.isVisible()){
1775 this.fireEvent("beforehide", this);
1776 if(this.activeItem){
1777 this.activeItem.deactivate();
1778 this.activeItem = null;
1780 this.triggerEl.removeClass('open');;
1782 this.fireEvent("hide", this);
1784 if(deep === true && this.parentMenu){
1785 this.parentMenu.hide(true);
1789 onTriggerPress : function(e)
1792 Roo.log('trigger press');
1793 //Roo.log(e.getTarget());
1794 // Roo.log(this.triggerEl.dom);
1795 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1798 if (this.isVisible()) {
1802 this.show(this.triggerEl, false, false);
1811 hideMenuItems : function()
1813 //$(backdrop).remove()
1814 Roo.select('.open',true).each(function(aa) {
1816 aa.removeClass('open');
1817 //var parent = getParent($(this))
1818 //var relatedTarget = { relatedTarget: this }
1820 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1821 //if (e.isDefaultPrevented()) return
1822 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1825 addxtypeChild : function (tree, cntr) {
1826 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1828 this.menuitems.add(comp);
1849 * @class Roo.bootstrap.MenuItem
1850 * @extends Roo.bootstrap.Component
1851 * Bootstrap MenuItem class
1852 * @cfg {String} html the menu label
1853 * @cfg {String} href the link
1854 * @cfg {Boolean} preventDefault (true | false) default true
1858 * Create a new MenuItem
1859 * @param {Object} config The config object
1863 Roo.bootstrap.MenuItem = function(config){
1864 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1869 * The raw click event for the entire grid.
1870 * @param {Roo.EventObject} e
1876 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1880 preventDefault: true,
1882 getAutoCreate : function(){
1885 cls: 'dropdown-menu-item',
1894 if (this.parent().type == 'treeview') {
1895 cfg.cls = 'treeview-menu';
1898 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1899 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1903 initEvents: function() {
1905 //this.el.select('a').on('click', this.onClick, this);
1908 onClick : function(e)
1910 Roo.log('item on click ');
1911 //if(this.preventDefault){
1912 // e.preventDefault();
1914 //this.parent().hideMenuItems();
1916 this.fireEvent('click', this, e);
1935 * @class Roo.bootstrap.MenuSeparator
1936 * @extends Roo.bootstrap.Component
1937 * Bootstrap MenuSeparator class
1940 * Create a new MenuItem
1941 * @param {Object} config The config object
1945 Roo.bootstrap.MenuSeparator = function(config){
1946 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1949 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1951 getAutoCreate : function(){
1966 <div class="modal fade">
1967 <div class="modal-dialog">
1968 <div class="modal-content">
1969 <div class="modal-header">
1970 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1971 <h4 class="modal-title">Modal title</h4>
1973 <div class="modal-body">
1974 <p>One fine body…</p>
1976 <div class="modal-footer">
1977 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1978 <button type="button" class="btn btn-primary">Save changes</button>
1980 </div><!-- /.modal-content -->
1981 </div><!-- /.modal-dialog -->
1982 </div><!-- /.modal -->
1992 * @class Roo.bootstrap.Modal
1993 * @extends Roo.bootstrap.Component
1994 * Bootstrap Modal class
1995 * @cfg {String} title Title of dialog
1996 * @cfg {Boolean} specificTitle (true|false) default false
1997 * @cfg {Array} buttons Array of buttons or standard button set..
1998 * @cfg {String} buttonPosition (left|right|center) default right
2001 * Create a new Modal Dialog
2002 * @param {Object} config The config object
2005 Roo.bootstrap.Modal = function(config){
2006 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2011 * The raw btnclick event for the button
2012 * @param {Roo.EventObject} e
2016 this.buttons = this.buttons || [];
2019 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2021 title : 'test dialog',
2028 specificTitle: false,
2030 buttonPosition: 'right',
2032 onRender : function(ct, position)
2034 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2037 var cfg = Roo.apply({}, this.getAutoCreate());
2040 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2042 //if (!cfg.name.length) {
2046 cfg.cls += ' ' + this.cls;
2049 cfg.style = this.style;
2051 this.el = Roo.get(document.body).createChild(cfg, position);
2053 //var type = this.el.dom.type;
2055 if(this.tabIndex !== undefined){
2056 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2061 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2062 this.maskEl.enableDisplayMode("block");
2064 //this.el.addClass("x-dlg-modal");
2066 if (this.buttons.length) {
2067 Roo.each(this.buttons, function(bb) {
2068 b = Roo.apply({}, bb);
2069 b.xns = b.xns || Roo.bootstrap;
2070 b.xtype = b.xtype || 'Button';
2071 if (typeof(b.listeners) == 'undefined') {
2072 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2075 var btn = Roo.factory(b);
2077 btn.onRender(this.el.select('.modal-footer div').first());
2081 // render the children.
2084 if(typeof(this.items) != 'undefined'){
2085 var items = this.items;
2088 for(var i =0;i < items.length;i++) {
2089 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2093 this.items = nitems;
2095 this.body = this.el.select('.modal-body',true).first();
2096 this.close = this.el.select('.modal-header .close', true).first();
2097 this.footer = this.el.select('.modal-footer',true).first();
2099 //this.el.addClass([this.fieldClass, this.cls]);
2102 getAutoCreate : function(){
2107 html : this.html || ''
2112 cls : 'modal-title',
2116 if(this.specificTitle){
2122 style : 'display: none',
2125 cls: "modal-dialog",
2128 cls : "modal-content",
2131 cls : 'modal-header',
2143 cls : 'modal-footer',
2147 cls: 'btn-' + this.buttonPosition
2166 getChildContainer : function() {
2168 return this.el.select('.modal-body',true).first();
2171 getButtonContainer : function() {
2172 return this.el.select('.modal-footer div',true).first();
2175 initEvents : function()
2177 this.el.select('.modal-header .close').on('click', this.hide, this);
2179 // this.addxtype(this);
2183 if (!this.rendered) {
2187 this.el.addClass('on');
2188 this.el.removeClass('fade');
2189 this.el.setStyle('display', 'block');
2190 Roo.get(document.body).addClass("x-body-masked");
2191 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2193 this.el.setStyle('zIndex', '10001');
2194 this.fireEvent('show', this);
2200 Roo.log('Modal hide?!');
2202 Roo.get(document.body).removeClass("x-body-masked");
2203 this.el.removeClass('on');
2204 this.el.addClass('fade');
2205 this.el.setStyle('display', 'none');
2206 this.fireEvent('hide', this);
2209 addButton : function(str, cb)
2213 var b = Roo.apply({}, { html : str } );
2214 b.xns = b.xns || Roo.bootstrap;
2215 b.xtype = b.xtype || 'Button';
2216 if (typeof(b.listeners) == 'undefined') {
2217 b.listeners = { click : cb.createDelegate(this) };
2220 var btn = Roo.factory(b);
2222 btn.onRender(this.el.select('.modal-footer div').first());
2228 setDefaultButton : function(btn)
2230 //this.el.select('.modal-footer').()
2232 resizeTo: function(w,h)
2236 setContentSize : function(w, h)
2240 onButtonClick: function(btn,e)
2243 this.fireEvent('btnclick', btn.name, e);
2245 setTitle: function(str) {
2246 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2252 Roo.apply(Roo.bootstrap.Modal, {
2254 * Button config that displays a single OK button
2263 * Button config that displays Yes and No buttons
2279 * Button config that displays OK and Cancel buttons
2294 * Button config that displays Yes, No and Cancel buttons
2316 * messagebox - can be used as a replace
2320 * @class Roo.MessageBox
2321 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2325 Roo.Msg.alert('Status', 'Changes saved successfully.');
2327 // Prompt for user data:
2328 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2330 // process text value...
2334 // Show a dialog using config options:
2336 title:'Save Changes?',
2337 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2338 buttons: Roo.Msg.YESNOCANCEL,
2345 Roo.bootstrap.MessageBox = function(){
2346 var dlg, opt, mask, waitTimer;
2347 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2348 var buttons, activeTextEl, bwidth;
2352 var handleButton = function(button){
2354 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2358 var handleHide = function(){
2360 dlg.el.removeClass(opt.cls);
2363 // Roo.TaskMgr.stop(waitTimer);
2364 // waitTimer = null;
2369 var updateButtons = function(b){
2372 buttons["ok"].hide();
2373 buttons["cancel"].hide();
2374 buttons["yes"].hide();
2375 buttons["no"].hide();
2376 //dlg.footer.dom.style.display = 'none';
2379 dlg.footer.dom.style.display = '';
2380 for(var k in buttons){
2381 if(typeof buttons[k] != "function"){
2384 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2385 width += buttons[k].el.getWidth()+15;
2395 var handleEsc = function(d, k, e){
2396 if(opt && opt.closable !== false){
2406 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2407 * @return {Roo.BasicDialog} The BasicDialog element
2409 getDialog : function(){
2411 dlg = new Roo.bootstrap.Modal( {
2414 //constraintoviewport:false,
2416 //collapsible : false,
2421 //buttonAlign:"center",
2422 closeClick : function(){
2423 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2426 handleButton("cancel");
2431 dlg.on("hide", handleHide);
2433 //dlg.addKeyListener(27, handleEsc);
2435 this.buttons = buttons;
2436 var bt = this.buttonText;
2437 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2438 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2439 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2440 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2442 bodyEl = dlg.body.createChild({
2444 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2445 '<textarea class="roo-mb-textarea"></textarea>' +
2446 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2448 msgEl = bodyEl.dom.firstChild;
2449 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2450 textboxEl.enableDisplayMode();
2451 textboxEl.addKeyListener([10,13], function(){
2452 if(dlg.isVisible() && opt && opt.buttons){
2455 }else if(opt.buttons.yes){
2456 handleButton("yes");
2460 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2461 textareaEl.enableDisplayMode();
2462 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2463 progressEl.enableDisplayMode();
2464 var pf = progressEl.dom.firstChild;
2466 pp = Roo.get(pf.firstChild);
2467 pp.setHeight(pf.offsetHeight);
2475 * Updates the message box body text
2476 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2477 * the XHTML-compliant non-breaking space character '&#160;')
2478 * @return {Roo.MessageBox} This message box
2480 updateText : function(text){
2481 if(!dlg.isVisible() && !opt.width){
2482 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2484 msgEl.innerHTML = text || ' ';
2486 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2487 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2489 Math.min(opt.width || cw , this.maxWidth),
2490 Math.max(opt.minWidth || this.minWidth, bwidth)
2493 activeTextEl.setWidth(w);
2495 if(dlg.isVisible()){
2496 dlg.fixedcenter = false;
2498 // to big, make it scroll. = But as usual stupid IE does not support
2501 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2502 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2503 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2505 bodyEl.dom.style.height = '';
2506 bodyEl.dom.style.overflowY = '';
2509 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2511 bodyEl.dom.style.overflowX = '';
2514 dlg.setContentSize(w, bodyEl.getHeight());
2515 if(dlg.isVisible()){
2516 dlg.fixedcenter = true;
2522 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2523 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2524 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2525 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2526 * @return {Roo.MessageBox} This message box
2528 updateProgress : function(value, text){
2530 this.updateText(text);
2532 if (pp) { // weird bug on my firefox - for some reason this is not defined
2533 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2539 * Returns true if the message box is currently displayed
2540 * @return {Boolean} True if the message box is visible, else false
2542 isVisible : function(){
2543 return dlg && dlg.isVisible();
2547 * Hides the message box if it is displayed
2550 if(this.isVisible()){
2556 * Displays a new message box, or reinitializes an existing message box, based on the config options
2557 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2558 * The following config object properties are supported:
2560 Property Type Description
2561 ---------- --------------- ------------------------------------------------------------------------------------
2562 animEl String/Element An id or Element from which the message box should animate as it opens and
2563 closes (defaults to undefined)
2564 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2565 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2566 closable Boolean False to hide the top-right close button (defaults to true). Note that
2567 progress and wait dialogs will ignore this property and always hide the
2568 close button as they can only be closed programmatically.
2569 cls String A custom CSS class to apply to the message box element
2570 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2571 displayed (defaults to 75)
2572 fn Function A callback function to execute after closing the dialog. The arguments to the
2573 function will be btn (the name of the button that was clicked, if applicable,
2574 e.g. "ok"), and text (the value of the active text field, if applicable).
2575 Progress and wait dialogs will ignore this option since they do not respond to
2576 user actions and can only be closed programmatically, so any required function
2577 should be called by the same code after it closes the dialog.
2578 icon String A CSS class that provides a background image to be used as an icon for
2579 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2580 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2581 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2582 modal Boolean False to allow user interaction with the page while the message box is
2583 displayed (defaults to true)
2584 msg String A string that will replace the existing message box body text (defaults
2585 to the XHTML-compliant non-breaking space character ' ')
2586 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2587 progress Boolean True to display a progress bar (defaults to false)
2588 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2589 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2590 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2591 title String The title text
2592 value String The string value to set into the active textbox element if displayed
2593 wait Boolean True to display a progress bar (defaults to false)
2594 width Number The width of the dialog in pixels
2601 msg: 'Please enter your address:',
2603 buttons: Roo.MessageBox.OKCANCEL,
2606 animEl: 'addAddressBtn'
2609 * @param {Object} config Configuration options
2610 * @return {Roo.MessageBox} This message box
2612 show : function(options)
2615 // this causes nightmares if you show one dialog after another
2616 // especially on callbacks..
2618 if(this.isVisible()){
2621 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2622 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2623 Roo.log("New Dialog Message:" + options.msg )
2624 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2625 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2628 var d = this.getDialog();
2630 d.setTitle(opt.title || " ");
2631 d.close.setDisplayed(opt.closable !== false);
2632 activeTextEl = textboxEl;
2633 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2638 textareaEl.setHeight(typeof opt.multiline == "number" ?
2639 opt.multiline : this.defaultTextHeight);
2640 activeTextEl = textareaEl;
2649 progressEl.setDisplayed(opt.progress === true);
2650 this.updateProgress(0);
2651 activeTextEl.dom.value = opt.value || "";
2653 dlg.setDefaultButton(activeTextEl);
2655 var bs = opt.buttons;
2659 }else if(bs && bs.yes){
2660 db = buttons["yes"];
2662 dlg.setDefaultButton(db);
2664 bwidth = updateButtons(opt.buttons);
2665 this.updateText(opt.msg);
2667 d.el.addClass(opt.cls);
2669 d.proxyDrag = opt.proxyDrag === true;
2670 d.modal = opt.modal !== false;
2671 d.mask = opt.modal !== false ? mask : false;
2673 // force it to the end of the z-index stack so it gets a cursor in FF
2674 document.body.appendChild(dlg.el.dom);
2675 d.animateTarget = null;
2676 d.show(options.animEl);
2682 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2683 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2684 * and closing the message box when the process is complete.
2685 * @param {String} title The title bar text
2686 * @param {String} msg The message box body text
2687 * @return {Roo.MessageBox} This message box
2689 progress : function(title, msg){
2696 minWidth: this.minProgressWidth,
2703 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2704 * If a callback function is passed it will be called after the user clicks the button, and the
2705 * id of the button that was clicked will be passed as the only parameter to the callback
2706 * (could also be the top-right close button).
2707 * @param {String} title The title bar text
2708 * @param {String} msg The message box body text
2709 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2710 * @param {Object} scope (optional) The scope of the callback function
2711 * @return {Roo.MessageBox} This message box
2713 alert : function(title, msg, fn, scope){
2726 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2727 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2728 * You are responsible for closing the message box when the process is complete.
2729 * @param {String} msg The message box body text
2730 * @param {String} title (optional) The title bar text
2731 * @return {Roo.MessageBox} This message box
2733 wait : function(msg, title){
2744 waitTimer = Roo.TaskMgr.start({
2746 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2754 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2755 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2756 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2757 * @param {String} title The title bar text
2758 * @param {String} msg The message box body text
2759 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2760 * @param {Object} scope (optional) The scope of the callback function
2761 * @return {Roo.MessageBox} This message box
2763 confirm : function(title, msg, fn, scope){
2767 buttons: this.YESNO,
2776 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2777 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2778 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2779 * (could also be the top-right close button) and the text that was entered will be passed as the two
2780 * parameters to the callback.
2781 * @param {String} title The title bar text
2782 * @param {String} msg The message box body text
2783 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2784 * @param {Object} scope (optional) The scope of the callback function
2785 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2786 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2787 * @return {Roo.MessageBox} This message box
2789 prompt : function(title, msg, fn, scope, multiline){
2793 buttons: this.OKCANCEL,
2798 multiline: multiline,
2805 * Button config that displays a single OK button
2810 * Button config that displays Yes and No buttons
2813 YESNO : {yes:true, no:true},
2815 * Button config that displays OK and Cancel buttons
2818 OKCANCEL : {ok:true, cancel:true},
2820 * Button config that displays Yes, No and Cancel buttons
2823 YESNOCANCEL : {yes:true, no:true, cancel:true},
2826 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2829 defaultTextHeight : 75,
2831 * The maximum width in pixels of the message box (defaults to 600)
2836 * The minimum width in pixels of the message box (defaults to 100)
2841 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2842 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2845 minProgressWidth : 250,
2847 * An object containing the default button text strings that can be overriden for localized language support.
2848 * Supported properties are: ok, cancel, yes and no.
2849 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2862 * Shorthand for {@link Roo.MessageBox}
2864 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2865 Roo.Msg = Roo.Msg || Roo.MessageBox;
2874 * @class Roo.bootstrap.Navbar
2875 * @extends Roo.bootstrap.Component
2876 * Bootstrap Navbar class
2879 * Create a new Navbar
2880 * @param {Object} config The config object
2884 Roo.bootstrap.Navbar = function(config){
2885 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2889 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2898 getAutoCreate : function(){
2901 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2905 initEvents :function ()
2907 //Roo.log(this.el.select('.navbar-toggle',true));
2908 this.el.select('.navbar-toggle',true).on('click', function() {
2909 // Roo.log('click');
2910 this.el.select('.navbar-collapse',true).toggleClass('in');
2918 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2920 var size = this.el.getSize();
2921 this.maskEl.setSize(size.width, size.height);
2922 this.maskEl.enableDisplayMode("block");
2931 getChildContainer : function()
2933 if (this.el.select('.collapse').getCount()) {
2934 return this.el.select('.collapse',true).first();
2967 * @class Roo.bootstrap.NavSimplebar
2968 * @extends Roo.bootstrap.Navbar
2969 * Bootstrap Sidebar class
2971 * @cfg {Boolean} inverse is inverted color
2973 * @cfg {String} type (nav | pills | tabs)
2974 * @cfg {Boolean} arrangement stacked | justified
2975 * @cfg {String} align (left | right) alignment
2977 * @cfg {Boolean} main (true|false) main nav bar? default false
2978 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2980 * @cfg {String} tag (header|footer|nav|div) default is nav
2986 * Create a new Sidebar
2987 * @param {Object} config The config object
2991 Roo.bootstrap.NavSimplebar = function(config){
2992 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2995 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3011 getAutoCreate : function(){
3015 tag : this.tag || 'div',
3028 this.type = this.type || 'nav';
3029 if (['tabs','pills'].indexOf(this.type)!==-1) {
3030 cfg.cn[0].cls += ' nav-' + this.type
3034 if (this.type!=='nav') {
3035 Roo.log('nav type must be nav/tabs/pills')
3037 cfg.cn[0].cls += ' navbar-nav'
3043 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3044 cfg.cn[0].cls += ' nav-' + this.arrangement;
3048 if (this.align === 'right') {
3049 cfg.cn[0].cls += ' navbar-right';
3053 cfg.cls += ' navbar-inverse';
3080 * @class Roo.bootstrap.NavHeaderbar
3081 * @extends Roo.bootstrap.NavSimplebar
3082 * Bootstrap Sidebar class
3084 * @cfg {String} brand what is brand
3085 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3086 * @cfg {String} brand_href href of the brand
3087 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3088 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3091 * Create a new Sidebar
3092 * @param {Object} config The config object
3096 Roo.bootstrap.NavHeaderbar = function(config){
3097 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3100 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3108 getAutoCreate : function(){
3111 tag: this.nav || 'nav',
3120 cls: 'navbar-header',
3125 cls: 'navbar-toggle',
3126 'data-toggle': 'collapse',
3131 html: 'Toggle navigation'
3153 cls: 'collapse navbar-collapse',
3157 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3159 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3160 cfg.cls += ' navbar-' + this.position;
3162 // tag can override this..
3164 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3167 if (this.brand !== '') {
3170 href: this.brand_href ? this.brand_href : '#',
3171 cls: 'navbar-brand',
3179 cfg.cls += ' main-nav';
3187 initEvents : function()
3189 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3191 if (this.autohide) {
3196 Roo.get(document).on('scroll',function(e) {
3197 var ns = Roo.get(document).getScroll().top;
3198 var os = prevScroll;
3202 ft.removeClass('slideDown');
3203 ft.addClass('slideUp');
3206 ft.removeClass('slideUp');
3207 ft.addClass('slideDown');
3231 * @class Roo.bootstrap.NavSidebar
3232 * @extends Roo.bootstrap.Navbar
3233 * Bootstrap Sidebar class
3236 * Create a new Sidebar
3237 * @param {Object} config The config object
3241 Roo.bootstrap.NavSidebar = function(config){
3242 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3245 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3247 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3249 getAutoCreate : function(){
3254 cls: 'sidebar sidebar-nav'
3276 * @class Roo.bootstrap.NavGroup
3277 * @extends Roo.bootstrap.Component
3278 * Bootstrap NavGroup class
3279 * @cfg {String} align left | right
3280 * @cfg {Boolean} inverse false | true
3281 * @cfg {String} type (nav|pills|tab) default nav
3282 * @cfg {String} navId - reference Id for navbar.
3286 * Create a new nav group
3287 * @param {Object} config The config object
3290 Roo.bootstrap.NavGroup = function(config){
3291 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3294 Roo.bootstrap.NavGroup.register(this);
3298 * Fires when the active item changes
3299 * @param {Roo.bootstrap.NavGroup} this
3300 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3301 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3308 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3319 getAutoCreate : function()
3321 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3328 if (['tabs','pills'].indexOf(this.type)!==-1) {
3329 cfg.cls += ' nav-' + this.type
3331 if (this.type!=='nav') {
3332 Roo.log('nav type must be nav/tabs/pills')
3334 cfg.cls += ' navbar-nav'
3337 if (this.parent().sidebar) {
3340 cls: 'dashboard-menu sidebar-menu'
3346 if (this.form === true) {
3352 if (this.align === 'right') {
3353 cfg.cls += ' navbar-right';
3355 cfg.cls += ' navbar-left';
3359 if (this.align === 'right') {
3360 cfg.cls += ' navbar-right';
3364 cfg.cls += ' navbar-inverse';
3372 * sets the active Navigation item
3373 * @param {Roo.bootstrap.NavItem} the new current navitem
3375 setActiveItem : function(item)
3378 Roo.each(this.navItems, function(v){
3383 v.setActive(false, true);
3390 item.setActive(true, true);
3391 this.fireEvent('changed', this, item, prev);
3396 * gets the active Navigation item
3397 * @return {Roo.bootstrap.NavItem} the current navitem
3399 getActive : function()
3403 Roo.each(this.navItems, function(v){
3414 indexOfNav : function()
3418 Roo.each(this.navItems, function(v,i){
3429 * adds a Navigation item
3430 * @param {Roo.bootstrap.NavItem} the navitem to add
3432 addItem : function(cfg)
3434 var cn = new Roo.bootstrap.NavItem(cfg);
3436 cn.parentId = this.id;
3437 cn.onRender(this.el, null);
3441 * register a Navigation item
3442 * @param {Roo.bootstrap.NavItem} the navitem to add
3444 register : function(item)
3446 this.navItems.push( item);
3447 item.navId = this.navId;
3452 getNavItem: function(tabId)
3455 Roo.each(this.navItems, function(e) {
3456 if (e.tabId == tabId) {
3466 setActiveNext : function()
3468 var i = this.indexOfNav(this.getActive());
3469 if (i > this.navItems.length) {
3472 this.setActiveItem(this.navItems[i+1]);
3474 setActivePrev : function()
3476 var i = this.indexOfNav(this.getActive());
3480 this.setActiveItem(this.navItems[i-1]);
3482 clearWasActive : function(except) {
3483 Roo.each(this.navItems, function(e) {
3484 if (e.tabId != except.tabId && e.was_active) {
3485 e.was_active = false;
3492 getWasActive : function ()
3495 Roo.each(this.navItems, function(e) {
3510 Roo.apply(Roo.bootstrap.NavGroup, {
3514 * register a Navigation Group
3515 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3517 register : function(navgrp)
3519 this.groups[navgrp.navId] = navgrp;
3523 * fetch a Navigation Group based on the navigation ID
3524 * @param {string} the navgroup to add
3525 * @returns {Roo.bootstrap.NavGroup} the navgroup
3527 get: function(navId) {
3528 if (typeof(this.groups[navId]) == 'undefined') {
3530 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3532 return this.groups[navId] ;
3547 * @class Roo.bootstrap.NavItem
3548 * @extends Roo.bootstrap.Component
3549 * Bootstrap Navbar.NavItem class
3550 * @cfg {String} href link to
3551 * @cfg {String} html content of button
3552 * @cfg {String} badge text inside badge
3553 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3554 * @cfg {String} glyphicon name of glyphicon
3555 * @cfg {String} icon name of font awesome icon
3556 * @cfg {Boolean} active Is item active
3557 * @cfg {Boolean} disabled Is item disabled
3559 * @cfg {Boolean} preventDefault (true | false) default false
3560 * @cfg {String} tabId the tab that this item activates.
3561 * @cfg {String} tagtype (a|span) render as a href or span?
3564 * Create a new Navbar Item
3565 * @param {Object} config The config object
3567 Roo.bootstrap.NavItem = function(config){
3568 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3573 * The raw click event for the entire grid.
3574 * @param {Roo.EventObject} e
3579 * Fires when the active item active state changes
3580 * @param {Roo.bootstrap.NavItem} this
3581 * @param {boolean} state the new state
3589 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3597 preventDefault : false,
3604 getAutoCreate : function(){
3612 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3614 if (this.disabled) {
3615 cfg.cls += ' disabled';
3618 if (this.href || this.html || this.glyphicon || this.icon) {
3622 href : this.href || "#",
3623 html: this.html || ''
3628 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3631 if(this.glyphicon) {
3632 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3637 cfg.cn[0].html += " <span class='caret'></span>";
3641 if (this.badge !== '') {
3643 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3651 initEvents: function() {
3652 // Roo.log('init events?');
3653 // Roo.log(this.el.dom);
3654 if (typeof (this.menu) != 'undefined') {
3655 this.menu.parentType = this.xtype;
3656 this.menu.triggerEl = this.el;
3657 this.addxtype(Roo.apply({}, this.menu));
3661 this.el.select('a',true).on('click', this.onClick, this);
3662 // at this point parent should be available..
3663 this.parent().register(this);
3666 onClick : function(e)
3669 if(this.preventDefault){
3672 if (this.disabled) {
3676 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3677 if (tg && tg.transition) {
3678 Roo.log("waiting for the transitionend");
3682 Roo.log("fire event clicked");
3683 if(this.fireEvent('click', this, e) === false){
3687 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3688 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3689 this.parent().setActiveItem(this);
3694 isActive: function () {
3697 setActive : function(state, fire, is_was_active)
3699 if (this.active && !state & this.navId) {
3700 this.was_active = true;
3701 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3703 nv.clearWasActive(this);
3707 this.active = state;
3710 this.el.removeClass('active');
3711 } else if (!this.el.hasClass('active')) {
3712 this.el.addClass('active');
3715 this.fireEvent('changed', this, state);
3718 // show a panel if it's registered and related..
3720 if (!this.navId || !this.tabId || !state || is_was_active) {
3724 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3728 var pan = tg.getPanelByName(this.tabId);
3732 // if we can not flip to new panel - go back to old nav highlight..
3733 if (false == tg.showPanel(pan)) {
3734 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3736 var onav = nv.getWasActive();
3738 onav.setActive(true, false, true);
3747 // this should not be here...
3748 setDisabled : function(state)
3750 this.disabled = state;
3752 this.el.removeClass('disabled');
3753 } else if (!this.el.hasClass('disabled')) {
3754 this.el.addClass('disabled');
3767 * <span> icon </span>
3768 * <span> text </span>
3769 * <span>badge </span>
3773 * @class Roo.bootstrap.NavSidebarItem
3774 * @extends Roo.bootstrap.NavItem
3775 * Bootstrap Navbar.NavSidebarItem class
3777 * Create a new Navbar Button
3778 * @param {Object} config The config object
3780 Roo.bootstrap.NavSidebarItem = function(config){
3781 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3786 * The raw click event for the entire grid.
3787 * @param {Roo.EventObject} e
3792 * Fires when the active item active state changes
3793 * @param {Roo.bootstrap.NavSidebarItem} this
3794 * @param {boolean} state the new state
3802 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3805 getAutoCreate : function(){
3810 href : this.href || '#',
3822 html : this.html || ''
3827 cfg.cls += ' active';
3831 if (this.glyphicon || this.icon) {
3832 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3833 a.cn.push({ tag : 'i', cls : c }) ;
3838 if (this.badge !== '') {
3839 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3843 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3844 a.cls += 'dropdown-toggle treeview' ;
3868 * @class Roo.bootstrap.Row
3869 * @extends Roo.bootstrap.Component
3870 * Bootstrap Row class (contains columns...)
3874 * @param {Object} config The config object
3877 Roo.bootstrap.Row = function(config){
3878 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3881 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3883 getAutoCreate : function(){
3902 * @class Roo.bootstrap.Element
3903 * @extends Roo.bootstrap.Component
3904 * Bootstrap Element class
3905 * @cfg {String} html contents of the element
3906 * @cfg {String} tag tag of the element
3907 * @cfg {String} cls class of the element
3910 * Create a new Element
3911 * @param {Object} config The config object
3914 Roo.bootstrap.Element = function(config){
3915 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3918 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3925 getAutoCreate : function(){
3950 * @class Roo.bootstrap.Pagination
3951 * @extends Roo.bootstrap.Component
3952 * Bootstrap Pagination class
3953 * @cfg {String} size xs | sm | md | lg
3954 * @cfg {Boolean} inverse false | true
3957 * Create a new Pagination
3958 * @param {Object} config The config object
3961 Roo.bootstrap.Pagination = function(config){
3962 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3965 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3971 getAutoCreate : function(){
3977 cfg.cls += ' inverse';
3983 cfg.cls += " " + this.cls;
4001 * @class Roo.bootstrap.PaginationItem
4002 * @extends Roo.bootstrap.Component
4003 * Bootstrap PaginationItem class
4004 * @cfg {String} html text
4005 * @cfg {String} href the link
4006 * @cfg {Boolean} preventDefault (true | false) default true
4007 * @cfg {Boolean} active (true | false) default false
4011 * Create a new PaginationItem
4012 * @param {Object} config The config object
4016 Roo.bootstrap.PaginationItem = function(config){
4017 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4022 * The raw click event for the entire grid.
4023 * @param {Roo.EventObject} e
4029 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4033 preventDefault: true,
4037 getAutoCreate : function(){
4043 href : this.href ? this.href : '#',
4044 html : this.html ? this.html : ''
4054 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4060 initEvents: function() {
4062 this.el.on('click', this.onClick, this);
4065 onClick : function(e)
4067 Roo.log('PaginationItem on click ');
4068 if(this.preventDefault){
4072 this.fireEvent('click', this, e);
4088 * @class Roo.bootstrap.Slider
4089 * @extends Roo.bootstrap.Component
4090 * Bootstrap Slider class
4093 * Create a new Slider
4094 * @param {Object} config The config object
4097 Roo.bootstrap.Slider = function(config){
4098 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4101 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4103 getAutoCreate : function(){
4107 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4111 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4123 * Ext JS Library 1.1.1
4124 * Copyright(c) 2006-2007, Ext JS, LLC.
4126 * Originally Released Under LGPL - original licence link has changed is not relivant.
4129 * <script type="text/javascript">
4134 * @class Roo.grid.ColumnModel
4135 * @extends Roo.util.Observable
4136 * This is the default implementation of a ColumnModel used by the Grid. It defines
4137 * the columns in the grid.
4140 var colModel = new Roo.grid.ColumnModel([
4141 {header: "Ticker", width: 60, sortable: true, locked: true},
4142 {header: "Company Name", width: 150, sortable: true},
4143 {header: "Market Cap.", width: 100, sortable: true},
4144 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4145 {header: "Employees", width: 100, sortable: true, resizable: false}
4150 * The config options listed for this class are options which may appear in each
4151 * individual column definition.
4152 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4154 * @param {Object} config An Array of column config objects. See this class's
4155 * config objects for details.
4157 Roo.grid.ColumnModel = function(config){
4159 * The config passed into the constructor
4161 this.config = config;
4164 // if no id, create one
4165 // if the column does not have a dataIndex mapping,
4166 // map it to the order it is in the config
4167 for(var i = 0, len = config.length; i < len; i++){
4169 if(typeof c.dataIndex == "undefined"){
4172 if(typeof c.renderer == "string"){
4173 c.renderer = Roo.util.Format[c.renderer];
4175 if(typeof c.id == "undefined"){
4178 if(c.editor && c.editor.xtype){
4179 c.editor = Roo.factory(c.editor, Roo.grid);
4181 if(c.editor && c.editor.isFormField){
4182 c.editor = new Roo.grid.GridEditor(c.editor);
4184 this.lookup[c.id] = c;
4188 * The width of columns which have no width specified (defaults to 100)
4191 this.defaultWidth = 100;
4194 * Default sortable of columns which have no sortable specified (defaults to false)
4197 this.defaultSortable = false;
4201 * @event widthchange
4202 * Fires when the width of a column changes.
4203 * @param {ColumnModel} this
4204 * @param {Number} columnIndex The column index
4205 * @param {Number} newWidth The new width
4207 "widthchange": true,
4209 * @event headerchange
4210 * Fires when the text of a header changes.
4211 * @param {ColumnModel} this
4212 * @param {Number} columnIndex The column index
4213 * @param {Number} newText The new header text
4215 "headerchange": true,
4217 * @event hiddenchange
4218 * Fires when a column is hidden or "unhidden".
4219 * @param {ColumnModel} this
4220 * @param {Number} columnIndex The column index
4221 * @param {Boolean} hidden true if hidden, false otherwise
4223 "hiddenchange": true,
4225 * @event columnmoved
4226 * Fires when a column is moved.
4227 * @param {ColumnModel} this
4228 * @param {Number} oldIndex
4229 * @param {Number} newIndex
4231 "columnmoved" : true,
4233 * @event columlockchange
4234 * Fires when a column's locked state is changed
4235 * @param {ColumnModel} this
4236 * @param {Number} colIndex
4237 * @param {Boolean} locked true if locked
4239 "columnlockchange" : true
4241 Roo.grid.ColumnModel.superclass.constructor.call(this);
4243 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4245 * @cfg {String} header The header text to display in the Grid view.
4248 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4249 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4250 * specified, the column's index is used as an index into the Record's data Array.
4253 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4254 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4257 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4258 * Defaults to the value of the {@link #defaultSortable} property.
4259 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4262 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4265 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4268 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4271 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4274 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4275 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4276 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4277 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4280 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4283 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4287 * Returns the id of the column at the specified index.
4288 * @param {Number} index The column index
4289 * @return {String} the id
4291 getColumnId : function(index){
4292 return this.config[index].id;
4296 * Returns the column for a specified id.
4297 * @param {String} id The column id
4298 * @return {Object} the column
4300 getColumnById : function(id){
4301 return this.lookup[id];
4306 * Returns the column for a specified dataIndex.
4307 * @param {String} dataIndex The column dataIndex
4308 * @return {Object|Boolean} the column or false if not found
4310 getColumnByDataIndex: function(dataIndex){
4311 var index = this.findColumnIndex(dataIndex);
4312 return index > -1 ? this.config[index] : false;
4316 * Returns the index for a specified column id.
4317 * @param {String} id The column id
4318 * @return {Number} the index, or -1 if not found
4320 getIndexById : function(id){
4321 for(var i = 0, len = this.config.length; i < len; i++){
4322 if(this.config[i].id == id){
4330 * Returns the index for a specified column dataIndex.
4331 * @param {String} dataIndex The column dataIndex
4332 * @return {Number} the index, or -1 if not found
4335 findColumnIndex : function(dataIndex){
4336 for(var i = 0, len = this.config.length; i < len; i++){
4337 if(this.config[i].dataIndex == dataIndex){
4345 moveColumn : function(oldIndex, newIndex){
4346 var c = this.config[oldIndex];
4347 this.config.splice(oldIndex, 1);
4348 this.config.splice(newIndex, 0, c);
4349 this.dataMap = null;
4350 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4353 isLocked : function(colIndex){
4354 return this.config[colIndex].locked === true;
4357 setLocked : function(colIndex, value, suppressEvent){
4358 if(this.isLocked(colIndex) == value){
4361 this.config[colIndex].locked = value;
4363 this.fireEvent("columnlockchange", this, colIndex, value);
4367 getTotalLockedWidth : function(){
4369 for(var i = 0; i < this.config.length; i++){
4370 if(this.isLocked(i) && !this.isHidden(i)){
4371 this.totalWidth += this.getColumnWidth(i);
4377 getLockedCount : function(){
4378 for(var i = 0, len = this.config.length; i < len; i++){
4379 if(!this.isLocked(i)){
4386 * Returns the number of columns.
4389 getColumnCount : function(visibleOnly){
4390 if(visibleOnly === true){
4392 for(var i = 0, len = this.config.length; i < len; i++){
4393 if(!this.isHidden(i)){
4399 return this.config.length;
4403 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4404 * @param {Function} fn
4405 * @param {Object} scope (optional)
4406 * @return {Array} result
4408 getColumnsBy : function(fn, scope){
4410 for(var i = 0, len = this.config.length; i < len; i++){
4411 var c = this.config[i];
4412 if(fn.call(scope||this, c, i) === true){
4420 * Returns true if the specified column is sortable.
4421 * @param {Number} col The column index
4424 isSortable : function(col){
4425 if(typeof this.config[col].sortable == "undefined"){
4426 return this.defaultSortable;
4428 return this.config[col].sortable;
4432 * Returns the rendering (formatting) function defined for the column.
4433 * @param {Number} col The column index.
4434 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4436 getRenderer : function(col){
4437 if(!this.config[col].renderer){
4438 return Roo.grid.ColumnModel.defaultRenderer;
4440 return this.config[col].renderer;
4444 * Sets the rendering (formatting) function for a column.
4445 * @param {Number} col The column index
4446 * @param {Function} fn The function to use to process the cell's raw data
4447 * to return HTML markup for the grid view. The render function is called with
4448 * the following parameters:<ul>
4449 * <li>Data value.</li>
4450 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4451 * <li>css A CSS style string to apply to the table cell.</li>
4452 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4453 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4454 * <li>Row index</li>
4455 * <li>Column index</li>
4456 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4458 setRenderer : function(col, fn){
4459 this.config[col].renderer = fn;
4463 * Returns the width for the specified column.
4464 * @param {Number} col The column index
4467 getColumnWidth : function(col){
4468 return this.config[col].width * 1 || this.defaultWidth;
4472 * Sets the width for a column.
4473 * @param {Number} col The column index
4474 * @param {Number} width The new width
4476 setColumnWidth : function(col, width, suppressEvent){
4477 this.config[col].width = width;
4478 this.totalWidth = null;
4480 this.fireEvent("widthchange", this, col, width);
4485 * Returns the total width of all columns.
4486 * @param {Boolean} includeHidden True to include hidden column widths
4489 getTotalWidth : function(includeHidden){
4490 if(!this.totalWidth){
4491 this.totalWidth = 0;
4492 for(var i = 0, len = this.config.length; i < len; i++){
4493 if(includeHidden || !this.isHidden(i)){
4494 this.totalWidth += this.getColumnWidth(i);
4498 return this.totalWidth;
4502 * Returns the header for the specified column.
4503 * @param {Number} col The column index
4506 getColumnHeader : function(col){
4507 return this.config[col].header;
4511 * Sets the header for a column.
4512 * @param {Number} col The column index
4513 * @param {String} header The new header
4515 setColumnHeader : function(col, header){
4516 this.config[col].header = header;
4517 this.fireEvent("headerchange", this, col, header);
4521 * Returns the tooltip for the specified column.
4522 * @param {Number} col The column index
4525 getColumnTooltip : function(col){
4526 return this.config[col].tooltip;
4529 * Sets the tooltip for a column.
4530 * @param {Number} col The column index
4531 * @param {String} tooltip The new tooltip
4533 setColumnTooltip : function(col, tooltip){
4534 this.config[col].tooltip = tooltip;
4538 * Returns the dataIndex for the specified column.
4539 * @param {Number} col The column index
4542 getDataIndex : function(col){
4543 return this.config[col].dataIndex;
4547 * Sets the dataIndex for a column.
4548 * @param {Number} col The column index
4549 * @param {Number} dataIndex The new dataIndex
4551 setDataIndex : function(col, dataIndex){
4552 this.config[col].dataIndex = dataIndex;
4558 * Returns true if the cell is editable.
4559 * @param {Number} colIndex The column index
4560 * @param {Number} rowIndex The row index
4563 isCellEditable : function(colIndex, rowIndex){
4564 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4568 * Returns the editor defined for the cell/column.
4569 * return false or null to disable editing.
4570 * @param {Number} colIndex The column index
4571 * @param {Number} rowIndex The row index
4574 getCellEditor : function(colIndex, rowIndex){
4575 return this.config[colIndex].editor;
4579 * Sets if a column is editable.
4580 * @param {Number} col The column index
4581 * @param {Boolean} editable True if the column is editable
4583 setEditable : function(col, editable){
4584 this.config[col].editable = editable;
4589 * Returns true if the column is hidden.
4590 * @param {Number} colIndex The column index
4593 isHidden : function(colIndex){
4594 return this.config[colIndex].hidden;
4599 * Returns true if the column width cannot be changed
4601 isFixed : function(colIndex){
4602 return this.config[colIndex].fixed;
4606 * Returns true if the column can be resized
4609 isResizable : function(colIndex){
4610 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4613 * Sets if a column is hidden.
4614 * @param {Number} colIndex The column index
4615 * @param {Boolean} hidden True if the column is hidden
4617 setHidden : function(colIndex, hidden){
4618 this.config[colIndex].hidden = hidden;
4619 this.totalWidth = null;
4620 this.fireEvent("hiddenchange", this, colIndex, hidden);
4624 * Sets the editor for a column.
4625 * @param {Number} col The column index
4626 * @param {Object} editor The editor object
4628 setEditor : function(col, editor){
4629 this.config[col].editor = editor;
4633 Roo.grid.ColumnModel.defaultRenderer = function(value){
4634 if(typeof value == "string" && value.length < 1){
4640 // Alias for backwards compatibility
4641 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4644 * Ext JS Library 1.1.1
4645 * Copyright(c) 2006-2007, Ext JS, LLC.
4647 * Originally Released Under LGPL - original licence link has changed is not relivant.
4650 * <script type="text/javascript">
4654 * @class Roo.LoadMask
4655 * A simple utility class for generically masking elements while loading data. If the element being masked has
4656 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4657 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4658 * element's UpdateManager load indicator and will be destroyed after the initial load.
4660 * Create a new LoadMask
4661 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4662 * @param {Object} config The config object
4664 Roo.LoadMask = function(el, config){
4665 this.el = Roo.get(el);
4666 Roo.apply(this, config);
4668 this.store.on('beforeload', this.onBeforeLoad, this);
4669 this.store.on('load', this.onLoad, this);
4670 this.store.on('loadexception', this.onLoadException, this);
4671 this.removeMask = false;
4673 var um = this.el.getUpdateManager();
4674 um.showLoadIndicator = false; // disable the default indicator
4675 um.on('beforeupdate', this.onBeforeLoad, this);
4676 um.on('update', this.onLoad, this);
4677 um.on('failure', this.onLoad, this);
4678 this.removeMask = true;
4682 Roo.LoadMask.prototype = {
4684 * @cfg {Boolean} removeMask
4685 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4686 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4690 * The text to display in a centered loading message box (defaults to 'Loading...')
4694 * @cfg {String} msgCls
4695 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4697 msgCls : 'x-mask-loading',
4700 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4706 * Disables the mask to prevent it from being displayed
4708 disable : function(){
4709 this.disabled = true;
4713 * Enables the mask so that it can be displayed
4715 enable : function(){
4716 this.disabled = false;
4719 onLoadException : function()
4723 if (typeof(arguments[3]) != 'undefined') {
4724 Roo.MessageBox.alert("Error loading",arguments[3]);
4728 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4729 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4738 this.el.unmask(this.removeMask);
4743 this.el.unmask(this.removeMask);
4747 onBeforeLoad : function(){
4749 this.el.mask(this.msg, this.msgCls);
4754 destroy : function(){
4756 this.store.un('beforeload', this.onBeforeLoad, this);
4757 this.store.un('load', this.onLoad, this);
4758 this.store.un('loadexception', this.onLoadException, this);
4760 var um = this.el.getUpdateManager();
4761 um.un('beforeupdate', this.onBeforeLoad, this);
4762 um.un('update', this.onLoad, this);
4763 um.un('failure', this.onLoad, this);
4774 * @class Roo.bootstrap.Table
4775 * @extends Roo.bootstrap.Component
4776 * Bootstrap Table class
4777 * @cfg {String} cls table class
4778 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4779 * @cfg {String} bgcolor Specifies the background color for a table
4780 * @cfg {Number} border Specifies whether the table cells should have borders or not
4781 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4782 * @cfg {Number} cellspacing Specifies the space between cells
4783 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4784 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4785 * @cfg {String} sortable Specifies that the table should be sortable
4786 * @cfg {String} summary Specifies a summary of the content of a table
4787 * @cfg {Number} width Specifies the width of a table
4788 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4790 * @cfg {boolean} striped Should the rows be alternative striped
4791 * @cfg {boolean} bordered Add borders to the table
4792 * @cfg {boolean} hover Add hover highlighting
4793 * @cfg {boolean} condensed Format condensed
4794 * @cfg {boolean} responsive Format condensed
4795 * @cfg {Boolean} loadMask (true|false) default false
4796 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4797 * @cfg {Boolean} thead (true|false) generate thead, default true
4798 * @cfg {Boolean} RowSelection (true|false) default false
4799 * @cfg {Boolean} CellSelection (true|false) default false
4801 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4805 * Create a new Table
4806 * @param {Object} config The config object
4809 Roo.bootstrap.Table = function(config){
4810 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4813 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4814 this.sm = this.selModel;
4815 this.sm.xmodule = this.xmodule || false;
4817 if (this.cm && typeof(this.cm.config) == 'undefined') {
4818 this.colModel = new Roo.grid.ColumnModel(this.cm);
4819 this.cm = this.colModel;
4820 this.cm.xmodule = this.xmodule || false;
4823 this.store= Roo.factory(this.store, Roo.data);
4824 this.ds = this.store;
4825 this.ds.xmodule = this.xmodule || false;
4828 if (this.footer && this.store) {
4829 this.footer.dataSource = this.ds;
4830 this.footer = Roo.factory(this.footer);
4837 * Fires when a cell is clicked
4838 * @param {Roo.bootstrap.Table} this
4839 * @param {Roo.Element} el
4840 * @param {Number} rowIndex
4841 * @param {Number} columnIndex
4842 * @param {Roo.EventObject} e
4846 * @event celldblclick
4847 * Fires when a cell is double clicked
4848 * @param {Roo.bootstrap.Table} this
4849 * @param {Roo.Element} el
4850 * @param {Number} rowIndex
4851 * @param {Number} columnIndex
4852 * @param {Roo.EventObject} e
4854 "celldblclick" : true,
4857 * Fires when a row is clicked
4858 * @param {Roo.bootstrap.Table} this
4859 * @param {Roo.Element} el
4860 * @param {Number} rowIndex
4861 * @param {Roo.EventObject} e
4865 * @event rowdblclick
4866 * Fires when a row is double clicked
4867 * @param {Roo.bootstrap.Table} this
4868 * @param {Roo.Element} el
4869 * @param {Number} rowIndex
4870 * @param {Roo.EventObject} e
4872 "rowdblclick" : true,
4875 * Fires when a mouseover occur
4876 * @param {Roo.bootstrap.Table} this
4877 * @param {Roo.Element} el
4878 * @param {Number} rowIndex
4879 * @param {Number} columnIndex
4880 * @param {Roo.EventObject} e
4885 * Fires when a mouseout occur
4886 * @param {Roo.bootstrap.Table} this
4887 * @param {Roo.Element} el
4888 * @param {Number} rowIndex
4889 * @param {Number} columnIndex
4890 * @param {Roo.EventObject} e
4895 * Fires when a row is rendered, so you can change add a style to it.
4896 * @param {Roo.bootstrap.Table} this
4897 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4904 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4928 RowSelection : false,
4929 CellSelection : false,
4932 // Roo.Element - the tbody
4935 getAutoCreate : function(){
4936 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4945 cfg.cls += ' table-striped';
4949 cfg.cls += ' table-hover';
4951 if (this.bordered) {
4952 cfg.cls += ' table-bordered';
4954 if (this.condensed) {
4955 cfg.cls += ' table-condensed';
4957 if (this.responsive) {
4958 cfg.cls += ' table-responsive';
4962 cfg.cls+= ' ' +this.cls;
4965 // this lot should be simplifed...
4968 cfg.align=this.align;
4971 cfg.bgcolor=this.bgcolor;
4974 cfg.border=this.border;
4976 if (this.cellpadding) {
4977 cfg.cellpadding=this.cellpadding;
4979 if (this.cellspacing) {
4980 cfg.cellspacing=this.cellspacing;
4983 cfg.frame=this.frame;
4986 cfg.rules=this.rules;
4988 if (this.sortable) {
4989 cfg.sortable=this.sortable;
4992 cfg.summary=this.summary;
4995 cfg.width=this.width;
4998 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5001 if(this.store || this.cm){
5003 cfg.cn.push(this.renderHeader());
5006 cfg.cn.push(this.renderBody());
5009 cfg.cn.push(this.renderFooter());
5012 cfg.cls+= ' TableGrid';
5015 return { cn : [ cfg ] };
5018 initEvents : function()
5020 if(!this.store || !this.cm){
5024 //Roo.log('initEvents with ds!!!!');
5026 this.mainBody = this.el.select('tbody', true).first();
5031 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5032 e.on('click', _this.sort, _this);
5035 this.el.on("click", this.onClick, this);
5036 this.el.on("dblclick", this.onDblClick, this);
5038 this.parent().el.setStyle('position', 'relative');
5040 this.footer.parentId = this.id;
5041 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5044 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5046 this.store.on('load', this.onLoad, this);
5047 this.store.on('beforeload', this.onBeforeLoad, this);
5048 this.store.on('update', this.onUpdate, this);
5052 onMouseover : function(e, el)
5054 var cell = Roo.get(el);
5060 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5061 cell = cell.findParent('td', false, true);
5064 var row = cell.findParent('tr', false, true);
5065 var cellIndex = cell.dom.cellIndex;
5066 var rowIndex = row.dom.rowIndex - 1; // start from 0
5068 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5072 onMouseout : function(e, el)
5074 var cell = Roo.get(el);
5080 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5081 cell = cell.findParent('td', false, true);
5084 var row = cell.findParent('tr', false, true);
5085 var cellIndex = cell.dom.cellIndex;
5086 var rowIndex = row.dom.rowIndex - 1; // start from 0
5088 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5092 onClick : function(e, el)
5094 var cell = Roo.get(el);
5096 if(!cell || (!this.CellSelection && !this.RowSelection)){
5101 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5102 cell = cell.findParent('td', false, true);
5105 var row = cell.findParent('tr', false, true);
5106 var cellIndex = cell.dom.cellIndex;
5107 var rowIndex = row.dom.rowIndex - 1;
5109 if(this.CellSelection){
5110 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5113 if(this.RowSelection){
5114 this.fireEvent('rowclick', this, row, rowIndex, e);
5120 onDblClick : function(e,el)
5122 var cell = Roo.get(el);
5124 if(!cell || (!this.CellSelection && !this.RowSelection)){
5128 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5129 cell = cell.findParent('td', false, true);
5132 var row = cell.findParent('tr', false, true);
5133 var cellIndex = cell.dom.cellIndex;
5134 var rowIndex = row.dom.rowIndex - 1;
5136 if(this.CellSelection){
5137 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5140 if(this.RowSelection){
5141 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5145 sort : function(e,el)
5147 var col = Roo.get(el)
5149 if(!col.hasClass('sortable')){
5153 var sort = col.attr('sort');
5156 if(col.hasClass('glyphicon-arrow-up')){
5160 this.store.sortInfo = {field : sort, direction : dir};
5163 Roo.log("calling footer first");
5164 this.footer.onClick('first');
5167 this.store.load({ params : { start : 0 } });
5171 renderHeader : function()
5180 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5182 var config = cm.config[i];
5187 html: cm.getColumnHeader(i)
5190 if(typeof(config.hidden) != 'undefined' && config.hidden){
5191 c.style += ' display:none;';
5194 if(typeof(config.dataIndex) != 'undefined'){
5195 c.sort = config.dataIndex;
5198 if(typeof(config.sortable) != 'undefined' && config.sortable){
5202 if(typeof(config.align) != 'undefined' && config.align.length){
5203 c.style += ' text-align:' + config.align + ';';
5206 if(typeof(config.width) != 'undefined'){
5207 c.style += ' width:' + config.width + 'px;';
5216 renderBody : function()
5226 colspan : this.cm.getColumnCount()
5236 renderFooter : function()
5246 colspan : this.cm.getColumnCount()
5260 Roo.log('ds onload');
5265 var ds = this.store;
5267 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5268 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5270 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5271 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5274 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5275 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5279 var tbody = this.mainBody;
5281 if(ds.getCount() > 0){
5282 ds.data.each(function(d,rowIndex){
5283 var row = this.renderRow(cm, ds, rowIndex);
5285 tbody.createChild(row);
5289 if(row.cellObjects.length){
5290 Roo.each(row.cellObjects, function(r){
5291 _this.renderCellObject(r);
5298 Roo.each(this.el.select('tbody td', true).elements, function(e){
5299 e.on('mouseover', _this.onMouseover, _this);
5302 Roo.each(this.el.select('tbody td', true).elements, function(e){
5303 e.on('mouseout', _this.onMouseout, _this);
5306 //if(this.loadMask){
5307 // this.maskEl.hide();
5312 onUpdate : function(ds,record)
5314 this.refreshRow(record);
5316 onRemove : function(ds, record, index, isUpdate){
5317 if(isUpdate !== true){
5318 this.fireEvent("beforerowremoved", this, index, record);
5320 var bt = this.mainBody.dom;
5322 bt.removeChild(bt.rows[index]);
5325 if(isUpdate !== true){
5326 //this.stripeRows(index);
5327 //this.syncRowHeights(index, index);
5329 this.fireEvent("rowremoved", this, index, record);
5334 refreshRow : function(record){
5335 var ds = this.store, index;
5336 if(typeof record == 'number'){
5338 record = ds.getAt(index);
5340 index = ds.indexOf(record);
5342 this.insertRow(ds, index, true);
5343 this.onRemove(ds, record, index+1, true);
5344 //this.syncRowHeights(index, index);
5346 this.fireEvent("rowupdated", this, index, record);
5349 insertRow : function(dm, rowIndex, isUpdate){
5352 this.fireEvent("beforerowsinserted", this, rowIndex);
5354 //var s = this.getScrollState();
5355 var row = this.renderRow(this.cm, this.store, rowIndex);
5356 // insert before rowIndex..
5357 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5361 if(row.cellObjects.length){
5362 Roo.each(row.cellObjects, function(r){
5363 _this.renderCellObject(r);
5368 this.fireEvent("rowsinserted", this, rowIndex);
5369 //this.syncRowHeights(firstRow, lastRow);
5370 //this.stripeRows(firstRow);
5377 getRowDom : function(rowIndex)
5379 // not sure if I need to check this.. but let's do it anyway..
5380 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5381 this.mainBody.dom.rows[rowIndex] : false
5383 // returns the object tree for a tr..
5386 renderRow : function(cm, ds, rowIndex) {
5388 var d = ds.getAt(rowIndex);
5395 var cellObjects = [];
5397 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5398 var config = cm.config[i];
5400 var renderer = cm.getRenderer(i);
5404 if(typeof(renderer) !== 'undefined'){
5405 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5407 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5408 // and are rendered into the cells after the row is rendered - using the id for the element.
5410 if(typeof(value) === 'object'){
5420 rowIndex : rowIndex,
5425 this.fireEvent('rowclass', this, rowcfg);
5429 cls : rowcfg.rowClass,
5431 html: (typeof(value) === 'object') ? '' : value
5438 if(typeof(config.hidden) != 'undefined' && config.hidden){
5439 td.style += ' display:none;';
5442 if(typeof(config.align) != 'undefined' && config.align.length){
5443 td.style += ' text-align:' + config.align + ';';
5446 if(typeof(config.width) != 'undefined'){
5447 td.style += ' width:' + config.width + 'px;';
5454 row.cellObjects = cellObjects;
5462 onBeforeLoad : function()
5464 //Roo.log('ds onBeforeLoad');
5468 //if(this.loadMask){
5469 // this.maskEl.show();
5475 this.el.select('tbody', true).first().dom.innerHTML = '';
5478 getSelectionModel : function(){
5480 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5482 return this.selModel;
5485 * Render the Roo.bootstrap object from renderder
5487 renderCellObject : function(r)
5491 var t = r.cfg.render(r.container);
5494 Roo.each(r.cfg.cn, function(c){
5496 container: t.getChildContainer(),
5499 _this.renderCellObject(child);
5516 * @class Roo.bootstrap.TableCell
5517 * @extends Roo.bootstrap.Component
5518 * Bootstrap TableCell class
5519 * @cfg {String} html cell contain text
5520 * @cfg {String} cls cell class
5521 * @cfg {String} tag cell tag (td|th) default td
5522 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5523 * @cfg {String} align Aligns the content in a cell
5524 * @cfg {String} axis Categorizes cells
5525 * @cfg {String} bgcolor Specifies the background color of a cell
5526 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5527 * @cfg {Number} colspan Specifies the number of columns a cell should span
5528 * @cfg {String} headers Specifies one or more header cells a cell is related to
5529 * @cfg {Number} height Sets the height of a cell
5530 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5531 * @cfg {Number} rowspan Sets the number of rows a cell should span
5532 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5533 * @cfg {String} valign Vertical aligns the content in a cell
5534 * @cfg {Number} width Specifies the width of a cell
5537 * Create a new TableCell
5538 * @param {Object} config The config object
5541 Roo.bootstrap.TableCell = function(config){
5542 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5545 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5565 getAutoCreate : function(){
5566 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5586 cfg.align=this.align
5592 cfg.bgcolor=this.bgcolor
5595 cfg.charoff=this.charoff
5598 cfg.colspan=this.colspan
5601 cfg.headers=this.headers
5604 cfg.height=this.height
5607 cfg.nowrap=this.nowrap
5610 cfg.rowspan=this.rowspan
5613 cfg.scope=this.scope
5616 cfg.valign=this.valign
5619 cfg.width=this.width
5638 * @class Roo.bootstrap.TableRow
5639 * @extends Roo.bootstrap.Component
5640 * Bootstrap TableRow class
5641 * @cfg {String} cls row class
5642 * @cfg {String} align Aligns the content in a table row
5643 * @cfg {String} bgcolor Specifies a background color for a table row
5644 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5645 * @cfg {String} valign Vertical aligns the content in a table row
5648 * Create a new TableRow
5649 * @param {Object} config The config object
5652 Roo.bootstrap.TableRow = function(config){
5653 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5656 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5664 getAutoCreate : function(){
5665 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5675 cfg.align = this.align;
5678 cfg.bgcolor = this.bgcolor;
5681 cfg.charoff = this.charoff;
5684 cfg.valign = this.valign;
5702 * @class Roo.bootstrap.TableBody
5703 * @extends Roo.bootstrap.Component
5704 * Bootstrap TableBody class
5705 * @cfg {String} cls element class
5706 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5707 * @cfg {String} align Aligns the content inside the element
5708 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5709 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5712 * Create a new TableBody
5713 * @param {Object} config The config object
5716 Roo.bootstrap.TableBody = function(config){
5717 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5720 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5728 getAutoCreate : function(){
5729 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5743 cfg.align = this.align;
5746 cfg.charoff = this.charoff;
5749 cfg.valign = this.valign;
5756 // initEvents : function()
5763 // this.store = Roo.factory(this.store, Roo.data);
5764 // this.store.on('load', this.onLoad, this);
5766 // this.store.load();
5770 // onLoad: function ()
5772 // this.fireEvent('load', this);
5782 * Ext JS Library 1.1.1
5783 * Copyright(c) 2006-2007, Ext JS, LLC.
5785 * Originally Released Under LGPL - original licence link has changed is not relivant.
5788 * <script type="text/javascript">
5791 // as we use this in bootstrap.
5792 Roo.namespace('Roo.form');
5794 * @class Roo.form.Action
5795 * Internal Class used to handle form actions
5797 * @param {Roo.form.BasicForm} el The form element or its id
5798 * @param {Object} config Configuration options
5803 // define the action interface
5804 Roo.form.Action = function(form, options){
5806 this.options = options || {};
5809 * Client Validation Failed
5812 Roo.form.Action.CLIENT_INVALID = 'client';
5814 * Server Validation Failed
5817 Roo.form.Action.SERVER_INVALID = 'server';
5819 * Connect to Server Failed
5822 Roo.form.Action.CONNECT_FAILURE = 'connect';
5824 * Reading Data from Server Failed
5827 Roo.form.Action.LOAD_FAILURE = 'load';
5829 Roo.form.Action.prototype = {
5831 failureType : undefined,
5832 response : undefined,
5836 run : function(options){
5841 success : function(response){
5846 handleResponse : function(response){
5850 // default connection failure
5851 failure : function(response){
5853 this.response = response;
5854 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5855 this.form.afterAction(this, false);
5858 processResponse : function(response){
5859 this.response = response;
5860 if(!response.responseText){
5863 this.result = this.handleResponse(response);
5867 // utility functions used internally
5868 getUrl : function(appendParams){
5869 var url = this.options.url || this.form.url || this.form.el.dom.action;
5871 var p = this.getParams();
5873 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5879 getMethod : function(){
5880 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5883 getParams : function(){
5884 var bp = this.form.baseParams;
5885 var p = this.options.params;
5887 if(typeof p == "object"){
5888 p = Roo.urlEncode(Roo.applyIf(p, bp));
5889 }else if(typeof p == 'string' && bp){
5890 p += '&' + Roo.urlEncode(bp);
5893 p = Roo.urlEncode(bp);
5898 createCallback : function(){
5900 success: this.success,
5901 failure: this.failure,
5903 timeout: (this.form.timeout*1000),
5904 upload: this.form.fileUpload ? this.success : undefined
5909 Roo.form.Action.Submit = function(form, options){
5910 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5913 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5916 haveProgress : false,
5917 uploadComplete : false,
5919 // uploadProgress indicator.
5920 uploadProgress : function()
5922 if (!this.form.progressUrl) {
5926 if (!this.haveProgress) {
5927 Roo.MessageBox.progress("Uploading", "Uploading");
5929 if (this.uploadComplete) {
5930 Roo.MessageBox.hide();
5934 this.haveProgress = true;
5936 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5938 var c = new Roo.data.Connection();
5940 url : this.form.progressUrl,
5945 success : function(req){
5946 //console.log(data);
5950 rdata = Roo.decode(req.responseText)
5952 Roo.log("Invalid data from server..");
5956 if (!rdata || !rdata.success) {
5958 Roo.MessageBox.alert(Roo.encode(rdata));
5961 var data = rdata.data;
5963 if (this.uploadComplete) {
5964 Roo.MessageBox.hide();
5969 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5970 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5973 this.uploadProgress.defer(2000,this);
5976 failure: function(data) {
5977 Roo.log('progress url failed ');
5988 // run get Values on the form, so it syncs any secondary forms.
5989 this.form.getValues();
5991 var o = this.options;
5992 var method = this.getMethod();
5993 var isPost = method == 'POST';
5994 if(o.clientValidation === false || this.form.isValid()){
5996 if (this.form.progressUrl) {
5997 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5998 (new Date() * 1) + '' + Math.random());
6003 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6004 form:this.form.el.dom,
6005 url:this.getUrl(!isPost),
6007 params:isPost ? this.getParams() : null,
6008 isUpload: this.form.fileUpload
6011 this.uploadProgress();
6013 }else if (o.clientValidation !== false){ // client validation failed
6014 this.failureType = Roo.form.Action.CLIENT_INVALID;
6015 this.form.afterAction(this, false);
6019 success : function(response)
6021 this.uploadComplete= true;
6022 if (this.haveProgress) {
6023 Roo.MessageBox.hide();
6027 var result = this.processResponse(response);
6028 if(result === true || result.success){
6029 this.form.afterAction(this, true);
6033 this.form.markInvalid(result.errors);
6034 this.failureType = Roo.form.Action.SERVER_INVALID;
6036 this.form.afterAction(this, false);
6038 failure : function(response)
6040 this.uploadComplete= true;
6041 if (this.haveProgress) {
6042 Roo.MessageBox.hide();
6045 this.response = response;
6046 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6047 this.form.afterAction(this, false);
6050 handleResponse : function(response){
6051 if(this.form.errorReader){
6052 var rs = this.form.errorReader.read(response);
6055 for(var i = 0, len = rs.records.length; i < len; i++) {
6056 var r = rs.records[i];
6060 if(errors.length < 1){
6064 success : rs.success,
6070 ret = Roo.decode(response.responseText);
6074 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6084 Roo.form.Action.Load = function(form, options){
6085 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6086 this.reader = this.form.reader;
6089 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6094 Roo.Ajax.request(Roo.apply(
6095 this.createCallback(), {
6096 method:this.getMethod(),
6097 url:this.getUrl(false),
6098 params:this.getParams()
6102 success : function(response){
6104 var result = this.processResponse(response);
6105 if(result === true || !result.success || !result.data){
6106 this.failureType = Roo.form.Action.LOAD_FAILURE;
6107 this.form.afterAction(this, false);
6110 this.form.clearInvalid();
6111 this.form.setValues(result.data);
6112 this.form.afterAction(this, true);
6115 handleResponse : function(response){
6116 if(this.form.reader){
6117 var rs = this.form.reader.read(response);
6118 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6120 success : rs.success,
6124 return Roo.decode(response.responseText);
6128 Roo.form.Action.ACTION_TYPES = {
6129 'load' : Roo.form.Action.Load,
6130 'submit' : Roo.form.Action.Submit
6139 * @class Roo.bootstrap.Form
6140 * @extends Roo.bootstrap.Component
6141 * Bootstrap Form class
6142 * @cfg {String} method GET | POST (default POST)
6143 * @cfg {String} labelAlign top | left (default top)
6144 * @cfg {String} align left | right - for navbars
6145 * @cfg {Boolean} loadMask load mask when submit (default true)
6150 * @param {Object} config The config object
6154 Roo.bootstrap.Form = function(config){
6155 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6158 * @event clientvalidation
6159 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6160 * @param {Form} this
6161 * @param {Boolean} valid true if the form has passed client-side validation
6163 clientvalidation: true,
6165 * @event beforeaction
6166 * Fires before any action is performed. Return false to cancel the action.
6167 * @param {Form} this
6168 * @param {Action} action The action to be performed
6172 * @event actionfailed
6173 * Fires when an action fails.
6174 * @param {Form} this
6175 * @param {Action} action The action that failed
6177 actionfailed : true,
6179 * @event actioncomplete
6180 * Fires when an action is completed.
6181 * @param {Form} this
6182 * @param {Action} action The action that completed
6184 actioncomplete : true
6189 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6192 * @cfg {String} method
6193 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6198 * The URL to use for form actions if one isn't supplied in the action options.
6201 * @cfg {Boolean} fileUpload
6202 * Set to true if this form is a file upload.
6206 * @cfg {Object} baseParams
6207 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6211 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6215 * @cfg {Sting} align (left|right) for navbar forms
6220 activeAction : null,
6223 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6224 * element by passing it or its id or mask the form itself by passing in true.
6227 waitMsgTarget : false,
6231 getAutoCreate : function(){
6235 method : this.method || 'POST',
6236 id : this.id || Roo.id(),
6239 if (this.parent().xtype.match(/^Nav/)) {
6240 cfg.cls = 'navbar-form navbar-' + this.align;
6244 if (this.labelAlign == 'left' ) {
6245 cfg.cls += ' form-horizontal';
6251 initEvents : function()
6253 this.el.on('submit', this.onSubmit, this);
6254 // this was added as random key presses on the form where triggering form submit.
6255 this.el.on('keypress', function(e) {
6256 if (e.getCharCode() != 13) {
6259 // we might need to allow it for textareas.. and some other items.
6260 // check e.getTarget().
6262 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6266 Roo.log("keypress blocked");
6274 onSubmit : function(e){
6279 * Returns true if client-side validation on the form is successful.
6282 isValid : function(){
6283 var items = this.getItems();
6285 items.each(function(f){
6294 * Returns true if any fields in this form have changed since their original load.
6297 isDirty : function(){
6299 var items = this.getItems();
6300 items.each(function(f){
6310 * Performs a predefined action (submit or load) or custom actions you define on this form.
6311 * @param {String} actionName The name of the action type
6312 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6313 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6314 * accept other config options):
6316 Property Type Description
6317 ---------------- --------------- ----------------------------------------------------------------------------------
6318 url String The url for the action (defaults to the form's url)
6319 method String The form method to use (defaults to the form's method, or POST if not defined)
6320 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6321 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6322 validate the form on the client (defaults to false)
6324 * @return {BasicForm} this
6326 doAction : function(action, options){
6327 if(typeof action == 'string'){
6328 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6330 if(this.fireEvent('beforeaction', this, action) !== false){
6331 this.beforeAction(action);
6332 action.run.defer(100, action);
6338 beforeAction : function(action){
6339 var o = action.options;
6342 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6344 // not really supported yet.. ??
6346 //if(this.waitMsgTarget === true){
6347 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6348 //}else if(this.waitMsgTarget){
6349 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6350 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6352 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6358 afterAction : function(action, success){
6359 this.activeAction = null;
6360 var o = action.options;
6362 //if(this.waitMsgTarget === true){
6364 //}else if(this.waitMsgTarget){
6365 // this.waitMsgTarget.unmask();
6367 // Roo.MessageBox.updateProgress(1);
6368 // Roo.MessageBox.hide();
6375 Roo.callback(o.success, o.scope, [this, action]);
6376 this.fireEvent('actioncomplete', this, action);
6380 // failure condition..
6381 // we have a scenario where updates need confirming.
6382 // eg. if a locking scenario exists..
6383 // we look for { errors : { needs_confirm : true }} in the response.
6385 (typeof(action.result) != 'undefined') &&
6386 (typeof(action.result.errors) != 'undefined') &&
6387 (typeof(action.result.errors.needs_confirm) != 'undefined')
6390 Roo.log("not supported yet");
6393 Roo.MessageBox.confirm(
6394 "Change requires confirmation",
6395 action.result.errorMsg,
6400 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6410 Roo.callback(o.failure, o.scope, [this, action]);
6411 // show an error message if no failed handler is set..
6412 if (!this.hasListener('actionfailed')) {
6413 Roo.log("need to add dialog support");
6415 Roo.MessageBox.alert("Error",
6416 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6417 action.result.errorMsg :
6418 "Saving Failed, please check your entries or try again"
6423 this.fireEvent('actionfailed', this, action);
6428 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6429 * @param {String} id The value to search for
6432 findField : function(id){
6433 var items = this.getItems();
6434 var field = items.get(id);
6436 items.each(function(f){
6437 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6444 return field || null;
6447 * Mark fields in this form invalid in bulk.
6448 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6449 * @return {BasicForm} this
6451 markInvalid : function(errors){
6452 if(errors instanceof Array){
6453 for(var i = 0, len = errors.length; i < len; i++){
6454 var fieldError = errors[i];
6455 var f = this.findField(fieldError.id);
6457 f.markInvalid(fieldError.msg);
6463 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6464 field.markInvalid(errors[id]);
6468 //Roo.each(this.childForms || [], function (f) {
6469 // f.markInvalid(errors);
6476 * Set values for fields in this form in bulk.
6477 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6478 * @return {BasicForm} this
6480 setValues : function(values){
6481 if(values instanceof Array){ // array of objects
6482 for(var i = 0, len = values.length; i < len; i++){
6484 var f = this.findField(v.id);
6486 f.setValue(v.value);
6487 if(this.trackResetOnLoad){
6488 f.originalValue = f.getValue();
6492 }else{ // object hash
6495 if(typeof values[id] != 'function' && (field = this.findField(id))){
6497 if (field.setFromData &&
6499 field.displayField &&
6500 // combos' with local stores can
6501 // be queried via setValue()
6502 // to set their value..
6503 (field.store && !field.store.isLocal)
6507 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6508 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6509 field.setFromData(sd);
6512 field.setValue(values[id]);
6516 if(this.trackResetOnLoad){
6517 field.originalValue = field.getValue();
6523 //Roo.each(this.childForms || [], function (f) {
6524 // f.setValues(values);
6531 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6532 * they are returned as an array.
6533 * @param {Boolean} asString
6536 getValues : function(asString){
6537 //if (this.childForms) {
6538 // copy values from the child forms
6539 // Roo.each(this.childForms, function (f) {
6540 // this.setValues(f.getValues());
6546 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6547 if(asString === true){
6550 return Roo.urlDecode(fs);
6554 * Returns the fields in this form as an object with key/value pairs.
6555 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6558 getFieldValues : function(with_hidden)
6560 var items = this.getItems();
6562 items.each(function(f){
6566 var v = f.getValue();
6567 if (f.inputType =='radio') {
6568 if (typeof(ret[f.getName()]) == 'undefined') {
6569 ret[f.getName()] = ''; // empty..
6572 if (!f.el.dom.checked) {
6580 // not sure if this supported any more..
6581 if ((typeof(v) == 'object') && f.getRawValue) {
6582 v = f.getRawValue() ; // dates..
6584 // combo boxes where name != hiddenName...
6585 if (f.name != f.getName()) {
6586 ret[f.name] = f.getRawValue();
6588 ret[f.getName()] = v;
6595 * Clears all invalid messages in this form.
6596 * @return {BasicForm} this
6598 clearInvalid : function(){
6599 var items = this.getItems();
6601 items.each(function(f){
6612 * @return {BasicForm} this
6615 var items = this.getItems();
6616 items.each(function(f){
6620 Roo.each(this.childForms || [], function (f) {
6627 getItems : function()
6629 var r=new Roo.util.MixedCollection(false, function(o){
6630 return o.id || (o.id = Roo.id());
6632 var iter = function(el) {
6639 Roo.each(el.items,function(e) {
6658 * Ext JS Library 1.1.1
6659 * Copyright(c) 2006-2007, Ext JS, LLC.
6661 * Originally Released Under LGPL - original licence link has changed is not relivant.
6664 * <script type="text/javascript">
6667 * @class Roo.form.VTypes
6668 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6671 Roo.form.VTypes = function(){
6672 // closure these in so they are only created once.
6673 var alpha = /^[a-zA-Z_]+$/;
6674 var alphanum = /^[a-zA-Z0-9_]+$/;
6675 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6676 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6678 // All these messages and functions are configurable
6681 * The function used to validate email addresses
6682 * @param {String} value The email address
6684 'email' : function(v){
6685 return email.test(v);
6688 * The error text to display when the email validation function returns false
6691 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6693 * The keystroke filter mask to be applied on email input
6696 'emailMask' : /[a-z0-9_\.\-@]/i,
6699 * The function used to validate URLs
6700 * @param {String} value The URL
6702 'url' : function(v){
6706 * The error text to display when the url validation function returns false
6709 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6712 * The function used to validate alpha values
6713 * @param {String} value The value
6715 'alpha' : function(v){
6716 return alpha.test(v);
6719 * The error text to display when the alpha validation function returns false
6722 'alphaText' : 'This field should only contain letters and _',
6724 * The keystroke filter mask to be applied on alpha input
6727 'alphaMask' : /[a-z_]/i,
6730 * The function used to validate alphanumeric values
6731 * @param {String} value The value
6733 'alphanum' : function(v){
6734 return alphanum.test(v);
6737 * The error text to display when the alphanumeric validation function returns false
6740 'alphanumText' : 'This field should only contain letters, numbers and _',
6742 * The keystroke filter mask to be applied on alphanumeric input
6745 'alphanumMask' : /[a-z0-9_]/i
6755 * @class Roo.bootstrap.Input
6756 * @extends Roo.bootstrap.Component
6757 * Bootstrap Input class
6758 * @cfg {Boolean} disabled is it disabled
6759 * @cfg {String} fieldLabel - the label associated
6760 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6761 * @cfg {String} name name of the input
6762 * @cfg {string} fieldLabel - the label associated
6763 * @cfg {string} inputType - input / file submit ...
6764 * @cfg {string} placeholder - placeholder to put in text.
6765 * @cfg {string} before - input group add on before
6766 * @cfg {string} after - input group add on after
6767 * @cfg {string} size - (lg|sm) or leave empty..
6768 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6769 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6770 * @cfg {Number} md colspan out of 12 for computer-sized screens
6771 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6772 * @cfg {string} value default value of the input
6773 * @cfg {Number} labelWidth set the width of label (0-12)
6774 * @cfg {String} labelAlign (top|left)
6775 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6776 * @cfg {String} align (left|center|right) Default left
6780 * Create a new Input
6781 * @param {Object} config The config object
6784 Roo.bootstrap.Input = function(config){
6785 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6790 * Fires when this field receives input focus.
6791 * @param {Roo.form.Field} this
6796 * Fires when this field loses input focus.
6797 * @param {Roo.form.Field} this
6802 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6803 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6804 * @param {Roo.form.Field} this
6805 * @param {Roo.EventObject} e The event object
6810 * Fires just before the field blurs if the field value has changed.
6811 * @param {Roo.form.Field} this
6812 * @param {Mixed} newValue The new value
6813 * @param {Mixed} oldValue The original value
6818 * Fires after the field has been marked as invalid.
6819 * @param {Roo.form.Field} this
6820 * @param {String} msg The validation message
6825 * Fires after the field has been validated with no errors.
6826 * @param {Roo.form.Field} this
6831 * Fires after the key up
6832 * @param {Roo.form.Field} this
6833 * @param {Roo.EventObject} e The event Object
6839 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6841 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6842 automatic validation (defaults to "keyup").
6844 validationEvent : "keyup",
6846 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6848 validateOnBlur : true,
6850 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6852 validationDelay : 250,
6854 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6856 focusClass : "x-form-focus", // not needed???
6860 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6862 invalidClass : "has-error",
6865 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6867 selectOnFocus : false,
6870 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6874 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6879 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6881 disableKeyFilter : false,
6884 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6888 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6892 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6894 blankText : "This field is required",
6897 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6901 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6903 maxLength : Number.MAX_VALUE,
6905 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6907 minLengthText : "The minimum length for this field is {0}",
6909 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6911 maxLengthText : "The maximum length for this field is {0}",
6915 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6916 * If available, this function will be called only after the basic validators all return true, and will be passed the
6917 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6921 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6922 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6923 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6927 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6950 formatedValue : false,
6952 parentLabelAlign : function()
6955 while (parent.parent()) {
6956 parent = parent.parent();
6957 if (typeof(parent.labelAlign) !='undefined') {
6958 return parent.labelAlign;
6965 getAutoCreate : function(){
6967 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6973 if(this.inputType != 'hidden'){
6974 cfg.cls = 'form-group' //input-group
6980 type : this.inputType,
6982 cls : 'form-control',
6983 placeholder : this.placeholder || ''
6988 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6991 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6992 input.maxLength = this.maxLength;
6995 if (this.disabled) {
6996 input.disabled=true;
6999 if (this.readOnly) {
7000 input.readonly=true;
7004 input.name = this.name;
7007 input.cls += ' input-' + this.size;
7010 ['xs','sm','md','lg'].map(function(size){
7011 if (settings[size]) {
7012 cfg.cls += ' col-' + size + '-' + settings[size];
7016 var inputblock = input;
7018 if (this.before || this.after) {
7021 cls : 'input-group',
7024 if (this.before && typeof(this.before) == 'string') {
7026 inputblock.cn.push({
7028 cls : 'roo-input-before input-group-addon',
7032 if (this.before && typeof(this.before) == 'object') {
7033 this.before = Roo.factory(this.before);
7034 Roo.log(this.before);
7035 inputblock.cn.push({
7037 cls : 'roo-input-before input-group-' +
7038 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7042 inputblock.cn.push(input);
7044 if (this.after && typeof(this.after) == 'string') {
7045 inputblock.cn.push({
7047 cls : 'roo-input-after input-group-addon',
7051 if (this.after && typeof(this.after) == 'object') {
7052 this.after = Roo.factory(this.after);
7053 Roo.log(this.after);
7054 inputblock.cn.push({
7056 cls : 'roo-input-after input-group-' +
7057 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7062 if (align ==='left' && this.fieldLabel.length) {
7063 Roo.log("left and has label");
7069 cls : 'control-label col-sm-' + this.labelWidth,
7070 html : this.fieldLabel
7074 cls : "col-sm-" + (12 - this.labelWidth),
7081 } else if ( this.fieldLabel.length) {
7087 //cls : 'input-group-addon',
7088 html : this.fieldLabel
7098 Roo.log(" no label && no align");
7107 Roo.log('input-parentType: ' + this.parentType);
7109 if (this.parentType === 'Navbar' && this.parent().bar) {
7110 cfg.cls += ' navbar-form';
7118 * return the real input element.
7120 inputEl: function ()
7122 return this.el.select('input.form-control',true).first();
7124 setDisabled : function(v)
7126 var i = this.inputEl().dom;
7128 i.removeAttribute('disabled');
7132 i.setAttribute('disabled','true');
7134 initEvents : function()
7137 this.inputEl().on("keydown" , this.fireKey, this);
7138 this.inputEl().on("focus", this.onFocus, this);
7139 this.inputEl().on("blur", this.onBlur, this);
7141 this.inputEl().relayEvent('keyup', this);
7143 // reference to original value for reset
7144 this.originalValue = this.getValue();
7145 //Roo.form.TextField.superclass.initEvents.call(this);
7146 if(this.validationEvent == 'keyup'){
7147 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7148 this.inputEl().on('keyup', this.filterValidation, this);
7150 else if(this.validationEvent !== false){
7151 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7154 if(this.selectOnFocus){
7155 this.on("focus", this.preFocus, this);
7158 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7159 this.inputEl().on("keypress", this.filterKeys, this);
7162 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7163 this.el.on("click", this.autoSize, this);
7166 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7167 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7170 if (typeof(this.before) == 'object') {
7171 this.before.render(this.el.select('.roo-input-before',true).first());
7173 if (typeof(this.after) == 'object') {
7174 this.after.render(this.el.select('.roo-input-after',true).first());
7179 filterValidation : function(e){
7180 if(!e.isNavKeyPress()){
7181 this.validationTask.delay(this.validationDelay);
7185 * Validates the field value
7186 * @return {Boolean} True if the value is valid, else false
7188 validate : function(){
7189 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7190 if(this.disabled || this.validateValue(this.getRawValue())){
7191 this.clearInvalid();
7199 * Validates a value according to the field's validation rules and marks the field as invalid
7200 * if the validation fails
7201 * @param {Mixed} value The value to validate
7202 * @return {Boolean} True if the value is valid, else false
7204 validateValue : function(value){
7205 if(value.length < 1) { // if it's blank
7206 if(this.allowBlank){
7207 this.clearInvalid();
7210 this.markInvalid(this.blankText);
7214 if(value.length < this.minLength){
7215 this.markInvalid(String.format(this.minLengthText, this.minLength));
7218 if(value.length > this.maxLength){
7219 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7223 var vt = Roo.form.VTypes;
7224 if(!vt[this.vtype](value, this)){
7225 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7229 if(typeof this.validator == "function"){
7230 var msg = this.validator(value);
7232 this.markInvalid(msg);
7236 if(this.regex && !this.regex.test(value)){
7237 this.markInvalid(this.regexText);
7246 fireKey : function(e){
7247 //Roo.log('field ' + e.getKey());
7248 if(e.isNavKeyPress()){
7249 this.fireEvent("specialkey", this, e);
7252 focus : function (selectText){
7254 this.inputEl().focus();
7255 if(selectText === true){
7256 this.inputEl().dom.select();
7262 onFocus : function(){
7263 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7264 // this.el.addClass(this.focusClass);
7267 this.hasFocus = true;
7268 this.startValue = this.getValue();
7269 this.fireEvent("focus", this);
7273 beforeBlur : Roo.emptyFn,
7277 onBlur : function(){
7279 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7280 //this.el.removeClass(this.focusClass);
7282 this.hasFocus = false;
7283 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7286 var v = this.getValue();
7287 if(String(v) !== String(this.startValue)){
7288 this.fireEvent('change', this, v, this.startValue);
7290 this.fireEvent("blur", this);
7294 * Resets the current field value to the originally loaded value and clears any validation messages
7297 this.setValue(this.originalValue);
7298 this.clearInvalid();
7301 * Returns the name of the field
7302 * @return {Mixed} name The name field
7304 getName: function(){
7308 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7309 * @return {Mixed} value The field value
7311 getValue : function(){
7313 var v = this.inputEl().getValue();
7318 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7319 * @return {Mixed} value The field value
7321 getRawValue : function(){
7322 var v = this.inputEl().getValue();
7328 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7329 * @param {Mixed} value The value to set
7331 setRawValue : function(v){
7332 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7335 selectText : function(start, end){
7336 var v = this.getRawValue();
7338 start = start === undefined ? 0 : start;
7339 end = end === undefined ? v.length : end;
7340 var d = this.inputEl().dom;
7341 if(d.setSelectionRange){
7342 d.setSelectionRange(start, end);
7343 }else if(d.createTextRange){
7344 var range = d.createTextRange();
7345 range.moveStart("character", start);
7346 range.moveEnd("character", v.length-end);
7353 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7354 * @param {Mixed} value The value to set
7356 setValue : function(v){
7359 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7365 processValue : function(value){
7366 if(this.stripCharsRe){
7367 var newValue = value.replace(this.stripCharsRe, '');
7368 if(newValue !== value){
7369 this.setRawValue(newValue);
7376 preFocus : function(){
7378 if(this.selectOnFocus){
7379 this.inputEl().dom.select();
7382 filterKeys : function(e){
7384 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7387 var c = e.getCharCode(), cc = String.fromCharCode(c);
7388 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7391 if(!this.maskRe.test(cc)){
7396 * Clear any invalid styles/messages for this field
7398 clearInvalid : function(){
7400 if(!this.el || this.preventMark){ // not rendered
7403 this.el.removeClass(this.invalidClass);
7405 switch(this.msgTarget){
7407 this.el.dom.qtip = '';
7410 this.el.dom.title = '';
7414 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7419 this.errorIcon.dom.qtip = '';
7420 this.errorIcon.hide();
7421 this.un('resize', this.alignErrorIcon, this);
7425 var t = Roo.getDom(this.msgTarget);
7427 t.style.display = 'none';
7431 this.fireEvent('valid', this);
7434 * Mark this field as invalid
7435 * @param {String} msg The validation message
7437 markInvalid : function(msg){
7438 if(!this.el || this.preventMark){ // not rendered
7441 this.el.addClass(this.invalidClass);
7443 msg = msg || this.invalidText;
7444 switch(this.msgTarget){
7446 this.el.dom.qtip = msg;
7447 this.el.dom.qclass = 'x-form-invalid-tip';
7448 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7449 Roo.QuickTips.enable();
7453 this.el.dom.title = msg;
7457 var elp = this.el.findParent('.x-form-element', 5, true);
7458 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7459 this.errorEl.setWidth(elp.getWidth(true)-20);
7461 this.errorEl.update(msg);
7462 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7465 if(!this.errorIcon){
7466 var elp = this.el.findParent('.x-form-element', 5, true);
7467 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7469 this.alignErrorIcon();
7470 this.errorIcon.dom.qtip = msg;
7471 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7472 this.errorIcon.show();
7473 this.on('resize', this.alignErrorIcon, this);
7476 var t = Roo.getDom(this.msgTarget);
7478 t.style.display = this.msgDisplay;
7482 this.fireEvent('invalid', this, msg);
7485 SafariOnKeyDown : function(event)
7487 // this is a workaround for a password hang bug on chrome/ webkit.
7489 var isSelectAll = false;
7491 if(this.inputEl().dom.selectionEnd > 0){
7492 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7494 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7495 event.preventDefault();
7500 if(isSelectAll){ // backspace and delete key
7502 event.preventDefault();
7503 // this is very hacky as keydown always get's upper case.
7505 var cc = String.fromCharCode(event.getCharCode());
7506 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7510 adjustWidth : function(tag, w){
7511 tag = tag.toLowerCase();
7512 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7513 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7517 if(tag == 'textarea'){
7520 }else if(Roo.isOpera){
7524 if(tag == 'textarea'){
7543 * @class Roo.bootstrap.TextArea
7544 * @extends Roo.bootstrap.Input
7545 * Bootstrap TextArea class
7546 * @cfg {Number} cols Specifies the visible width of a text area
7547 * @cfg {Number} rows Specifies the visible number of lines in a text area
7548 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7549 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7550 * @cfg {string} html text
7553 * Create a new TextArea
7554 * @param {Object} config The config object
7557 Roo.bootstrap.TextArea = function(config){
7558 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7562 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7572 getAutoCreate : function(){
7574 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7585 value : this.value || '',
7586 html: this.html || '',
7587 cls : 'form-control',
7588 placeholder : this.placeholder || ''
7592 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7593 input.maxLength = this.maxLength;
7597 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7601 input.cols = this.cols;
7604 if (this.readOnly) {
7605 input.readonly = true;
7609 input.name = this.name;
7613 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7617 ['xs','sm','md','lg'].map(function(size){
7618 if (settings[size]) {
7619 cfg.cls += ' col-' + size + '-' + settings[size];
7623 var inputblock = input;
7625 if (this.before || this.after) {
7628 cls : 'input-group',
7632 inputblock.cn.push({
7634 cls : 'input-group-addon',
7638 inputblock.cn.push(input);
7640 inputblock.cn.push({
7642 cls : 'input-group-addon',
7649 if (align ==='left' && this.fieldLabel.length) {
7650 Roo.log("left and has label");
7656 cls : 'control-label col-sm-' + this.labelWidth,
7657 html : this.fieldLabel
7661 cls : "col-sm-" + (12 - this.labelWidth),
7668 } else if ( this.fieldLabel.length) {
7674 //cls : 'input-group-addon',
7675 html : this.fieldLabel
7685 Roo.log(" no label && no align");
7695 if (this.disabled) {
7696 input.disabled=true;
7703 * return the real textarea element.
7705 inputEl: function ()
7707 return this.el.select('textarea.form-control',true).first();
7715 * trigger field - base class for combo..
7720 * @class Roo.bootstrap.TriggerField
7721 * @extends Roo.bootstrap.Input
7722 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7723 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7724 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7725 * for which you can provide a custom implementation. For example:
7727 var trigger = new Roo.bootstrap.TriggerField();
7728 trigger.onTriggerClick = myTriggerFn;
7729 trigger.applyTo('my-field');
7732 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7733 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7734 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7735 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7737 * Create a new TriggerField.
7738 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7739 * to the base TextField)
7741 Roo.bootstrap.TriggerField = function(config){
7742 this.mimicing = false;
7743 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7746 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7748 * @cfg {String} triggerClass A CSS class to apply to the trigger
7751 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7755 /** @cfg {Boolean} grow @hide */
7756 /** @cfg {Number} growMin @hide */
7757 /** @cfg {Number} growMax @hide */
7763 autoSize: Roo.emptyFn,
7770 actionMode : 'wrap',
7774 getAutoCreate : function(){
7776 var align = this.labelAlign || this.parentLabelAlign();
7781 cls: 'form-group' //input-group
7788 type : this.inputType,
7789 cls : 'form-control',
7790 autocomplete: 'off',
7791 placeholder : this.placeholder || ''
7795 input.name = this.name;
7798 input.cls += ' input-' + this.size;
7801 if (this.disabled) {
7802 input.disabled=true;
7805 var inputblock = input;
7807 if (this.before || this.after) {
7810 cls : 'input-group',
7814 inputblock.cn.push({
7816 cls : 'input-group-addon',
7820 inputblock.cn.push(input);
7822 inputblock.cn.push({
7824 cls : 'input-group-addon',
7837 cls: 'form-hidden-field'
7845 Roo.log('multiple');
7853 cls: 'form-hidden-field'
7857 cls: 'select2-choices',
7861 cls: 'select2-search-field',
7874 cls: 'select2-container input-group',
7879 // cls: 'typeahead typeahead-long dropdown-menu',
7880 // style: 'display:none'
7885 if(!this.multiple && this.showToggleBtn){
7888 cls : 'input-group-addon btn dropdown-toggle',
7896 cls: 'combobox-clear',
7910 combobox.cls += ' select2-container-multi';
7913 if (align ==='left' && this.fieldLabel.length) {
7915 Roo.log("left and has label");
7921 cls : 'control-label col-sm-' + this.labelWidth,
7922 html : this.fieldLabel
7926 cls : "col-sm-" + (12 - this.labelWidth),
7933 } else if ( this.fieldLabel.length) {
7939 //cls : 'input-group-addon',
7940 html : this.fieldLabel
7950 Roo.log(" no label && no align");
7957 ['xs','sm','md','lg'].map(function(size){
7958 if (settings[size]) {
7959 cfg.cls += ' col-' + size + '-' + settings[size];
7970 onResize : function(w, h){
7971 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7972 // if(typeof w == 'number'){
7973 // var x = w - this.trigger.getWidth();
7974 // this.inputEl().setWidth(this.adjustWidth('input', x));
7975 // this.trigger.setStyle('left', x+'px');
7980 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7983 getResizeEl : function(){
7984 return this.inputEl();
7988 getPositionEl : function(){
7989 return this.inputEl();
7993 alignErrorIcon : function(){
7994 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7998 initEvents : function(){
8002 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8003 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8004 if(!this.multiple && this.showToggleBtn){
8005 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8006 if(this.hideTrigger){
8007 this.trigger.setDisplayed(false);
8009 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8013 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8016 //this.trigger.addClassOnOver('x-form-trigger-over');
8017 //this.trigger.addClassOnClick('x-form-trigger-click');
8020 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8024 createList : function()
8026 this.list = Roo.get(document.body).createChild({
8028 cls: 'typeahead typeahead-long dropdown-menu',
8029 style: 'display:none'
8032 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8037 initTrigger : function(){
8042 onDestroy : function(){
8044 this.trigger.removeAllListeners();
8045 // this.trigger.remove();
8048 // this.wrap.remove();
8050 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8054 onFocus : function(){
8055 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8058 this.wrap.addClass('x-trigger-wrap-focus');
8059 this.mimicing = true;
8060 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8061 if(this.monitorTab){
8062 this.el.on("keydown", this.checkTab, this);
8069 checkTab : function(e){
8070 if(e.getKey() == e.TAB){
8076 onBlur : function(){
8081 mimicBlur : function(e, t){
8083 if(!this.wrap.contains(t) && this.validateBlur()){
8090 triggerBlur : function(){
8091 this.mimicing = false;
8092 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8093 if(this.monitorTab){
8094 this.el.un("keydown", this.checkTab, this);
8096 //this.wrap.removeClass('x-trigger-wrap-focus');
8097 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8101 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8102 validateBlur : function(e, t){
8107 onDisable : function(){
8108 this.inputEl().dom.disabled = true;
8109 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8111 // this.wrap.addClass('x-item-disabled');
8116 onEnable : function(){
8117 this.inputEl().dom.disabled = false;
8118 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8120 // this.el.removeClass('x-item-disabled');
8125 onShow : function(){
8126 var ae = this.getActionEl();
8129 ae.dom.style.display = '';
8130 ae.dom.style.visibility = 'visible';
8136 onHide : function(){
8137 var ae = this.getActionEl();
8138 ae.dom.style.display = 'none';
8142 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8143 * by an implementing function.
8145 * @param {EventObject} e
8147 onTriggerClick : Roo.emptyFn
8151 * Ext JS Library 1.1.1
8152 * Copyright(c) 2006-2007, Ext JS, LLC.
8154 * Originally Released Under LGPL - original licence link has changed is not relivant.
8157 * <script type="text/javascript">
8162 * @class Roo.data.SortTypes
8164 * Defines the default sorting (casting?) comparison functions used when sorting data.
8166 Roo.data.SortTypes = {
8168 * Default sort that does nothing
8169 * @param {Mixed} s The value being converted
8170 * @return {Mixed} The comparison value
8177 * The regular expression used to strip tags
8181 stripTagsRE : /<\/?[^>]+>/gi,
8184 * Strips all HTML tags to sort on text only
8185 * @param {Mixed} s The value being converted
8186 * @return {String} The comparison value
8188 asText : function(s){
8189 return String(s).replace(this.stripTagsRE, "");
8193 * Strips all HTML tags to sort on text only - Case insensitive
8194 * @param {Mixed} s The value being converted
8195 * @return {String} The comparison value
8197 asUCText : function(s){
8198 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8202 * Case insensitive string
8203 * @param {Mixed} s The value being converted
8204 * @return {String} The comparison value
8206 asUCString : function(s) {
8207 return String(s).toUpperCase();
8212 * @param {Mixed} s The value being converted
8213 * @return {Number} The comparison value
8215 asDate : function(s) {
8219 if(s instanceof Date){
8222 return Date.parse(String(s));
8227 * @param {Mixed} s The value being converted
8228 * @return {Float} The comparison value
8230 asFloat : function(s) {
8231 var val = parseFloat(String(s).replace(/,/g, ""));
8232 if(isNaN(val)) val = 0;
8238 * @param {Mixed} s The value being converted
8239 * @return {Number} The comparison value
8241 asInt : function(s) {
8242 var val = parseInt(String(s).replace(/,/g, ""));
8243 if(isNaN(val)) val = 0;
8248 * Ext JS Library 1.1.1
8249 * Copyright(c) 2006-2007, Ext JS, LLC.
8251 * Originally Released Under LGPL - original licence link has changed is not relivant.
8254 * <script type="text/javascript">
8258 * @class Roo.data.Record
8259 * Instances of this class encapsulate both record <em>definition</em> information, and record
8260 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8261 * to access Records cached in an {@link Roo.data.Store} object.<br>
8263 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8264 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8267 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8269 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8270 * {@link #create}. The parameters are the same.
8271 * @param {Array} data An associative Array of data values keyed by the field name.
8272 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8273 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8274 * not specified an integer id is generated.
8276 Roo.data.Record = function(data, id){
8277 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8282 * Generate a constructor for a specific record layout.
8283 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8284 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8285 * Each field definition object may contain the following properties: <ul>
8286 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
8287 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8288 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8289 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8290 * is being used, then this is a string containing the javascript expression to reference the data relative to
8291 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8292 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8293 * this may be omitted.</p></li>
8294 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8295 * <ul><li>auto (Default, implies no conversion)</li>
8300 * <li>date</li></ul></p></li>
8301 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8302 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8303 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8304 * by the Reader into an object that will be stored in the Record. It is passed the
8305 * following parameters:<ul>
8306 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8308 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8310 * <br>usage:<br><pre><code>
8311 var TopicRecord = Roo.data.Record.create(
8312 {name: 'title', mapping: 'topic_title'},
8313 {name: 'author', mapping: 'username'},
8314 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8315 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8316 {name: 'lastPoster', mapping: 'user2'},
8317 {name: 'excerpt', mapping: 'post_text'}
8320 var myNewRecord = new TopicRecord({
8321 title: 'Do my job please',
8324 lastPost: new Date(),
8325 lastPoster: 'Animal',
8326 excerpt: 'No way dude!'
8328 myStore.add(myNewRecord);
8333 Roo.data.Record.create = function(o){
8335 f.superclass.constructor.apply(this, arguments);
8337 Roo.extend(f, Roo.data.Record);
8338 var p = f.prototype;
8339 p.fields = new Roo.util.MixedCollection(false, function(field){
8342 for(var i = 0, len = o.length; i < len; i++){
8343 p.fields.add(new Roo.data.Field(o[i]));
8345 f.getField = function(name){
8346 return p.fields.get(name);
8351 Roo.data.Record.AUTO_ID = 1000;
8352 Roo.data.Record.EDIT = 'edit';
8353 Roo.data.Record.REJECT = 'reject';
8354 Roo.data.Record.COMMIT = 'commit';
8356 Roo.data.Record.prototype = {
8358 * Readonly flag - true if this record has been modified.
8367 join : function(store){
8372 * Set the named field to the specified value.
8373 * @param {String} name The name of the field to set.
8374 * @param {Object} value The value to set the field to.
8376 set : function(name, value){
8377 if(this.data[name] == value){
8384 if(typeof this.modified[name] == 'undefined'){
8385 this.modified[name] = this.data[name];
8387 this.data[name] = value;
8388 if(!this.editing && this.store){
8389 this.store.afterEdit(this);
8394 * Get the value of the named field.
8395 * @param {String} name The name of the field to get the value of.
8396 * @return {Object} The value of the field.
8398 get : function(name){
8399 return this.data[name];
8403 beginEdit : function(){
8404 this.editing = true;
8409 cancelEdit : function(){
8410 this.editing = false;
8411 delete this.modified;
8415 endEdit : function(){
8416 this.editing = false;
8417 if(this.dirty && this.store){
8418 this.store.afterEdit(this);
8423 * Usually called by the {@link Roo.data.Store} which owns the Record.
8424 * Rejects all changes made to the Record since either creation, or the last commit operation.
8425 * Modified fields are reverted to their original values.
8427 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8428 * of reject operations.
8430 reject : function(){
8431 var m = this.modified;
8433 if(typeof m[n] != "function"){
8434 this.data[n] = m[n];
8438 delete this.modified;
8439 this.editing = false;
8441 this.store.afterReject(this);
8446 * Usually called by the {@link Roo.data.Store} which owns the Record.
8447 * Commits all changes made to the Record since either creation, or the last commit operation.
8449 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8450 * of commit operations.
8452 commit : function(){
8454 delete this.modified;
8455 this.editing = false;
8457 this.store.afterCommit(this);
8462 hasError : function(){
8463 return this.error != null;
8467 clearError : function(){
8472 * Creates a copy of this record.
8473 * @param {String} id (optional) A new record id if you don't want to use this record's id
8476 copy : function(newId) {
8477 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8481 * Ext JS Library 1.1.1
8482 * Copyright(c) 2006-2007, Ext JS, LLC.
8484 * Originally Released Under LGPL - original licence link has changed is not relivant.
8487 * <script type="text/javascript">
8493 * @class Roo.data.Store
8494 * @extends Roo.util.Observable
8495 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8496 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8498 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
8499 * has no knowledge of the format of the data returned by the Proxy.<br>
8501 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8502 * instances from the data object. These records are cached and made available through accessor functions.
8504 * Creates a new Store.
8505 * @param {Object} config A config object containing the objects needed for the Store to access data,
8506 * and read the data into Records.
8508 Roo.data.Store = function(config){
8509 this.data = new Roo.util.MixedCollection(false);
8510 this.data.getKey = function(o){
8513 this.baseParams = {};
8520 "multisort" : "_multisort"
8523 if(config && config.data){
8524 this.inlineData = config.data;
8528 Roo.apply(this, config);
8530 if(this.reader){ // reader passed
8531 this.reader = Roo.factory(this.reader, Roo.data);
8532 this.reader.xmodule = this.xmodule || false;
8533 if(!this.recordType){
8534 this.recordType = this.reader.recordType;
8536 if(this.reader.onMetaChange){
8537 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8541 if(this.recordType){
8542 this.fields = this.recordType.prototype.fields;
8548 * @event datachanged
8549 * Fires when the data cache has changed, and a widget which is using this Store
8550 * as a Record cache should refresh its view.
8551 * @param {Store} this
8556 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8557 * @param {Store} this
8558 * @param {Object} meta The JSON metadata
8563 * Fires when Records have been added to the Store
8564 * @param {Store} this
8565 * @param {Roo.data.Record[]} records The array of Records added
8566 * @param {Number} index The index at which the record(s) were added
8571 * Fires when a Record has been removed from the Store
8572 * @param {Store} this
8573 * @param {Roo.data.Record} record The Record that was removed
8574 * @param {Number} index The index at which the record was removed
8579 * Fires when a Record has been updated
8580 * @param {Store} this
8581 * @param {Roo.data.Record} record The Record that was updated
8582 * @param {String} operation The update operation being performed. Value may be one of:
8584 Roo.data.Record.EDIT
8585 Roo.data.Record.REJECT
8586 Roo.data.Record.COMMIT
8592 * Fires when the data cache has been cleared.
8593 * @param {Store} this
8598 * Fires before a request is made for a new data object. If the beforeload handler returns false
8599 * the load action will be canceled.
8600 * @param {Store} this
8601 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8605 * @event beforeloadadd
8606 * Fires after a new set of Records has been loaded.
8607 * @param {Store} this
8608 * @param {Roo.data.Record[]} records The Records that were loaded
8609 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8611 beforeloadadd : true,
8614 * Fires after a new set of Records has been loaded, before they are added to the store.
8615 * @param {Store} this
8616 * @param {Roo.data.Record[]} records The Records that were loaded
8617 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8618 * @params {Object} return from reader
8622 * @event loadexception
8623 * Fires if an exception occurs in the Proxy during loading.
8624 * Called with the signature of the Proxy's "loadexception" event.
8625 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8628 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8629 * @param {Object} load options
8630 * @param {Object} jsonData from your request (normally this contains the Exception)
8632 loadexception : true
8636 this.proxy = Roo.factory(this.proxy, Roo.data);
8637 this.proxy.xmodule = this.xmodule || false;
8638 this.relayEvents(this.proxy, ["loadexception"]);
8640 this.sortToggle = {};
8641 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8643 Roo.data.Store.superclass.constructor.call(this);
8645 if(this.inlineData){
8646 this.loadData(this.inlineData);
8647 delete this.inlineData;
8651 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8653 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8654 * without a remote query - used by combo/forms at present.
8658 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8661 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8664 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8665 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8668 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8669 * on any HTTP request
8672 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8675 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8679 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8680 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8685 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8686 * loaded or when a record is removed. (defaults to false).
8688 pruneModifiedRecords : false,
8694 * Add Records to the Store and fires the add event.
8695 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8697 add : function(records){
8698 records = [].concat(records);
8699 for(var i = 0, len = records.length; i < len; i++){
8700 records[i].join(this);
8702 var index = this.data.length;
8703 this.data.addAll(records);
8704 this.fireEvent("add", this, records, index);
8708 * Remove a Record from the Store and fires the remove event.
8709 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8711 remove : function(record){
8712 var index = this.data.indexOf(record);
8713 this.data.removeAt(index);
8714 if(this.pruneModifiedRecords){
8715 this.modified.remove(record);
8717 this.fireEvent("remove", this, record, index);
8721 * Remove all Records from the Store and fires the clear event.
8723 removeAll : function(){
8725 if(this.pruneModifiedRecords){
8728 this.fireEvent("clear", this);
8732 * Inserts Records to the Store at the given index and fires the add event.
8733 * @param {Number} index The start index at which to insert the passed Records.
8734 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8736 insert : function(index, records){
8737 records = [].concat(records);
8738 for(var i = 0, len = records.length; i < len; i++){
8739 this.data.insert(index, records[i]);
8740 records[i].join(this);
8742 this.fireEvent("add", this, records, index);
8746 * Get the index within the cache of the passed Record.
8747 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8748 * @return {Number} The index of the passed Record. Returns -1 if not found.
8750 indexOf : function(record){
8751 return this.data.indexOf(record);
8755 * Get the index within the cache of the Record with the passed id.
8756 * @param {String} id The id of the Record to find.
8757 * @return {Number} The index of the Record. Returns -1 if not found.
8759 indexOfId : function(id){
8760 return this.data.indexOfKey(id);
8764 * Get the Record with the specified id.
8765 * @param {String} id The id of the Record to find.
8766 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8768 getById : function(id){
8769 return this.data.key(id);
8773 * Get the Record at the specified index.
8774 * @param {Number} index The index of the Record to find.
8775 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8777 getAt : function(index){
8778 return this.data.itemAt(index);
8782 * Returns a range of Records between specified indices.
8783 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8784 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8785 * @return {Roo.data.Record[]} An array of Records
8787 getRange : function(start, end){
8788 return this.data.getRange(start, end);
8792 storeOptions : function(o){
8793 o = Roo.apply({}, o);
8796 this.lastOptions = o;
8800 * Loads the Record cache from the configured Proxy using the configured Reader.
8802 * If using remote paging, then the first load call must specify the <em>start</em>
8803 * and <em>limit</em> properties in the options.params property to establish the initial
8804 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8806 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8807 * and this call will return before the new data has been loaded. Perform any post-processing
8808 * in a callback function, or in a "load" event handler.</strong>
8810 * @param {Object} options An object containing properties which control loading options:<ul>
8811 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8812 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8813 * passed the following arguments:<ul>
8814 * <li>r : Roo.data.Record[]</li>
8815 * <li>options: Options object from the load call</li>
8816 * <li>success: Boolean success indicator</li></ul></li>
8817 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8818 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8821 load : function(options){
8822 options = options || {};
8823 if(this.fireEvent("beforeload", this, options) !== false){
8824 this.storeOptions(options);
8825 var p = Roo.apply(options.params || {}, this.baseParams);
8826 // if meta was not loaded from remote source.. try requesting it.
8827 if (!this.reader.metaFromRemote) {
8830 if(this.sortInfo && this.remoteSort){
8831 var pn = this.paramNames;
8832 p[pn["sort"]] = this.sortInfo.field;
8833 p[pn["dir"]] = this.sortInfo.direction;
8835 if (this.multiSort) {
8836 var pn = this.paramNames;
8837 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8840 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8845 * Reloads the Record cache from the configured Proxy using the configured Reader and
8846 * the options from the last load operation performed.
8847 * @param {Object} options (optional) An object containing properties which may override the options
8848 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8849 * the most recently used options are reused).
8851 reload : function(options){
8852 this.load(Roo.applyIf(options||{}, this.lastOptions));
8856 // Called as a callback by the Reader during a load operation.
8857 loadRecords : function(o, options, success){
8858 if(!o || success === false){
8859 if(success !== false){
8860 this.fireEvent("load", this, [], options, o);
8862 if(options.callback){
8863 options.callback.call(options.scope || this, [], options, false);
8867 // if data returned failure - throw an exception.
8868 if (o.success === false) {
8869 // show a message if no listener is registered.
8870 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8871 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8873 // loadmask wil be hooked into this..
8874 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8877 var r = o.records, t = o.totalRecords || r.length;
8879 this.fireEvent("beforeloadadd", this, r, options, o);
8881 if(!options || options.add !== true){
8882 if(this.pruneModifiedRecords){
8885 for(var i = 0, len = r.length; i < len; i++){
8889 this.data = this.snapshot;
8890 delete this.snapshot;
8893 this.data.addAll(r);
8894 this.totalLength = t;
8896 this.fireEvent("datachanged", this);
8898 this.totalLength = Math.max(t, this.data.length+r.length);
8901 this.fireEvent("load", this, r, options, o);
8902 if(options.callback){
8903 options.callback.call(options.scope || this, r, options, true);
8909 * Loads data from a passed data block. A Reader which understands the format of the data
8910 * must have been configured in the constructor.
8911 * @param {Object} data The data block from which to read the Records. The format of the data expected
8912 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8913 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8915 loadData : function(o, append){
8916 var r = this.reader.readRecords(o);
8917 this.loadRecords(r, {add: append}, true);
8921 * Gets the number of cached records.
8923 * <em>If using paging, this may not be the total size of the dataset. If the data object
8924 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8925 * the data set size</em>
8927 getCount : function(){
8928 return this.data.length || 0;
8932 * Gets the total number of records in the dataset as returned by the server.
8934 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8935 * the dataset size</em>
8937 getTotalCount : function(){
8938 return this.totalLength || 0;
8942 * Returns the sort state of the Store as an object with two properties:
8944 field {String} The name of the field by which the Records are sorted
8945 direction {String} The sort order, "ASC" or "DESC"
8948 getSortState : function(){
8949 return this.sortInfo;
8953 applySort : function(){
8954 if(this.sortInfo && !this.remoteSort){
8955 var s = this.sortInfo, f = s.field;
8956 var st = this.fields.get(f).sortType;
8957 var fn = function(r1, r2){
8958 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8959 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8961 this.data.sort(s.direction, fn);
8962 if(this.snapshot && this.snapshot != this.data){
8963 this.snapshot.sort(s.direction, fn);
8969 * Sets the default sort column and order to be used by the next load operation.
8970 * @param {String} fieldName The name of the field to sort by.
8971 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8973 setDefaultSort : function(field, dir){
8974 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8979 * If remote sorting is used, the sort is performed on the server, and the cache is
8980 * reloaded. If local sorting is used, the cache is sorted internally.
8981 * @param {String} fieldName The name of the field to sort by.
8982 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8984 sort : function(fieldName, dir){
8985 var f = this.fields.get(fieldName);
8987 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8989 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8990 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8995 this.sortToggle[f.name] = dir;
8996 this.sortInfo = {field: f.name, direction: dir};
8997 if(!this.remoteSort){
8999 this.fireEvent("datachanged", this);
9001 this.load(this.lastOptions);
9006 * Calls the specified function for each of the Records in the cache.
9007 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9008 * Returning <em>false</em> aborts and exits the iteration.
9009 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9011 each : function(fn, scope){
9012 this.data.each(fn, scope);
9016 * Gets all records modified since the last commit. Modified records are persisted across load operations
9017 * (e.g., during paging).
9018 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9020 getModifiedRecords : function(){
9021 return this.modified;
9025 createFilterFn : function(property, value, anyMatch){
9026 if(!value.exec){ // not a regex
9027 value = String(value);
9028 if(value.length == 0){
9031 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9034 return value.test(r.data[property]);
9039 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9040 * @param {String} property A field on your records
9041 * @param {Number} start The record index to start at (defaults to 0)
9042 * @param {Number} end The last record index to include (defaults to length - 1)
9043 * @return {Number} The sum
9045 sum : function(property, start, end){
9046 var rs = this.data.items, v = 0;
9048 end = (end || end === 0) ? end : rs.length-1;
9050 for(var i = start; i <= end; i++){
9051 v += (rs[i].data[property] || 0);
9057 * Filter the records by a specified property.
9058 * @param {String} field A field on your records
9059 * @param {String/RegExp} value Either a string that the field
9060 * should start with or a RegExp to test against the field
9061 * @param {Boolean} anyMatch True to match any part not just the beginning
9063 filter : function(property, value, anyMatch){
9064 var fn = this.createFilterFn(property, value, anyMatch);
9065 return fn ? this.filterBy(fn) : this.clearFilter();
9069 * Filter by a function. The specified function will be called with each
9070 * record in this data source. If the function returns true the record is included,
9071 * otherwise it is filtered.
9072 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9073 * @param {Object} scope (optional) The scope of the function (defaults to this)
9075 filterBy : function(fn, scope){
9076 this.snapshot = this.snapshot || this.data;
9077 this.data = this.queryBy(fn, scope||this);
9078 this.fireEvent("datachanged", this);
9082 * Query the records by a specified property.
9083 * @param {String} field A field on your records
9084 * @param {String/RegExp} value Either a string that the field
9085 * should start with or a RegExp to test against the field
9086 * @param {Boolean} anyMatch True to match any part not just the beginning
9087 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9089 query : function(property, value, anyMatch){
9090 var fn = this.createFilterFn(property, value, anyMatch);
9091 return fn ? this.queryBy(fn) : this.data.clone();
9095 * Query by a function. The specified function will be called with each
9096 * record in this data source. If the function returns true the record is included
9098 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9099 * @param {Object} scope (optional) The scope of the function (defaults to this)
9100 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9102 queryBy : function(fn, scope){
9103 var data = this.snapshot || this.data;
9104 return data.filterBy(fn, scope||this);
9108 * Collects unique values for a particular dataIndex from this store.
9109 * @param {String} dataIndex The property to collect
9110 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9111 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9112 * @return {Array} An array of the unique values
9114 collect : function(dataIndex, allowNull, bypassFilter){
9115 var d = (bypassFilter === true && this.snapshot) ?
9116 this.snapshot.items : this.data.items;
9117 var v, sv, r = [], l = {};
9118 for(var i = 0, len = d.length; i < len; i++){
9119 v = d[i].data[dataIndex];
9121 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9130 * Revert to a view of the Record cache with no filtering applied.
9131 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9133 clearFilter : function(suppressEvent){
9134 if(this.snapshot && this.snapshot != this.data){
9135 this.data = this.snapshot;
9136 delete this.snapshot;
9137 if(suppressEvent !== true){
9138 this.fireEvent("datachanged", this);
9144 afterEdit : function(record){
9145 if(this.modified.indexOf(record) == -1){
9146 this.modified.push(record);
9148 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9152 afterReject : function(record){
9153 this.modified.remove(record);
9154 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9158 afterCommit : function(record){
9159 this.modified.remove(record);
9160 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9164 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9165 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9167 commitChanges : function(){
9168 var m = this.modified.slice(0);
9170 for(var i = 0, len = m.length; i < len; i++){
9176 * Cancel outstanding changes on all changed records.
9178 rejectChanges : function(){
9179 var m = this.modified.slice(0);
9181 for(var i = 0, len = m.length; i < len; i++){
9186 onMetaChange : function(meta, rtype, o){
9187 this.recordType = rtype;
9188 this.fields = rtype.prototype.fields;
9189 delete this.snapshot;
9190 this.sortInfo = meta.sortInfo || this.sortInfo;
9192 this.fireEvent('metachange', this, this.reader.meta);
9195 moveIndex : function(data, type)
9197 var index = this.indexOf(data);
9199 var newIndex = index + type;
9203 this.insert(newIndex, data);
9208 * Ext JS Library 1.1.1
9209 * Copyright(c) 2006-2007, Ext JS, LLC.
9211 * Originally Released Under LGPL - original licence link has changed is not relivant.
9214 * <script type="text/javascript">
9218 * @class Roo.data.SimpleStore
9219 * @extends Roo.data.Store
9220 * Small helper class to make creating Stores from Array data easier.
9221 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9222 * @cfg {Array} fields An array of field definition objects, or field name strings.
9223 * @cfg {Array} data The multi-dimensional array of data
9225 * @param {Object} config
9227 Roo.data.SimpleStore = function(config){
9228 Roo.data.SimpleStore.superclass.constructor.call(this, {
9230 reader: new Roo.data.ArrayReader({
9233 Roo.data.Record.create(config.fields)
9235 proxy : new Roo.data.MemoryProxy(config.data)
9239 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9241 * Ext JS Library 1.1.1
9242 * Copyright(c) 2006-2007, Ext JS, LLC.
9244 * Originally Released Under LGPL - original licence link has changed is not relivant.
9247 * <script type="text/javascript">
9252 * @extends Roo.data.Store
9253 * @class Roo.data.JsonStore
9254 * Small helper class to make creating Stores for JSON data easier. <br/>
9256 var store = new Roo.data.JsonStore({
9257 url: 'get-images.php',
9259 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9262 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9263 * JsonReader and HttpProxy (unless inline data is provided).</b>
9264 * @cfg {Array} fields An array of field definition objects, or field name strings.
9266 * @param {Object} config
9268 Roo.data.JsonStore = function(c){
9269 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9270 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9271 reader: new Roo.data.JsonReader(c, c.fields)
9274 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9276 * Ext JS Library 1.1.1
9277 * Copyright(c) 2006-2007, Ext JS, LLC.
9279 * Originally Released Under LGPL - original licence link has changed is not relivant.
9282 * <script type="text/javascript">
9286 Roo.data.Field = function(config){
9287 if(typeof config == "string"){
9288 config = {name: config};
9290 Roo.apply(this, config);
9296 var st = Roo.data.SortTypes;
9297 // named sortTypes are supported, here we look them up
9298 if(typeof this.sortType == "string"){
9299 this.sortType = st[this.sortType];
9302 // set default sortType for strings and dates
9306 this.sortType = st.asUCString;
9309 this.sortType = st.asDate;
9312 this.sortType = st.none;
9317 var stripRe = /[\$,%]/g;
9319 // prebuilt conversion function for this field, instead of
9320 // switching every time we're reading a value
9322 var cv, dateFormat = this.dateFormat;
9327 cv = function(v){ return v; };
9330 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9334 return v !== undefined && v !== null && v !== '' ?
9335 parseInt(String(v).replace(stripRe, ""), 10) : '';
9340 return v !== undefined && v !== null && v !== '' ?
9341 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9346 cv = function(v){ return v === true || v === "true" || v == 1; };
9353 if(v instanceof Date){
9357 if(dateFormat == "timestamp"){
9358 return new Date(v*1000);
9360 return Date.parseDate(v, dateFormat);
9362 var parsed = Date.parse(v);
9363 return parsed ? new Date(parsed) : null;
9372 Roo.data.Field.prototype = {
9380 * Ext JS Library 1.1.1
9381 * Copyright(c) 2006-2007, Ext JS, LLC.
9383 * Originally Released Under LGPL - original licence link has changed is not relivant.
9386 * <script type="text/javascript">
9389 // Base class for reading structured data from a data source. This class is intended to be
9390 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9393 * @class Roo.data.DataReader
9394 * Base class for reading structured data from a data source. This class is intended to be
9395 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9398 Roo.data.DataReader = function(meta, recordType){
9402 this.recordType = recordType instanceof Array ?
9403 Roo.data.Record.create(recordType) : recordType;
9406 Roo.data.DataReader.prototype = {
9408 * Create an empty record
9409 * @param {Object} data (optional) - overlay some values
9410 * @return {Roo.data.Record} record created.
9412 newRow : function(d) {
9414 this.recordType.prototype.fields.each(function(c) {
9416 case 'int' : da[c.name] = 0; break;
9417 case 'date' : da[c.name] = new Date(); break;
9418 case 'float' : da[c.name] = 0.0; break;
9419 case 'boolean' : da[c.name] = false; break;
9420 default : da[c.name] = ""; break;
9424 return new this.recordType(Roo.apply(da, d));
9429 * Ext JS Library 1.1.1
9430 * Copyright(c) 2006-2007, Ext JS, LLC.
9432 * Originally Released Under LGPL - original licence link has changed is not relivant.
9435 * <script type="text/javascript">
9439 * @class Roo.data.DataProxy
9440 * @extends Roo.data.Observable
9441 * This class is an abstract base class for implementations which provide retrieval of
9442 * unformatted data objects.<br>
9444 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9445 * (of the appropriate type which knows how to parse the data object) to provide a block of
9446 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9448 * Custom implementations must implement the load method as described in
9449 * {@link Roo.data.HttpProxy#load}.
9451 Roo.data.DataProxy = function(){
9455 * Fires before a network request is made to retrieve a data object.
9456 * @param {Object} This DataProxy object.
9457 * @param {Object} params The params parameter to the load function.
9462 * Fires before the load method's callback is called.
9463 * @param {Object} This DataProxy object.
9464 * @param {Object} o The data object.
9465 * @param {Object} arg The callback argument object passed to the load function.
9469 * @event loadexception
9470 * Fires if an Exception occurs during data retrieval.
9471 * @param {Object} This DataProxy object.
9472 * @param {Object} o The data object.
9473 * @param {Object} arg The callback argument object passed to the load function.
9474 * @param {Object} e The Exception.
9476 loadexception : true
9478 Roo.data.DataProxy.superclass.constructor.call(this);
9481 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9484 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9488 * Ext JS Library 1.1.1
9489 * Copyright(c) 2006-2007, Ext JS, LLC.
9491 * Originally Released Under LGPL - original licence link has changed is not relivant.
9494 * <script type="text/javascript">
9497 * @class Roo.data.MemoryProxy
9498 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9499 * to the Reader when its load method is called.
9501 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9503 Roo.data.MemoryProxy = function(data){
9507 Roo.data.MemoryProxy.superclass.constructor.call(this);
9511 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9513 * Load data from the requested source (in this case an in-memory
9514 * data object passed to the constructor), read the data object into
9515 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9516 * process that block using the passed callback.
9517 * @param {Object} params This parameter is not used by the MemoryProxy class.
9518 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9519 * object into a block of Roo.data.Records.
9520 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9521 * The function must be passed <ul>
9522 * <li>The Record block object</li>
9523 * <li>The "arg" argument from the load function</li>
9524 * <li>A boolean success indicator</li>
9526 * @param {Object} scope The scope in which to call the callback
9527 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9529 load : function(params, reader, callback, scope, arg){
9530 params = params || {};
9533 result = reader.readRecords(this.data);
9535 this.fireEvent("loadexception", this, arg, null, e);
9536 callback.call(scope, null, arg, false);
9539 callback.call(scope, result, arg, true);
9543 update : function(params, records){
9548 * Ext JS Library 1.1.1
9549 * Copyright(c) 2006-2007, Ext JS, LLC.
9551 * Originally Released Under LGPL - original licence link has changed is not relivant.
9554 * <script type="text/javascript">
9557 * @class Roo.data.HttpProxy
9558 * @extends Roo.data.DataProxy
9559 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9560 * configured to reference a certain URL.<br><br>
9562 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9563 * from which the running page was served.<br><br>
9565 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9567 * Be aware that to enable the browser to parse an XML document, the server must set
9568 * the Content-Type header in the HTTP response to "text/xml".
9570 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9571 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9572 * will be used to make the request.
9574 Roo.data.HttpProxy = function(conn){
9575 Roo.data.HttpProxy.superclass.constructor.call(this);
9576 // is conn a conn config or a real conn?
9578 this.useAjax = !conn || !conn.events;
9582 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9583 // thse are take from connection...
9586 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9589 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9590 * extra parameters to each request made by this object. (defaults to undefined)
9593 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9594 * to each request made by this object. (defaults to undefined)
9597 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
9600 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9603 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9609 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9613 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9614 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9615 * a finer-grained basis than the DataProxy events.
9617 getConnection : function(){
9618 return this.useAjax ? Roo.Ajax : this.conn;
9622 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9623 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9624 * process that block using the passed callback.
9625 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9626 * for the request to the remote server.
9627 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9628 * object into a block of Roo.data.Records.
9629 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9630 * The function must be passed <ul>
9631 * <li>The Record block object</li>
9632 * <li>The "arg" argument from the load function</li>
9633 * <li>A boolean success indicator</li>
9635 * @param {Object} scope The scope in which to call the callback
9636 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9638 load : function(params, reader, callback, scope, arg){
9639 if(this.fireEvent("beforeload", this, params) !== false){
9641 params : params || {},
9643 callback : callback,
9648 callback : this.loadResponse,
9652 Roo.applyIf(o, this.conn);
9653 if(this.activeRequest){
9654 Roo.Ajax.abort(this.activeRequest);
9656 this.activeRequest = Roo.Ajax.request(o);
9658 this.conn.request(o);
9661 callback.call(scope||this, null, arg, false);
9666 loadResponse : function(o, success, response){
9667 delete this.activeRequest;
9669 this.fireEvent("loadexception", this, o, response);
9670 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9675 result = o.reader.read(response);
9677 this.fireEvent("loadexception", this, o, response, e);
9678 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9682 this.fireEvent("load", this, o, o.request.arg);
9683 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9687 update : function(dataSet){
9692 updateResponse : function(dataSet){
9697 * Ext JS Library 1.1.1
9698 * Copyright(c) 2006-2007, Ext JS, LLC.
9700 * Originally Released Under LGPL - original licence link has changed is not relivant.
9703 * <script type="text/javascript">
9707 * @class Roo.data.ScriptTagProxy
9708 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9709 * other than the originating domain of the running page.<br><br>
9711 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
9712 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9714 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9715 * source code that is used as the source inside a <script> tag.<br><br>
9717 * In order for the browser to process the returned data, the server must wrap the data object
9718 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9719 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9720 * depending on whether the callback name was passed:
9723 boolean scriptTag = false;
9724 String cb = request.getParameter("callback");
9727 response.setContentType("text/javascript");
9729 response.setContentType("application/x-json");
9731 Writer out = response.getWriter();
9733 out.write(cb + "(");
9735 out.print(dataBlock.toJsonString());
9742 * @param {Object} config A configuration object.
9744 Roo.data.ScriptTagProxy = function(config){
9745 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9746 Roo.apply(this, config);
9747 this.head = document.getElementsByTagName("head")[0];
9750 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9752 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9754 * @cfg {String} url The URL from which to request the data object.
9757 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9761 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9762 * the server the name of the callback function set up by the load call to process the returned data object.
9763 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9764 * javascript output which calls this named function passing the data object as its only parameter.
9766 callbackParam : "callback",
9768 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9769 * name to the request.
9774 * Load data from the configured URL, read the data object into
9775 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9776 * process that block using the passed callback.
9777 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9778 * for the request to the remote server.
9779 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9780 * object into a block of Roo.data.Records.
9781 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9782 * The function must be passed <ul>
9783 * <li>The Record block object</li>
9784 * <li>The "arg" argument from the load function</li>
9785 * <li>A boolean success indicator</li>
9787 * @param {Object} scope The scope in which to call the callback
9788 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9790 load : function(params, reader, callback, scope, arg){
9791 if(this.fireEvent("beforeload", this, params) !== false){
9793 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9796 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9798 url += "&_dc=" + (new Date().getTime());
9800 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9803 cb : "stcCallback"+transId,
9804 scriptId : "stcScript"+transId,
9808 callback : callback,
9814 window[trans.cb] = function(o){
9815 conn.handleResponse(o, trans);
9818 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9820 if(this.autoAbort !== false){
9824 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9826 var script = document.createElement("script");
9827 script.setAttribute("src", url);
9828 script.setAttribute("type", "text/javascript");
9829 script.setAttribute("id", trans.scriptId);
9830 this.head.appendChild(script);
9834 callback.call(scope||this, null, arg, false);
9839 isLoading : function(){
9840 return this.trans ? true : false;
9844 * Abort the current server request.
9847 if(this.isLoading()){
9848 this.destroyTrans(this.trans);
9853 destroyTrans : function(trans, isLoaded){
9854 this.head.removeChild(document.getElementById(trans.scriptId));
9855 clearTimeout(trans.timeoutId);
9857 window[trans.cb] = undefined;
9859 delete window[trans.cb];
9862 // if hasn't been loaded, wait for load to remove it to prevent script error
9863 window[trans.cb] = function(){
9864 window[trans.cb] = undefined;
9866 delete window[trans.cb];
9873 handleResponse : function(o, trans){
9875 this.destroyTrans(trans, true);
9878 result = trans.reader.readRecords(o);
9880 this.fireEvent("loadexception", this, o, trans.arg, e);
9881 trans.callback.call(trans.scope||window, null, trans.arg, false);
9884 this.fireEvent("load", this, o, trans.arg);
9885 trans.callback.call(trans.scope||window, result, trans.arg, true);
9889 handleFailure : function(trans){
9891 this.destroyTrans(trans, false);
9892 this.fireEvent("loadexception", this, null, trans.arg);
9893 trans.callback.call(trans.scope||window, null, trans.arg, false);
9897 * Ext JS Library 1.1.1
9898 * Copyright(c) 2006-2007, Ext JS, LLC.
9900 * Originally Released Under LGPL - original licence link has changed is not relivant.
9903 * <script type="text/javascript">
9907 * @class Roo.data.JsonReader
9908 * @extends Roo.data.DataReader
9909 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9910 * based on mappings in a provided Roo.data.Record constructor.
9912 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9913 * in the reply previously.
9918 var RecordDef = Roo.data.Record.create([
9919 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9920 {name: 'occupation'} // This field will use "occupation" as the mapping.
9922 var myReader = new Roo.data.JsonReader({
9923 totalProperty: "results", // The property which contains the total dataset size (optional)
9924 root: "rows", // The property which contains an Array of row objects
9925 id: "id" // The property within each row object that provides an ID for the record (optional)
9929 * This would consume a JSON file like this:
9931 { 'results': 2, 'rows': [
9932 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9933 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9936 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9937 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9938 * paged from the remote server.
9939 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9940 * @cfg {String} root name of the property which contains the Array of row objects.
9941 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9943 * Create a new JsonReader
9944 * @param {Object} meta Metadata configuration options
9945 * @param {Object} recordType Either an Array of field definition objects,
9946 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9948 Roo.data.JsonReader = function(meta, recordType){
9951 // set some defaults:
9953 totalProperty: 'total',
9954 successProperty : 'success',
9959 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9961 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9964 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9965 * Used by Store query builder to append _requestMeta to params.
9968 metaFromRemote : false,
9970 * This method is only used by a DataProxy which has retrieved data from a remote server.
9971 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9972 * @return {Object} data A data block which is used by an Roo.data.Store object as
9973 * a cache of Roo.data.Records.
9975 read : function(response){
9976 var json = response.responseText;
9978 var o = /* eval:var:o */ eval("("+json+")");
9980 throw {message: "JsonReader.read: Json object not found"};
9986 this.metaFromRemote = true;
9987 this.meta = o.metaData;
9988 this.recordType = Roo.data.Record.create(o.metaData.fields);
9989 this.onMetaChange(this.meta, this.recordType, o);
9991 return this.readRecords(o);
9994 // private function a store will implement
9995 onMetaChange : function(meta, recordType, o){
10002 simpleAccess: function(obj, subsc) {
10009 getJsonAccessor: function(){
10011 return function(expr) {
10013 return(re.test(expr))
10014 ? new Function("obj", "return obj." + expr)
10019 return Roo.emptyFn;
10024 * Create a data block containing Roo.data.Records from an XML document.
10025 * @param {Object} o An object which contains an Array of row objects in the property specified
10026 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10027 * which contains the total size of the dataset.
10028 * @return {Object} data A data block which is used by an Roo.data.Store object as
10029 * a cache of Roo.data.Records.
10031 readRecords : function(o){
10033 * After any data loads, the raw JSON data is available for further custom processing.
10037 var s = this.meta, Record = this.recordType,
10038 f = Record.prototype.fields, fi = f.items, fl = f.length;
10040 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10042 if(s.totalProperty) {
10043 this.getTotal = this.getJsonAccessor(s.totalProperty);
10045 if(s.successProperty) {
10046 this.getSuccess = this.getJsonAccessor(s.successProperty);
10048 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10050 var g = this.getJsonAccessor(s.id);
10051 this.getId = function(rec) {
10053 return (r === undefined || r === "") ? null : r;
10056 this.getId = function(){return null;};
10059 for(var jj = 0; jj < fl; jj++){
10061 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10062 this.ef[jj] = this.getJsonAccessor(map);
10066 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10067 if(s.totalProperty){
10068 var vt = parseInt(this.getTotal(o), 10);
10073 if(s.successProperty){
10074 var vs = this.getSuccess(o);
10075 if(vs === false || vs === 'false'){
10080 for(var i = 0; i < c; i++){
10083 var id = this.getId(n);
10084 for(var j = 0; j < fl; j++){
10086 var v = this.ef[j](n);
10088 Roo.log('missing convert for ' + f.name);
10092 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10094 var record = new Record(values, id);
10096 records[i] = record;
10102 totalRecords : totalRecords
10107 * Ext JS Library 1.1.1
10108 * Copyright(c) 2006-2007, Ext JS, LLC.
10110 * Originally Released Under LGPL - original licence link has changed is not relivant.
10113 * <script type="text/javascript">
10117 * @class Roo.data.ArrayReader
10118 * @extends Roo.data.DataReader
10119 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10120 * Each element of that Array represents a row of data fields. The
10121 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10122 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10126 var RecordDef = Roo.data.Record.create([
10127 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10128 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10130 var myReader = new Roo.data.ArrayReader({
10131 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10135 * This would consume an Array like this:
10137 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10139 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10141 * Create a new JsonReader
10142 * @param {Object} meta Metadata configuration options.
10143 * @param {Object} recordType Either an Array of field definition objects
10144 * as specified to {@link Roo.data.Record#create},
10145 * or an {@link Roo.data.Record} object
10146 * created using {@link Roo.data.Record#create}.
10148 Roo.data.ArrayReader = function(meta, recordType){
10149 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10152 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10154 * Create a data block containing Roo.data.Records from an XML document.
10155 * @param {Object} o An Array of row objects which represents the dataset.
10156 * @return {Object} data A data block which is used by an Roo.data.Store object as
10157 * a cache of Roo.data.Records.
10159 readRecords : function(o){
10160 var sid = this.meta ? this.meta.id : null;
10161 var recordType = this.recordType, fields = recordType.prototype.fields;
10164 for(var i = 0; i < root.length; i++){
10167 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10168 for(var j = 0, jlen = fields.length; j < jlen; j++){
10169 var f = fields.items[j];
10170 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10171 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10173 values[f.name] = v;
10175 var record = new recordType(values, id);
10177 records[records.length] = record;
10181 totalRecords : records.length
10190 * @class Roo.bootstrap.ComboBox
10191 * @extends Roo.bootstrap.TriggerField
10192 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10193 * @cfg {Boolean} append (true|false) default false
10194 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10195 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10196 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10197 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10198 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10200 * Create a new ComboBox.
10201 * @param {Object} config Configuration options
10203 Roo.bootstrap.ComboBox = function(config){
10204 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10208 * Fires when the dropdown list is expanded
10209 * @param {Roo.bootstrap.ComboBox} combo This combo box
10214 * Fires when the dropdown list is collapsed
10215 * @param {Roo.bootstrap.ComboBox} combo This combo box
10219 * @event beforeselect
10220 * Fires before a list item is selected. Return false to cancel the selection.
10221 * @param {Roo.bootstrap.ComboBox} combo This combo box
10222 * @param {Roo.data.Record} record The data record returned from the underlying store
10223 * @param {Number} index The index of the selected item in the dropdown list
10225 'beforeselect' : true,
10228 * Fires when a list item is selected
10229 * @param {Roo.bootstrap.ComboBox} combo This combo box
10230 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10231 * @param {Number} index The index of the selected item in the dropdown list
10235 * @event beforequery
10236 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10237 * The event object passed has these properties:
10238 * @param {Roo.bootstrap.ComboBox} combo This combo box
10239 * @param {String} query The query
10240 * @param {Boolean} forceAll true to force "all" query
10241 * @param {Boolean} cancel true to cancel the query
10242 * @param {Object} e The query event object
10244 'beforequery': true,
10247 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10248 * @param {Roo.bootstrap.ComboBox} combo This combo box
10253 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10254 * @param {Roo.bootstrap.ComboBox} combo This combo box
10255 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10260 * Fires when the remove value from the combobox array
10261 * @param {Roo.bootstrap.ComboBox} combo This combo box
10268 this.tickItems = [];
10270 this.selectedIndex = -1;
10271 if(this.mode == 'local'){
10272 if(config.queryDelay === undefined){
10273 this.queryDelay = 10;
10275 if(config.minChars === undefined){
10281 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10284 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10285 * rendering into an Roo.Editor, defaults to false)
10288 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10289 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10292 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10295 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10296 * the dropdown list (defaults to undefined, with no header element)
10300 * @cfg {String/Roo.Template} tpl The template to use to render the output
10304 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10306 listWidth: undefined,
10308 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10309 * mode = 'remote' or 'text' if mode = 'local')
10311 displayField: undefined,
10313 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10314 * mode = 'remote' or 'value' if mode = 'local').
10315 * Note: use of a valueField requires the user make a selection
10316 * in order for a value to be mapped.
10318 valueField: undefined,
10322 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10323 * field's data value (defaults to the underlying DOM element's name)
10325 hiddenName: undefined,
10327 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10331 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10333 selectedClass: 'active',
10336 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10340 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10341 * anchor positions (defaults to 'tl-bl')
10343 listAlign: 'tl-bl?',
10345 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10349 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10350 * query specified by the allQuery config option (defaults to 'query')
10352 triggerAction: 'query',
10354 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10355 * (defaults to 4, does not apply if editable = false)
10359 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10360 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10364 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10365 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10369 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10370 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10374 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10375 * when editable = true (defaults to false)
10377 selectOnFocus:false,
10379 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10381 queryParam: 'query',
10383 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10384 * when mode = 'remote' (defaults to 'Loading...')
10386 loadingText: 'Loading...',
10388 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10392 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10396 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10397 * traditional select (defaults to true)
10401 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10405 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10409 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10410 * listWidth has a higher value)
10414 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10415 * allow the user to set arbitrary text into the field (defaults to false)
10417 forceSelection:false,
10419 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10420 * if typeAhead = true (defaults to 250)
10422 typeAheadDelay : 250,
10424 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10425 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10427 valueNotFoundText : undefined,
10429 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10431 blockFocus : false,
10434 * @cfg {Boolean} disableClear Disable showing of clear button.
10436 disableClear : false,
10438 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10440 alwaysQuery : false,
10443 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10457 btnPosition : 'right',
10458 triggerList : true,
10459 showToggleBtn : true,
10460 // element that contains real text value.. (when hidden is used..)
10462 getAutoCreate : function()
10469 if(!this.tickable){
10470 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10475 * ComboBox with tickable selections
10478 var align = this.labelAlign || this.parentLabelAlign();
10481 cls : 'form-group roo-combobox-tickable' //input-group
10487 cls : 'tickable-buttons',
10492 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10499 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10506 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10513 Roo.each(buttons.cn, function(c){
10515 c.cls += ' btn-' + _this.size;
10518 if (_this.disabled) {
10529 cls: 'form-hidden-field'
10533 cls: 'select2-choices',
10537 cls: 'select2-search-field',
10549 cls: 'select2-container input-group select2-container-multi',
10554 // cls: 'typeahead typeahead-long dropdown-menu',
10555 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10560 if (align ==='left' && this.fieldLabel.length) {
10562 Roo.log("left and has label");
10568 cls : 'control-label col-sm-' + this.labelWidth,
10569 html : this.fieldLabel
10573 cls : "col-sm-" + (12 - this.labelWidth),
10580 } else if ( this.fieldLabel.length) {
10586 //cls : 'input-group-addon',
10587 html : this.fieldLabel
10597 Roo.log(" no label && no align");
10604 ['xs','sm','md','lg'].map(function(size){
10605 if (settings[size]) {
10606 cfg.cls += ' col-' + size + '-' + settings[size];
10615 initEvents: function()
10619 throw "can not find store for combo";
10621 this.store = Roo.factory(this.store, Roo.data);
10624 this.initTickableEvents();
10628 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10630 if(this.hiddenName){
10632 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10634 this.hiddenField.dom.value =
10635 this.hiddenValue !== undefined ? this.hiddenValue :
10636 this.value !== undefined ? this.value : '';
10638 // prevent input submission
10639 this.el.dom.removeAttribute('name');
10640 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10645 // this.el.dom.setAttribute('autocomplete', 'off');
10648 var cls = 'x-combo-list';
10650 //this.list = new Roo.Layer({
10651 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10657 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10658 _this.list.setWidth(lw);
10661 this.list.on('mouseover', this.onViewOver, this);
10662 this.list.on('mousemove', this.onViewMove, this);
10664 this.list.on('scroll', this.onViewScroll, this);
10667 this.list.swallowEvent('mousewheel');
10668 this.assetHeight = 0;
10671 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10672 this.assetHeight += this.header.getHeight();
10675 this.innerList = this.list.createChild({cls:cls+'-inner'});
10676 this.innerList.on('mouseover', this.onViewOver, this);
10677 this.innerList.on('mousemove', this.onViewMove, this);
10678 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10680 if(this.allowBlank && !this.pageSize && !this.disableClear){
10681 this.footer = this.list.createChild({cls:cls+'-ft'});
10682 this.pageTb = new Roo.Toolbar(this.footer);
10686 this.footer = this.list.createChild({cls:cls+'-ft'});
10687 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10688 {pageSize: this.pageSize});
10692 if (this.pageTb && this.allowBlank && !this.disableClear) {
10694 this.pageTb.add(new Roo.Toolbar.Fill(), {
10695 cls: 'x-btn-icon x-btn-clear',
10697 handler: function()
10700 _this.clearValue();
10701 _this.onSelect(false, -1);
10706 this.assetHeight += this.footer.getHeight();
10711 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10714 this.view = new Roo.View(this.list, this.tpl, {
10715 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10717 //this.view.wrapEl.setDisplayed(false);
10718 this.view.on('click', this.onViewClick, this);
10722 this.store.on('beforeload', this.onBeforeLoad, this);
10723 this.store.on('load', this.onLoad, this);
10724 this.store.on('loadexception', this.onLoadException, this);
10726 if(this.resizable){
10727 this.resizer = new Roo.Resizable(this.list, {
10728 pinned:true, handles:'se'
10730 this.resizer.on('resize', function(r, w, h){
10731 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10732 this.listWidth = w;
10733 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10734 this.restrictHeight();
10736 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10739 if(!this.editable){
10740 this.editable = true;
10741 this.setEditable(false);
10746 if (typeof(this.events.add.listeners) != 'undefined') {
10748 this.addicon = this.wrap.createChild(
10749 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10751 this.addicon.on('click', function(e) {
10752 this.fireEvent('add', this);
10755 if (typeof(this.events.edit.listeners) != 'undefined') {
10757 this.editicon = this.wrap.createChild(
10758 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10759 if (this.addicon) {
10760 this.editicon.setStyle('margin-left', '40px');
10762 this.editicon.on('click', function(e) {
10764 // we fire even if inothing is selected..
10765 this.fireEvent('edit', this, this.lastData );
10771 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10772 "up" : function(e){
10773 this.inKeyMode = true;
10777 "down" : function(e){
10778 if(!this.isExpanded()){
10779 this.onTriggerClick();
10781 this.inKeyMode = true;
10786 "enter" : function(e){
10787 // this.onViewClick();
10791 if(this.fireEvent("specialkey", this, e)){
10792 this.onViewClick(false);
10798 "esc" : function(e){
10802 "tab" : function(e){
10805 if(this.fireEvent("specialkey", this, e)){
10806 this.onViewClick(false);
10814 doRelay : function(foo, bar, hname){
10815 if(hname == 'down' || this.scope.isExpanded()){
10816 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10825 this.queryDelay = Math.max(this.queryDelay || 10,
10826 this.mode == 'local' ? 10 : 250);
10829 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10831 if(this.typeAhead){
10832 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10834 if(this.editable !== false){
10835 this.inputEl().on("keyup", this.onKeyUp, this);
10837 if(this.forceSelection){
10838 this.inputEl().on('blur', this.doForce, this);
10842 this.choices = this.el.select('ul.select2-choices', true).first();
10843 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10847 initTickableEvents: function()
10851 if(this.hiddenName){
10853 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10855 this.hiddenField.dom.value =
10856 this.hiddenValue !== undefined ? this.hiddenValue :
10857 this.value !== undefined ? this.value : '';
10859 // prevent input submission
10860 this.el.dom.removeAttribute('name');
10861 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10866 // this.list = this.el.select('ul.dropdown-menu',true).first();
10868 this.choices = this.el.select('ul.select2-choices', true).first();
10869 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10870 if(this.triggerList){
10871 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10874 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10875 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10877 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10878 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10880 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10881 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10883 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10884 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10885 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10888 this.cancelBtn.hide();
10893 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10894 _this.list.setWidth(lw);
10897 this.list.on('mouseover', this.onViewOver, this);
10898 this.list.on('mousemove', this.onViewMove, this);
10900 this.list.on('scroll', this.onViewScroll, this);
10903 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
10906 this.view = new Roo.View(this.list, this.tpl, {
10907 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10910 //this.view.wrapEl.setDisplayed(false);
10911 this.view.on('click', this.onViewClick, this);
10915 this.store.on('beforeload', this.onBeforeLoad, this);
10916 this.store.on('load', this.onLoad, this);
10917 this.store.on('loadexception', this.onLoadException, this);
10919 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10920 // "up" : function(e){
10921 // this.inKeyMode = true;
10922 // this.selectPrev();
10925 // "down" : function(e){
10926 // if(!this.isExpanded()){
10927 // this.onTriggerClick();
10929 // this.inKeyMode = true;
10930 // this.selectNext();
10934 // "enter" : function(e){
10935 //// this.onViewClick();
10937 // this.collapse();
10939 // if(this.fireEvent("specialkey", this, e)){
10940 // this.onViewClick(false);
10946 // "esc" : function(e){
10947 // this.collapse();
10950 // "tab" : function(e){
10951 // this.collapse();
10953 // if(this.fireEvent("specialkey", this, e)){
10954 // this.onViewClick(false);
10962 // doRelay : function(foo, bar, hname){
10963 // if(hname == 'down' || this.scope.isExpanded()){
10964 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10969 // forceKeyDown: true
10973 this.queryDelay = Math.max(this.queryDelay || 10,
10974 this.mode == 'local' ? 10 : 250);
10977 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10979 if(this.typeAhead){
10980 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10984 onDestroy : function(){
10986 this.view.setStore(null);
10987 this.view.el.removeAllListeners();
10988 this.view.el.remove();
10989 this.view.purgeListeners();
10992 this.list.dom.innerHTML = '';
10996 this.store.un('beforeload', this.onBeforeLoad, this);
10997 this.store.un('load', this.onLoad, this);
10998 this.store.un('loadexception', this.onLoadException, this);
11000 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11004 fireKey : function(e){
11005 if(e.isNavKeyPress() && !this.list.isVisible()){
11006 this.fireEvent("specialkey", this, e);
11011 onResize: function(w, h){
11012 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11014 // if(typeof w != 'number'){
11015 // // we do not handle it!?!?
11018 // var tw = this.trigger.getWidth();
11019 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11020 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11022 // this.inputEl().setWidth( this.adjustWidth('input', x));
11024 // //this.trigger.setStyle('left', x+'px');
11026 // if(this.list && this.listWidth === undefined){
11027 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11028 // this.list.setWidth(lw);
11029 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11037 * Allow or prevent the user from directly editing the field text. If false is passed,
11038 * the user will only be able to select from the items defined in the dropdown list. This method
11039 * is the runtime equivalent of setting the 'editable' config option at config time.
11040 * @param {Boolean} value True to allow the user to directly edit the field text
11042 setEditable : function(value){
11043 if(value == this.editable){
11046 this.editable = value;
11048 this.inputEl().dom.setAttribute('readOnly', true);
11049 this.inputEl().on('mousedown', this.onTriggerClick, this);
11050 this.inputEl().addClass('x-combo-noedit');
11052 this.inputEl().dom.setAttribute('readOnly', false);
11053 this.inputEl().un('mousedown', this.onTriggerClick, this);
11054 this.inputEl().removeClass('x-combo-noedit');
11060 onBeforeLoad : function(combo,opts){
11061 if(!this.hasFocus){
11065 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11067 // this.restrictHeight();
11068 this.selectedIndex = -1;
11072 onLoad : function(){
11074 this.hasQuery = false;
11076 if(!this.hasFocus){
11080 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11081 this.loading.hide();
11084 if(this.store.getCount() > 0){
11086 // this.restrictHeight();
11087 if(this.lastQuery == this.allQuery){
11088 if(this.editable && !this.tickable){
11089 this.inputEl().dom.select();
11093 !this.selectByValue(this.value, true) &&
11094 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11095 this.store.lastOptions.add != true)
11097 this.select(0, true);
11100 if(this.autoFocus){
11103 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11104 this.taTask.delay(this.typeAheadDelay);
11108 this.onEmptyResults();
11114 onLoadException : function()
11116 this.hasQuery = false;
11118 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11119 this.loading.hide();
11123 Roo.log(this.store.reader.jsonData);
11124 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11126 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11132 onTypeAhead : function(){
11133 if(this.store.getCount() > 0){
11134 var r = this.store.getAt(0);
11135 var newValue = r.data[this.displayField];
11136 var len = newValue.length;
11137 var selStart = this.getRawValue().length;
11139 if(selStart != len){
11140 this.setRawValue(newValue);
11141 this.selectText(selStart, newValue.length);
11147 onSelect : function(record, index){
11149 if(this.fireEvent('beforeselect', this, record, index) !== false){
11151 this.setFromData(index > -1 ? record.data : false);
11154 this.fireEvent('select', this, record, index);
11159 * Returns the currently selected field value or empty string if no value is set.
11160 * @return {String} value The selected value
11162 getValue : function(){
11165 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11168 if(this.valueField){
11169 return typeof this.value != 'undefined' ? this.value : '';
11171 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11176 * Clears any text/value currently set in the field
11178 clearValue : function(){
11179 if(this.hiddenField){
11180 this.hiddenField.dom.value = '';
11183 this.setRawValue('');
11184 this.lastSelectionText = '';
11189 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11190 * will be displayed in the field. If the value does not match the data value of an existing item,
11191 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11192 * Otherwise the field will be blank (although the value will still be set).
11193 * @param {String} value The value to match
11195 setValue : function(v){
11202 if(this.valueField){
11203 var r = this.findRecord(this.valueField, v);
11205 text = r.data[this.displayField];
11206 }else if(this.valueNotFoundText !== undefined){
11207 text = this.valueNotFoundText;
11210 this.lastSelectionText = text;
11211 if(this.hiddenField){
11212 this.hiddenField.dom.value = v;
11214 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11218 * @property {Object} the last set data for the element
11223 * Sets the value of the field based on a object which is related to the record format for the store.
11224 * @param {Object} value the value to set as. or false on reset?
11226 setFromData : function(o){
11229 if(typeof o.display_name !== 'string'){
11230 for(var i=0;i<o.display_name.length;i++){
11231 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11239 var dv = ''; // display value
11240 var vv = ''; // value value..
11242 if (this.displayField) {
11243 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11245 // this is an error condition!!!
11246 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11249 if(this.valueField){
11250 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11253 if(this.hiddenField){
11254 this.hiddenField.dom.value = vv;
11256 this.lastSelectionText = dv;
11257 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11261 // no hidden field.. - we store the value in 'value', but still display
11262 // display field!!!!
11263 this.lastSelectionText = dv;
11264 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11270 reset : function(){
11271 // overridden so that last data is reset..
11272 this.setValue(this.originalValue);
11273 this.clearInvalid();
11274 this.lastData = false;
11276 this.view.clearSelections();
11280 findRecord : function(prop, value){
11282 if(this.store.getCount() > 0){
11283 this.store.each(function(r){
11284 if(r.data[prop] == value){
11294 getName: function()
11296 // returns hidden if it's set..
11297 if (!this.rendered) {return ''};
11298 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11302 onViewMove : function(e, t){
11303 this.inKeyMode = false;
11307 onViewOver : function(e, t){
11308 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11311 var item = this.view.findItemFromChild(t);
11314 var index = this.view.indexOf(item);
11315 this.select(index, false);
11320 onViewClick : function(view, doFocus, el, e)
11322 var index = this.view.getSelectedIndexes()[0];
11324 var r = this.store.getAt(index);
11328 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11335 Roo.each(this.tickItems, function(v,k){
11337 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11338 _this.tickItems.splice(k, 1);
11348 this.tickItems.push(r.data);
11353 this.onSelect(r, index);
11355 if(doFocus !== false && !this.blockFocus){
11356 this.inputEl().focus();
11361 restrictHeight : function(){
11362 //this.innerList.dom.style.height = '';
11363 //var inner = this.innerList.dom;
11364 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11365 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11366 //this.list.beginUpdate();
11367 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11368 this.list.alignTo(this.inputEl(), this.listAlign);
11369 this.list.alignTo(this.inputEl(), this.listAlign);
11370 //this.list.endUpdate();
11374 onEmptyResults : function(){
11379 * Returns true if the dropdown list is expanded, else false.
11381 isExpanded : function(){
11382 return this.list.isVisible();
11386 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11387 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11388 * @param {String} value The data value of the item to select
11389 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11390 * selected item if it is not currently in view (defaults to true)
11391 * @return {Boolean} True if the value matched an item in the list, else false
11393 selectByValue : function(v, scrollIntoView){
11394 if(v !== undefined && v !== null){
11395 var r = this.findRecord(this.valueField || this.displayField, v);
11397 this.select(this.store.indexOf(r), scrollIntoView);
11405 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11406 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11407 * @param {Number} index The zero-based index of the list item to select
11408 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11409 * selected item if it is not currently in view (defaults to true)
11411 select : function(index, scrollIntoView){
11412 this.selectedIndex = index;
11413 this.view.select(index);
11414 if(scrollIntoView !== false){
11415 var el = this.view.getNode(index);
11416 if(el && !this.multiple && !this.tickable){
11417 this.list.scrollChildIntoView(el, false);
11423 selectNext : function(){
11424 var ct = this.store.getCount();
11426 if(this.selectedIndex == -1){
11428 }else if(this.selectedIndex < ct-1){
11429 this.select(this.selectedIndex+1);
11435 selectPrev : function(){
11436 var ct = this.store.getCount();
11438 if(this.selectedIndex == -1){
11440 }else if(this.selectedIndex != 0){
11441 this.select(this.selectedIndex-1);
11447 onKeyUp : function(e){
11448 if(this.editable !== false && !e.isSpecialKey()){
11449 this.lastKey = e.getKey();
11450 this.dqTask.delay(this.queryDelay);
11455 validateBlur : function(){
11456 return !this.list || !this.list.isVisible();
11460 initQuery : function(){
11461 this.doQuery(this.getRawValue());
11465 doForce : function(){
11466 if(this.inputEl().dom.value.length > 0){
11467 this.inputEl().dom.value =
11468 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11474 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11475 * query allowing the query action to be canceled if needed.
11476 * @param {String} query The SQL query to execute
11477 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11478 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11479 * saved in the current store (defaults to false)
11481 doQuery : function(q, forceAll){
11483 if(q === undefined || q === null){
11488 forceAll: forceAll,
11492 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11497 forceAll = qe.forceAll;
11498 if(forceAll === true || (q.length >= this.minChars)){
11500 this.hasQuery = true;
11502 if(this.lastQuery != q || this.alwaysQuery){
11503 this.lastQuery = q;
11504 if(this.mode == 'local'){
11505 this.selectedIndex = -1;
11507 this.store.clearFilter();
11509 this.store.filter(this.displayField, q);
11513 this.store.baseParams[this.queryParam] = q;
11515 var options = {params : this.getParams(q)};
11518 options.add = true;
11519 options.params.start = this.page * this.pageSize;
11522 this.store.load(options);
11524 * this code will make the page width larger, at the beginning, the list not align correctly,
11525 * we should expand the list on onLoad
11526 * so command out it
11531 this.selectedIndex = -1;
11536 this.loadNext = false;
11540 getParams : function(q){
11542 //p[this.queryParam] = q;
11546 p.limit = this.pageSize;
11552 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11554 collapse : function(){
11555 if(!this.isExpanded()){
11563 this.cancelBtn.hide();
11564 this.trigger.show();
11567 Roo.get(document).un('mousedown', this.collapseIf, this);
11568 Roo.get(document).un('mousewheel', this.collapseIf, this);
11569 if (!this.editable) {
11570 Roo.get(document).un('keydown', this.listKeyPress, this);
11572 this.fireEvent('collapse', this);
11576 collapseIf : function(e){
11577 var in_combo = e.within(this.el);
11578 var in_list = e.within(this.list);
11579 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11581 if (in_combo || in_list || is_list) {
11582 //e.stopPropagation();
11587 this.onTickableFooterButtonClick(e, false, false);
11595 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11597 expand : function(){
11599 if(this.isExpanded() || !this.hasFocus){
11603 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11604 this.list.setWidth(lw);
11609 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11610 this.list.setWidth(lw);
11614 this.restrictHeight();
11618 this.tickItems = Roo.apply([], this.item);
11621 this.cancelBtn.show();
11622 this.trigger.hide();
11626 Roo.get(document).on('mousedown', this.collapseIf, this);
11627 Roo.get(document).on('mousewheel', this.collapseIf, this);
11628 if (!this.editable) {
11629 Roo.get(document).on('keydown', this.listKeyPress, this);
11632 this.fireEvent('expand', this);
11636 // Implements the default empty TriggerField.onTriggerClick function
11637 onTriggerClick : function(e)
11639 Roo.log('trigger click');
11641 if(this.disabled || !this.triggerList){
11646 this.loadNext = false;
11648 if(this.isExpanded()){
11650 if (!this.blockFocus) {
11651 this.inputEl().focus();
11655 this.hasFocus = true;
11656 if(this.triggerAction == 'all') {
11657 this.doQuery(this.allQuery, true);
11659 this.doQuery(this.getRawValue());
11661 if (!this.blockFocus) {
11662 this.inputEl().focus();
11667 onTickableTriggerClick : function(e)
11674 this.loadNext = false;
11675 this.hasFocus = true;
11677 if(this.triggerAction == 'all') {
11678 this.doQuery(this.allQuery, true);
11680 this.doQuery(this.getRawValue());
11684 onSearchFieldClick : function(e)
11686 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11691 this.loadNext = false;
11692 this.hasFocus = true;
11694 if(this.triggerAction == 'all') {
11695 this.doQuery(this.allQuery, true);
11697 this.doQuery(this.getRawValue());
11701 listKeyPress : function(e)
11703 //Roo.log('listkeypress');
11704 // scroll to first matching element based on key pres..
11705 if (e.isSpecialKey()) {
11708 var k = String.fromCharCode(e.getKey()).toUpperCase();
11711 var csel = this.view.getSelectedNodes();
11712 var cselitem = false;
11714 var ix = this.view.indexOf(csel[0]);
11715 cselitem = this.store.getAt(ix);
11716 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11722 this.store.each(function(v) {
11724 // start at existing selection.
11725 if (cselitem.id == v.id) {
11731 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11732 match = this.store.indexOf(v);
11738 if (match === false) {
11739 return true; // no more action?
11742 this.view.select(match);
11743 var sn = Roo.get(this.view.getSelectedNodes()[0])
11744 //sn.scrollIntoView(sn.dom.parentNode, false);
11747 onViewScroll : function(e, t){
11749 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11753 this.hasQuery = true;
11755 this.loading = this.list.select('.loading', true).first();
11757 if(this.loading === null){
11758 this.list.createChild({
11760 cls: 'loading select2-more-results select2-active',
11761 html: 'Loading more results...'
11764 this.loading = this.list.select('.loading', true).first();
11766 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11768 this.loading.hide();
11771 this.loading.show();
11776 this.loadNext = true;
11778 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11783 addItem : function(o)
11785 var dv = ''; // display value
11787 if (this.displayField) {
11788 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11790 // this is an error condition!!!
11791 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11798 var choice = this.choices.createChild({
11800 cls: 'select2-search-choice',
11809 cls: 'select2-search-choice-close',
11814 }, this.searchField);
11816 var close = choice.select('a.select2-search-choice-close', true).first()
11818 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11826 this.inputEl().dom.value = '';
11830 onRemoveItem : function(e, _self, o)
11832 e.preventDefault();
11833 var index = this.item.indexOf(o.data) * 1;
11836 Roo.log('not this item?!');
11840 this.item.splice(index, 1);
11845 this.fireEvent('remove', this, e);
11849 syncValue : function()
11851 if(!this.item.length){
11858 Roo.each(this.item, function(i){
11859 if(_this.valueField){
11860 value.push(i[_this.valueField]);
11867 this.value = value.join(',');
11869 if(this.hiddenField){
11870 this.hiddenField.dom.value = this.value;
11874 clearItem : function()
11876 if(!this.multiple){
11882 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11889 inputEl: function ()
11892 return this.searchField;
11894 return this.el.select('input.form-control',true).first();
11898 onTickableFooterButtonClick : function(e, btn, el)
11900 e.preventDefault();
11902 if(btn && btn.name == 'cancel'){
11903 this.tickItems = Roo.apply([], this.item);
11912 Roo.each(this.tickItems, function(o){
11923 * @cfg {Boolean} grow
11927 * @cfg {Number} growMin
11931 * @cfg {Number} growMax
11941 * Ext JS Library 1.1.1
11942 * Copyright(c) 2006-2007, Ext JS, LLC.
11944 * Originally Released Under LGPL - original licence link has changed is not relivant.
11947 * <script type="text/javascript">
11952 * @extends Roo.util.Observable
11953 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11954 * This class also supports single and multi selection modes. <br>
11955 * Create a data model bound view:
11957 var store = new Roo.data.Store(...);
11959 var view = new Roo.View({
11961 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11963 singleSelect: true,
11964 selectedClass: "ydataview-selected",
11968 // listen for node click?
11969 view.on("click", function(vw, index, node, e){
11970 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11974 dataModel.load("foobar.xml");
11976 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11978 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11979 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11981 * Note: old style constructor is still suported (container, template, config)
11984 * Create a new View
11985 * @param {Object} config The config object
11988 Roo.View = function(config, depreciated_tpl, depreciated_config){
11990 this.parent = false;
11992 if (typeof(depreciated_tpl) == 'undefined') {
11993 // new way.. - universal constructor.
11994 Roo.apply(this, config);
11995 this.el = Roo.get(this.el);
11998 this.el = Roo.get(config);
11999 this.tpl = depreciated_tpl;
12000 Roo.apply(this, depreciated_config);
12002 this.wrapEl = this.el.wrap().wrap();
12003 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12006 if(typeof(this.tpl) == "string"){
12007 this.tpl = new Roo.Template(this.tpl);
12009 // support xtype ctors..
12010 this.tpl = new Roo.factory(this.tpl, Roo);
12014 this.tpl.compile();
12019 * @event beforeclick
12020 * Fires before a click is processed. Returns false to cancel the default action.
12021 * @param {Roo.View} this
12022 * @param {Number} index The index of the target node
12023 * @param {HTMLElement} node The target node
12024 * @param {Roo.EventObject} e The raw event object
12026 "beforeclick" : true,
12029 * Fires when a template node is clicked.
12030 * @param {Roo.View} this
12031 * @param {Number} index The index of the target node
12032 * @param {HTMLElement} node The target node
12033 * @param {Roo.EventObject} e The raw event object
12038 * Fires when a template node is double clicked.
12039 * @param {Roo.View} this
12040 * @param {Number} index The index of the target node
12041 * @param {HTMLElement} node The target node
12042 * @param {Roo.EventObject} e The raw event object
12046 * @event contextmenu
12047 * Fires when a template node is right clicked.
12048 * @param {Roo.View} this
12049 * @param {Number} index The index of the target node
12050 * @param {HTMLElement} node The target node
12051 * @param {Roo.EventObject} e The raw event object
12053 "contextmenu" : true,
12055 * @event selectionchange
12056 * Fires when the selected nodes change.
12057 * @param {Roo.View} this
12058 * @param {Array} selections Array of the selected nodes
12060 "selectionchange" : true,
12063 * @event beforeselect
12064 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12065 * @param {Roo.View} this
12066 * @param {HTMLElement} node The node to be selected
12067 * @param {Array} selections Array of currently selected nodes
12069 "beforeselect" : true,
12071 * @event preparedata
12072 * Fires on every row to render, to allow you to change the data.
12073 * @param {Roo.View} this
12074 * @param {Object} data to be rendered (change this)
12076 "preparedata" : true
12084 "click": this.onClick,
12085 "dblclick": this.onDblClick,
12086 "contextmenu": this.onContextMenu,
12090 this.selections = [];
12092 this.cmp = new Roo.CompositeElementLite([]);
12094 this.store = Roo.factory(this.store, Roo.data);
12095 this.setStore(this.store, true);
12098 if ( this.footer && this.footer.xtype) {
12100 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12102 this.footer.dataSource = this.store
12103 this.footer.container = fctr;
12104 this.footer = Roo.factory(this.footer, Roo);
12105 fctr.insertFirst(this.el);
12107 // this is a bit insane - as the paging toolbar seems to detach the el..
12108 // dom.parentNode.parentNode.parentNode
12109 // they get detached?
12113 Roo.View.superclass.constructor.call(this);
12118 Roo.extend(Roo.View, Roo.util.Observable, {
12121 * @cfg {Roo.data.Store} store Data store to load data from.
12126 * @cfg {String|Roo.Element} el The container element.
12131 * @cfg {String|Roo.Template} tpl The template used by this View
12135 * @cfg {String} dataName the named area of the template to use as the data area
12136 * Works with domtemplates roo-name="name"
12140 * @cfg {String} selectedClass The css class to add to selected nodes
12142 selectedClass : "x-view-selected",
12144 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12149 * @cfg {String} text to display on mask (default Loading)
12153 * @cfg {Boolean} multiSelect Allow multiple selection
12155 multiSelect : false,
12157 * @cfg {Boolean} singleSelect Allow single selection
12159 singleSelect: false,
12162 * @cfg {Boolean} toggleSelect - selecting
12164 toggleSelect : false,
12167 * @cfg {Boolean} tickable - selecting
12172 * Returns the element this view is bound to.
12173 * @return {Roo.Element}
12175 getEl : function(){
12176 return this.wrapEl;
12182 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12184 refresh : function(){
12185 Roo.log('refresh');
12188 // if we are using something like 'domtemplate', then
12189 // the what gets used is:
12190 // t.applySubtemplate(NAME, data, wrapping data..)
12191 // the outer template then get' applied with
12192 // the store 'extra data'
12193 // and the body get's added to the
12194 // roo-name="data" node?
12195 // <span class='roo-tpl-{name}'></span> ?????
12199 this.clearSelections();
12200 this.el.update("");
12202 var records = this.store.getRange();
12203 if(records.length < 1) {
12205 // is this valid?? = should it render a template??
12207 this.el.update(this.emptyText);
12211 if (this.dataName) {
12212 this.el.update(t.apply(this.store.meta)); //????
12213 el = this.el.child('.roo-tpl-' + this.dataName);
12216 for(var i = 0, len = records.length; i < len; i++){
12217 var data = this.prepareData(records[i].data, i, records[i]);
12218 this.fireEvent("preparedata", this, data, i, records[i]);
12220 var d = Roo.apply({}, data);
12223 Roo.apply(d, {'roo-id' : Roo.id()});
12227 Roo.each(this.parent.item, function(item){
12228 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12231 Roo.apply(d, {'roo-data-checked' : 'checked'});
12235 html[html.length] = Roo.util.Format.trim(
12237 t.applySubtemplate(this.dataName, d, this.store.meta) :
12244 el.update(html.join(""));
12245 this.nodes = el.dom.childNodes;
12246 this.updateIndexes(0);
12251 * Function to override to reformat the data that is sent to
12252 * the template for each node.
12253 * DEPRICATED - use the preparedata event handler.
12254 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12255 * a JSON object for an UpdateManager bound view).
12257 prepareData : function(data, index, record)
12259 this.fireEvent("preparedata", this, data, index, record);
12263 onUpdate : function(ds, record){
12264 Roo.log('on update');
12265 this.clearSelections();
12266 var index = this.store.indexOf(record);
12267 var n = this.nodes[index];
12268 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12269 n.parentNode.removeChild(n);
12270 this.updateIndexes(index, index);
12276 onAdd : function(ds, records, index)
12278 Roo.log(['on Add', ds, records, index] );
12279 this.clearSelections();
12280 if(this.nodes.length == 0){
12284 var n = this.nodes[index];
12285 for(var i = 0, len = records.length; i < len; i++){
12286 var d = this.prepareData(records[i].data, i, records[i]);
12288 this.tpl.insertBefore(n, d);
12291 this.tpl.append(this.el, d);
12294 this.updateIndexes(index);
12297 onRemove : function(ds, record, index){
12298 Roo.log('onRemove');
12299 this.clearSelections();
12300 var el = this.dataName ?
12301 this.el.child('.roo-tpl-' + this.dataName) :
12304 el.dom.removeChild(this.nodes[index]);
12305 this.updateIndexes(index);
12309 * Refresh an individual node.
12310 * @param {Number} index
12312 refreshNode : function(index){
12313 this.onUpdate(this.store, this.store.getAt(index));
12316 updateIndexes : function(startIndex, endIndex){
12317 var ns = this.nodes;
12318 startIndex = startIndex || 0;
12319 endIndex = endIndex || ns.length - 1;
12320 for(var i = startIndex; i <= endIndex; i++){
12321 ns[i].nodeIndex = i;
12326 * Changes the data store this view uses and refresh the view.
12327 * @param {Store} store
12329 setStore : function(store, initial){
12330 if(!initial && this.store){
12331 this.store.un("datachanged", this.refresh);
12332 this.store.un("add", this.onAdd);
12333 this.store.un("remove", this.onRemove);
12334 this.store.un("update", this.onUpdate);
12335 this.store.un("clear", this.refresh);
12336 this.store.un("beforeload", this.onBeforeLoad);
12337 this.store.un("load", this.onLoad);
12338 this.store.un("loadexception", this.onLoad);
12342 store.on("datachanged", this.refresh, this);
12343 store.on("add", this.onAdd, this);
12344 store.on("remove", this.onRemove, this);
12345 store.on("update", this.onUpdate, this);
12346 store.on("clear", this.refresh, this);
12347 store.on("beforeload", this.onBeforeLoad, this);
12348 store.on("load", this.onLoad, this);
12349 store.on("loadexception", this.onLoad, this);
12357 * onbeforeLoad - masks the loading area.
12360 onBeforeLoad : function(store,opts)
12362 Roo.log('onBeforeLoad');
12364 this.el.update("");
12366 this.el.mask(this.mask ? this.mask : "Loading" );
12368 onLoad : function ()
12375 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12376 * @param {HTMLElement} node
12377 * @return {HTMLElement} The template node
12379 findItemFromChild : function(node){
12380 var el = this.dataName ?
12381 this.el.child('.roo-tpl-' + this.dataName,true) :
12384 if(!node || node.parentNode == el){
12387 var p = node.parentNode;
12388 while(p && p != el){
12389 if(p.parentNode == el){
12398 onClick : function(e){
12399 var item = this.findItemFromChild(e.getTarget());
12401 var index = this.indexOf(item);
12402 if(this.onItemClick(item, index, e) !== false){
12403 this.fireEvent("click", this, index, item, e);
12406 this.clearSelections();
12411 onContextMenu : function(e){
12412 var item = this.findItemFromChild(e.getTarget());
12414 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12419 onDblClick : function(e){
12420 var item = this.findItemFromChild(e.getTarget());
12422 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12426 onItemClick : function(item, index, e)
12428 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12431 if (this.toggleSelect) {
12432 var m = this.isSelected(item) ? 'unselect' : 'select';
12435 _t[m](item, true, false);
12438 if(this.multiSelect || this.singleSelect){
12439 if(this.multiSelect && e.shiftKey && this.lastSelection){
12440 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12442 this.select(item, this.multiSelect && e.ctrlKey);
12443 this.lastSelection = item;
12446 if(!this.tickable){
12447 e.preventDefault();
12455 * Get the number of selected nodes.
12458 getSelectionCount : function(){
12459 return this.selections.length;
12463 * Get the currently selected nodes.
12464 * @return {Array} An array of HTMLElements
12466 getSelectedNodes : function(){
12467 return this.selections;
12471 * Get the indexes of the selected nodes.
12474 getSelectedIndexes : function(){
12475 var indexes = [], s = this.selections;
12476 for(var i = 0, len = s.length; i < len; i++){
12477 indexes.push(s[i].nodeIndex);
12483 * Clear all selections
12484 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12486 clearSelections : function(suppressEvent){
12487 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12488 this.cmp.elements = this.selections;
12489 this.cmp.removeClass(this.selectedClass);
12490 this.selections = [];
12491 if(!suppressEvent){
12492 this.fireEvent("selectionchange", this, this.selections);
12498 * Returns true if the passed node is selected
12499 * @param {HTMLElement/Number} node The node or node index
12500 * @return {Boolean}
12502 isSelected : function(node){
12503 var s = this.selections;
12507 node = this.getNode(node);
12508 return s.indexOf(node) !== -1;
12513 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12514 * @param {Boolean} keepExisting (optional) true to keep existing selections
12515 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12517 select : function(nodeInfo, keepExisting, suppressEvent){
12518 if(nodeInfo instanceof Array){
12520 this.clearSelections(true);
12522 for(var i = 0, len = nodeInfo.length; i < len; i++){
12523 this.select(nodeInfo[i], true, true);
12527 var node = this.getNode(nodeInfo);
12528 if(!node || this.isSelected(node)){
12529 return; // already selected.
12532 this.clearSelections(true);
12534 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12535 Roo.fly(node).addClass(this.selectedClass);
12536 this.selections.push(node);
12537 if(!suppressEvent){
12538 this.fireEvent("selectionchange", this, this.selections);
12546 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12547 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12548 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12550 unselect : function(nodeInfo, keepExisting, suppressEvent)
12552 if(nodeInfo instanceof Array){
12553 Roo.each(this.selections, function(s) {
12554 this.unselect(s, nodeInfo);
12558 var node = this.getNode(nodeInfo);
12559 if(!node || !this.isSelected(node)){
12560 Roo.log("not selected");
12561 return; // not selected.
12565 Roo.each(this.selections, function(s) {
12567 Roo.fly(node).removeClass(this.selectedClass);
12574 this.selections= ns;
12575 this.fireEvent("selectionchange", this, this.selections);
12579 * Gets a template node.
12580 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12581 * @return {HTMLElement} The node or null if it wasn't found
12583 getNode : function(nodeInfo){
12584 if(typeof nodeInfo == "string"){
12585 return document.getElementById(nodeInfo);
12586 }else if(typeof nodeInfo == "number"){
12587 return this.nodes[nodeInfo];
12593 * Gets a range template nodes.
12594 * @param {Number} startIndex
12595 * @param {Number} endIndex
12596 * @return {Array} An array of nodes
12598 getNodes : function(start, end){
12599 var ns = this.nodes;
12600 start = start || 0;
12601 end = typeof end == "undefined" ? ns.length - 1 : end;
12604 for(var i = start; i <= end; i++){
12608 for(var i = start; i >= end; i--){
12616 * Finds the index of the passed node
12617 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12618 * @return {Number} The index of the node or -1
12620 indexOf : function(node){
12621 node = this.getNode(node);
12622 if(typeof node.nodeIndex == "number"){
12623 return node.nodeIndex;
12625 var ns = this.nodes;
12626 for(var i = 0, len = ns.length; i < len; i++){
12637 * based on jquery fullcalendar
12641 Roo.bootstrap = Roo.bootstrap || {};
12643 * @class Roo.bootstrap.Calendar
12644 * @extends Roo.bootstrap.Component
12645 * Bootstrap Calendar class
12646 * @cfg {Boolean} loadMask (true|false) default false
12647 * @cfg {Object} header generate the user specific header of the calendar, default false
12650 * Create a new Container
12651 * @param {Object} config The config object
12656 Roo.bootstrap.Calendar = function(config){
12657 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12661 * Fires when a date is selected
12662 * @param {DatePicker} this
12663 * @param {Date} date The selected date
12667 * @event monthchange
12668 * Fires when the displayed month changes
12669 * @param {DatePicker} this
12670 * @param {Date} date The selected month
12672 'monthchange': true,
12674 * @event evententer
12675 * Fires when mouse over an event
12676 * @param {Calendar} this
12677 * @param {event} Event
12679 'evententer': true,
12681 * @event eventleave
12682 * Fires when the mouse leaves an
12683 * @param {Calendar} this
12686 'eventleave': true,
12688 * @event eventclick
12689 * Fires when the mouse click an
12690 * @param {Calendar} this
12699 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12702 * @cfg {Number} startDay
12703 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12711 getAutoCreate : function(){
12714 var fc_button = function(name, corner, style, content ) {
12715 return Roo.apply({},{
12717 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12719 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12722 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12733 style : 'width:100%',
12740 cls : 'fc-header-left',
12742 fc_button('prev', 'left', 'arrow', '‹' ),
12743 fc_button('next', 'right', 'arrow', '›' ),
12744 { tag: 'span', cls: 'fc-header-space' },
12745 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12753 cls : 'fc-header-center',
12757 cls: 'fc-header-title',
12760 html : 'month / year'
12768 cls : 'fc-header-right',
12770 /* fc_button('month', 'left', '', 'month' ),
12771 fc_button('week', '', '', 'week' ),
12772 fc_button('day', 'right', '', 'day' )
12784 header = this.header;
12787 var cal_heads = function() {
12789 // fixme - handle this.
12791 for (var i =0; i < Date.dayNames.length; i++) {
12792 var d = Date.dayNames[i];
12795 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12796 html : d.substring(0,3)
12800 ret[0].cls += ' fc-first';
12801 ret[6].cls += ' fc-last';
12804 var cal_cell = function(n) {
12807 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12812 cls: 'fc-day-number',
12816 cls: 'fc-day-content',
12820 style: 'position: relative;' // height: 17px;
12832 var cal_rows = function() {
12835 for (var r = 0; r < 6; r++) {
12842 for (var i =0; i < Date.dayNames.length; i++) {
12843 var d = Date.dayNames[i];
12844 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12847 row.cn[0].cls+=' fc-first';
12848 row.cn[0].cn[0].style = 'min-height:90px';
12849 row.cn[6].cls+=' fc-last';
12853 ret[0].cls += ' fc-first';
12854 ret[4].cls += ' fc-prev-last';
12855 ret[5].cls += ' fc-last';
12862 cls: 'fc-border-separate',
12863 style : 'width:100%',
12871 cls : 'fc-first fc-last',
12889 cls : 'fc-content',
12890 style : "position: relative;",
12893 cls : 'fc-view fc-view-month fc-grid',
12894 style : 'position: relative',
12895 unselectable : 'on',
12898 cls : 'fc-event-container',
12899 style : 'position:absolute;z-index:8;top:0;left:0;'
12917 initEvents : function()
12920 throw "can not find store for calendar";
12926 style: "text-align:center",
12930 style: "background-color:white;width:50%;margin:250 auto",
12934 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12945 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12947 var size = this.el.select('.fc-content', true).first().getSize();
12948 this.maskEl.setSize(size.width, size.height);
12949 this.maskEl.enableDisplayMode("block");
12950 if(!this.loadMask){
12951 this.maskEl.hide();
12954 this.store = Roo.factory(this.store, Roo.data);
12955 this.store.on('load', this.onLoad, this);
12956 this.store.on('beforeload', this.onBeforeLoad, this);
12960 this.cells = this.el.select('.fc-day',true);
12961 //Roo.log(this.cells);
12962 this.textNodes = this.el.query('.fc-day-number');
12963 this.cells.addClassOnOver('fc-state-hover');
12965 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12966 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12967 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12968 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12970 this.on('monthchange', this.onMonthChange, this);
12972 this.update(new Date().clearTime());
12975 resize : function() {
12976 var sz = this.el.getSize();
12978 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12979 this.el.select('.fc-day-content div',true).setHeight(34);
12984 showPrevMonth : function(e){
12985 this.update(this.activeDate.add("mo", -1));
12987 showToday : function(e){
12988 this.update(new Date().clearTime());
12991 showNextMonth : function(e){
12992 this.update(this.activeDate.add("mo", 1));
12996 showPrevYear : function(){
12997 this.update(this.activeDate.add("y", -1));
13001 showNextYear : function(){
13002 this.update(this.activeDate.add("y", 1));
13007 update : function(date)
13009 var vd = this.activeDate;
13010 this.activeDate = date;
13011 // if(vd && this.el){
13012 // var t = date.getTime();
13013 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13014 // Roo.log('using add remove');
13016 // this.fireEvent('monthchange', this, date);
13018 // this.cells.removeClass("fc-state-highlight");
13019 // this.cells.each(function(c){
13020 // if(c.dateValue == t){
13021 // c.addClass("fc-state-highlight");
13022 // setTimeout(function(){
13023 // try{c.dom.firstChild.focus();}catch(e){}
13033 var days = date.getDaysInMonth();
13035 var firstOfMonth = date.getFirstDateOfMonth();
13036 var startingPos = firstOfMonth.getDay()-this.startDay;
13038 if(startingPos < this.startDay){
13042 var pm = date.add(Date.MONTH, -1);
13043 var prevStart = pm.getDaysInMonth()-startingPos;
13045 this.cells = this.el.select('.fc-day',true);
13046 this.textNodes = this.el.query('.fc-day-number');
13047 this.cells.addClassOnOver('fc-state-hover');
13049 var cells = this.cells.elements;
13050 var textEls = this.textNodes;
13052 Roo.each(cells, function(cell){
13053 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13056 days += startingPos;
13058 // convert everything to numbers so it's fast
13059 var day = 86400000;
13060 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13063 //Roo.log(prevStart);
13065 var today = new Date().clearTime().getTime();
13066 var sel = date.clearTime().getTime();
13067 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13068 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13069 var ddMatch = this.disabledDatesRE;
13070 var ddText = this.disabledDatesText;
13071 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13072 var ddaysText = this.disabledDaysText;
13073 var format = this.format;
13075 var setCellClass = function(cal, cell){
13079 //Roo.log('set Cell Class');
13081 var t = d.getTime();
13085 cell.dateValue = t;
13087 cell.className += " fc-today";
13088 cell.className += " fc-state-highlight";
13089 cell.title = cal.todayText;
13092 // disable highlight in other month..
13093 //cell.className += " fc-state-highlight";
13098 cell.className = " fc-state-disabled";
13099 cell.title = cal.minText;
13103 cell.className = " fc-state-disabled";
13104 cell.title = cal.maxText;
13108 if(ddays.indexOf(d.getDay()) != -1){
13109 cell.title = ddaysText;
13110 cell.className = " fc-state-disabled";
13113 if(ddMatch && format){
13114 var fvalue = d.dateFormat(format);
13115 if(ddMatch.test(fvalue)){
13116 cell.title = ddText.replace("%0", fvalue);
13117 cell.className = " fc-state-disabled";
13121 if (!cell.initialClassName) {
13122 cell.initialClassName = cell.dom.className;
13125 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13130 for(; i < startingPos; i++) {
13131 textEls[i].innerHTML = (++prevStart);
13132 d.setDate(d.getDate()+1);
13134 cells[i].className = "fc-past fc-other-month";
13135 setCellClass(this, cells[i]);
13140 for(; i < days; i++){
13141 intDay = i - startingPos + 1;
13142 textEls[i].innerHTML = (intDay);
13143 d.setDate(d.getDate()+1);
13145 cells[i].className = ''; // "x-date-active";
13146 setCellClass(this, cells[i]);
13150 for(; i < 42; i++) {
13151 textEls[i].innerHTML = (++extraDays);
13152 d.setDate(d.getDate()+1);
13154 cells[i].className = "fc-future fc-other-month";
13155 setCellClass(this, cells[i]);
13158 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13160 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13162 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13163 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13165 if(totalRows != 6){
13166 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13167 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13170 this.fireEvent('monthchange', this, date);
13174 if(!this.internalRender){
13175 var main = this.el.dom.firstChild;
13176 var w = main.offsetWidth;
13177 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13178 Roo.fly(main).setWidth(w);
13179 this.internalRender = true;
13180 // opera does not respect the auto grow header center column
13181 // then, after it gets a width opera refuses to recalculate
13182 // without a second pass
13183 if(Roo.isOpera && !this.secondPass){
13184 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13185 this.secondPass = true;
13186 this.update.defer(10, this, [date]);
13193 findCell : function(dt) {
13194 dt = dt.clearTime().getTime();
13196 this.cells.each(function(c){
13197 //Roo.log("check " +c.dateValue + '?=' + dt);
13198 if(c.dateValue == dt){
13208 findCells : function(ev) {
13209 var s = ev.start.clone().clearTime().getTime();
13211 var e= ev.end.clone().clearTime().getTime();
13214 this.cells.each(function(c){
13215 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13217 if(c.dateValue > e){
13220 if(c.dateValue < s){
13229 // findBestRow: function(cells)
13233 // for (var i =0 ; i < cells.length;i++) {
13234 // ret = Math.max(cells[i].rows || 0,ret);
13241 addItem : function(ev)
13243 // look for vertical location slot in
13244 var cells = this.findCells(ev);
13246 // ev.row = this.findBestRow(cells);
13248 // work out the location.
13252 for(var i =0; i < cells.length; i++) {
13254 cells[i].row = cells[0].row;
13257 cells[i].row = cells[i].row + 1;
13267 if (crow.start.getY() == cells[i].getY()) {
13269 crow.end = cells[i];
13286 cells[0].events.push(ev);
13288 this.calevents.push(ev);
13291 clearEvents: function() {
13293 if(!this.calevents){
13297 Roo.each(this.cells.elements, function(c){
13303 Roo.each(this.calevents, function(e) {
13304 Roo.each(e.els, function(el) {
13305 el.un('mouseenter' ,this.onEventEnter, this);
13306 el.un('mouseleave' ,this.onEventLeave, this);
13311 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13317 renderEvents: function()
13321 this.cells.each(function(c) {
13330 if(c.row != c.events.length){
13331 r = 4 - (4 - (c.row - c.events.length));
13334 c.events = ev.slice(0, r);
13335 c.more = ev.slice(r);
13337 if(c.more.length && c.more.length == 1){
13338 c.events.push(c.more.pop());
13341 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13345 this.cells.each(function(c) {
13347 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13350 for (var e = 0; e < c.events.length; e++){
13351 var ev = c.events[e];
13352 var rows = ev.rows;
13354 for(var i = 0; i < rows.length; i++) {
13356 // how many rows should it span..
13359 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13360 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13362 unselectable : "on",
13365 cls: 'fc-event-inner',
13369 // cls: 'fc-event-time',
13370 // html : cells.length > 1 ? '' : ev.time
13374 cls: 'fc-event-title',
13375 html : String.format('{0}', ev.title)
13382 cls: 'ui-resizable-handle ui-resizable-e',
13383 html : '  '
13390 cfg.cls += ' fc-event-start';
13392 if ((i+1) == rows.length) {
13393 cfg.cls += ' fc-event-end';
13396 var ctr = _this.el.select('.fc-event-container',true).first();
13397 var cg = ctr.createChild(cfg);
13399 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13400 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13402 var r = (c.more.length) ? 1 : 0;
13403 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13404 cg.setWidth(ebox.right - sbox.x -2);
13406 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13407 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13408 cg.on('click', _this.onEventClick, _this, ev);
13419 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13420 style : 'position: absolute',
13421 unselectable : "on",
13424 cls: 'fc-event-inner',
13428 cls: 'fc-event-title',
13436 cls: 'ui-resizable-handle ui-resizable-e',
13437 html : '  '
13443 var ctr = _this.el.select('.fc-event-container',true).first();
13444 var cg = ctr.createChild(cfg);
13446 var sbox = c.select('.fc-day-content',true).first().getBox();
13447 var ebox = c.select('.fc-day-content',true).first().getBox();
13449 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13450 cg.setWidth(ebox.right - sbox.x -2);
13452 cg.on('click', _this.onMoreEventClick, _this, c.more);
13462 onEventEnter: function (e, el,event,d) {
13463 this.fireEvent('evententer', this, el, event);
13466 onEventLeave: function (e, el,event,d) {
13467 this.fireEvent('eventleave', this, el, event);
13470 onEventClick: function (e, el,event,d) {
13471 this.fireEvent('eventclick', this, el, event);
13474 onMonthChange: function () {
13478 onMoreEventClick: function(e, el, more)
13482 this.calpopover.placement = 'right';
13483 this.calpopover.setTitle('More');
13485 this.calpopover.setContent('');
13487 var ctr = this.calpopover.el.select('.popover-content', true).first();
13489 Roo.each(more, function(m){
13491 cls : 'fc-event-hori fc-event-draggable',
13494 var cg = ctr.createChild(cfg);
13496 cg.on('click', _this.onEventClick, _this, m);
13499 this.calpopover.show(el);
13504 onLoad: function ()
13506 this.calevents = [];
13509 if(this.store.getCount() > 0){
13510 this.store.data.each(function(d){
13513 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13514 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13515 time : d.data.start_time,
13516 title : d.data.title,
13517 description : d.data.description,
13518 venue : d.data.venue
13523 this.renderEvents();
13525 if(this.calevents.length && this.loadMask){
13526 this.maskEl.hide();
13530 onBeforeLoad: function()
13532 this.clearEvents();
13534 this.maskEl.show();
13548 * @class Roo.bootstrap.Popover
13549 * @extends Roo.bootstrap.Component
13550 * Bootstrap Popover class
13551 * @cfg {String} html contents of the popover (or false to use children..)
13552 * @cfg {String} title of popover (or false to hide)
13553 * @cfg {String} placement how it is placed
13554 * @cfg {String} trigger click || hover (or false to trigger manually)
13555 * @cfg {String} over what (parent or false to trigger manually.)
13558 * Create a new Popover
13559 * @param {Object} config The config object
13562 Roo.bootstrap.Popover = function(config){
13563 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13566 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13568 title: 'Fill in a title',
13571 placement : 'right',
13572 trigger : 'hover', // hover
13576 can_build_overlaid : false,
13578 getChildContainer : function()
13580 return this.el.select('.popover-content',true).first();
13583 getAutoCreate : function(){
13584 Roo.log('make popover?');
13586 cls : 'popover roo-dynamic',
13587 style: 'display:block',
13593 cls : 'popover-inner',
13597 cls: 'popover-title',
13601 cls : 'popover-content',
13612 setTitle: function(str)
13614 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13616 setContent: function(str)
13618 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13620 // as it get's added to the bottom of the page.
13621 onRender : function(ct, position)
13623 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13625 var cfg = Roo.apply({}, this.getAutoCreate());
13629 cfg.cls += ' ' + this.cls;
13632 cfg.style = this.style;
13634 Roo.log("adding to ")
13635 this.el = Roo.get(document.body).createChild(cfg, position);
13641 initEvents : function()
13643 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13644 this.el.enableDisplayMode('block');
13646 if (this.over === false) {
13649 if (this.triggers === false) {
13652 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13653 var triggers = this.trigger ? this.trigger.split(' ') : [];
13654 Roo.each(triggers, function(trigger) {
13656 if (trigger == 'click') {
13657 on_el.on('click', this.toggle, this);
13658 } else if (trigger != 'manual') {
13659 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13660 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13662 on_el.on(eventIn ,this.enter, this);
13663 on_el.on(eventOut, this.leave, this);
13674 toggle : function () {
13675 this.hoverState == 'in' ? this.leave() : this.enter();
13678 enter : function () {
13681 clearTimeout(this.timeout);
13683 this.hoverState = 'in'
13685 if (!this.delay || !this.delay.show) {
13690 this.timeout = setTimeout(function () {
13691 if (_t.hoverState == 'in') {
13694 }, this.delay.show)
13696 leave : function() {
13697 clearTimeout(this.timeout);
13699 this.hoverState = 'out'
13701 if (!this.delay || !this.delay.hide) {
13706 this.timeout = setTimeout(function () {
13707 if (_t.hoverState == 'out') {
13710 }, this.delay.hide)
13713 show : function (on_el)
13716 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13719 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13720 if (this.html !== false) {
13721 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13723 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13724 if (!this.title.length) {
13725 this.el.select('.popover-title',true).hide();
13728 var placement = typeof this.placement == 'function' ?
13729 this.placement.call(this, this.el, on_el) :
13732 var autoToken = /\s?auto?\s?/i;
13733 var autoPlace = autoToken.test(placement);
13735 placement = placement.replace(autoToken, '') || 'top';
13739 //this.el.setXY([0,0]);
13741 this.el.dom.style.display='block';
13742 this.el.addClass(placement);
13744 //this.el.appendTo(on_el);
13746 var p = this.getPosition();
13747 var box = this.el.getBox();
13752 var align = Roo.bootstrap.Popover.alignment[placement]
13753 this.el.alignTo(on_el, align[0],align[1]);
13754 //var arrow = this.el.select('.arrow',true).first();
13755 //arrow.set(align[2],
13757 this.el.addClass('in');
13758 this.hoverState = null;
13760 if (this.el.hasClass('fade')) {
13767 this.el.setXY([0,0]);
13768 this.el.removeClass('in');
13775 Roo.bootstrap.Popover.alignment = {
13776 'left' : ['r-l', [-10,0], 'right'],
13777 'right' : ['l-r', [10,0], 'left'],
13778 'bottom' : ['t-b', [0,10], 'top'],
13779 'top' : [ 'b-t', [0,-10], 'bottom']
13790 * @class Roo.bootstrap.Progress
13791 * @extends Roo.bootstrap.Component
13792 * Bootstrap Progress class
13793 * @cfg {Boolean} striped striped of the progress bar
13794 * @cfg {Boolean} active animated of the progress bar
13798 * Create a new Progress
13799 * @param {Object} config The config object
13802 Roo.bootstrap.Progress = function(config){
13803 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13806 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13811 getAutoCreate : function(){
13819 cfg.cls += ' progress-striped';
13823 cfg.cls += ' active';
13842 * @class Roo.bootstrap.ProgressBar
13843 * @extends Roo.bootstrap.Component
13844 * Bootstrap ProgressBar class
13845 * @cfg {Number} aria_valuenow aria-value now
13846 * @cfg {Number} aria_valuemin aria-value min
13847 * @cfg {Number} aria_valuemax aria-value max
13848 * @cfg {String} label label for the progress bar
13849 * @cfg {String} panel (success | info | warning | danger )
13850 * @cfg {String} role role of the progress bar
13851 * @cfg {String} sr_only text
13855 * Create a new ProgressBar
13856 * @param {Object} config The config object
13859 Roo.bootstrap.ProgressBar = function(config){
13860 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13863 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13867 aria_valuemax : 100,
13873 getAutoCreate : function()
13878 cls: 'progress-bar',
13879 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13891 cfg.role = this.role;
13894 if(this.aria_valuenow){
13895 cfg['aria-valuenow'] = this.aria_valuenow;
13898 if(this.aria_valuemin){
13899 cfg['aria-valuemin'] = this.aria_valuemin;
13902 if(this.aria_valuemax){
13903 cfg['aria-valuemax'] = this.aria_valuemax;
13906 if(this.label && !this.sr_only){
13907 cfg.html = this.label;
13911 cfg.cls += ' progress-bar-' + this.panel;
13917 update : function(aria_valuenow)
13919 this.aria_valuenow = aria_valuenow;
13921 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13936 * @class Roo.bootstrap.TabGroup
13937 * @extends Roo.bootstrap.Column
13938 * Bootstrap Column class
13939 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13940 * @cfg {Boolean} carousel true to make the group behave like a carousel
13943 * Create a new TabGroup
13944 * @param {Object} config The config object
13947 Roo.bootstrap.TabGroup = function(config){
13948 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13950 this.navId = Roo.id();
13953 Roo.bootstrap.TabGroup.register(this);
13957 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13960 transition : false,
13962 getAutoCreate : function()
13964 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13966 cfg.cls += ' tab-content';
13968 if (this.carousel) {
13969 cfg.cls += ' carousel slide';
13971 cls : 'carousel-inner'
13978 getChildContainer : function()
13980 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13984 * register a Navigation item
13985 * @param {Roo.bootstrap.NavItem} the navitem to add
13987 register : function(item)
13989 this.tabs.push( item);
13990 item.navId = this.navId; // not really needed..
13994 getActivePanel : function()
13997 Roo.each(this.tabs, function(t) {
14007 getPanelByName : function(n)
14010 Roo.each(this.tabs, function(t) {
14011 if (t.tabId == n) {
14019 indexOfPanel : function(p)
14022 Roo.each(this.tabs, function(t,i) {
14023 if (t.tabId == p.tabId) {
14032 * show a specific panel
14033 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14034 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14036 showPanel : function (pan)
14039 if (typeof(pan) == 'number') {
14040 pan = this.tabs[pan];
14042 if (typeof(pan) == 'string') {
14043 pan = this.getPanelByName(pan);
14045 if (pan.tabId == this.getActivePanel().tabId) {
14048 var cur = this.getActivePanel();
14050 if (false === cur.fireEvent('beforedeactivate')) {
14054 if (this.carousel) {
14055 this.transition = true;
14056 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14057 var lr = dir == 'next' ? 'left' : 'right';
14058 pan.el.addClass(dir); // or prev
14059 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14060 cur.el.addClass(lr); // or right
14061 pan.el.addClass(lr);
14064 cur.el.on('transitionend', function() {
14065 Roo.log("trans end?");
14067 pan.el.removeClass([lr,dir]);
14068 pan.setActive(true);
14070 cur.el.removeClass([lr]);
14071 cur.setActive(false);
14073 _this.transition = false;
14075 }, this, { single: true } );
14079 cur.setActive(false);
14080 pan.setActive(true);
14084 showPanelNext : function()
14086 var i = this.indexOfPanel(this.getActivePanel());
14087 if (i > this.tabs.length) {
14090 this.showPanel(this.tabs[i+1]);
14092 showPanelPrev : function()
14094 var i = this.indexOfPanel(this.getActivePanel());
14098 this.showPanel(this.tabs[i-1]);
14109 Roo.apply(Roo.bootstrap.TabGroup, {
14113 * register a Navigation Group
14114 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14116 register : function(navgrp)
14118 this.groups[navgrp.navId] = navgrp;
14122 * fetch a Navigation Group based on the navigation ID
14123 * if one does not exist , it will get created.
14124 * @param {string} the navgroup to add
14125 * @returns {Roo.bootstrap.NavGroup} the navgroup
14127 get: function(navId) {
14128 if (typeof(this.groups[navId]) == 'undefined') {
14129 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14131 return this.groups[navId] ;
14146 * @class Roo.bootstrap.TabPanel
14147 * @extends Roo.bootstrap.Component
14148 * Bootstrap TabPanel class
14149 * @cfg {Boolean} active panel active
14150 * @cfg {String} html panel content
14151 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14152 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14156 * Create a new TabPanel
14157 * @param {Object} config The config object
14160 Roo.bootstrap.TabPanel = function(config){
14161 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14165 * Fires when the active status changes
14166 * @param {Roo.bootstrap.TabPanel} this
14167 * @param {Boolean} state the new state
14172 * @event beforedeactivate
14173 * Fires before a tab is de-activated - can be used to do validation on a form.
14174 * @param {Roo.bootstrap.TabPanel} this
14175 * @return {Boolean} false if there is an error
14178 'beforedeactivate': true
14181 this.tabId = this.tabId || Roo.id();
14185 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14192 getAutoCreate : function(){
14195 // item is needed for carousel - not sure if it has any effect otherwise
14196 cls: 'tab-pane item',
14197 html: this.html || ''
14201 cfg.cls += ' active';
14205 cfg.tabId = this.tabId;
14212 initEvents: function()
14214 Roo.log('-------- init events on tab panel ---------');
14216 var p = this.parent();
14217 this.navId = this.navId || p.navId;
14219 if (typeof(this.navId) != 'undefined') {
14220 // not really needed.. but just in case.. parent should be a NavGroup.
14221 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14222 Roo.log(['register', tg, this]);
14228 onRender : function(ct, position)
14230 // Roo.log("Call onRender: " + this.xtype);
14232 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14240 setActive: function(state)
14242 Roo.log("panel - set active " + this.tabId + "=" + state);
14244 this.active = state;
14246 this.el.removeClass('active');
14248 } else if (!this.el.hasClass('active')) {
14249 this.el.addClass('active');
14251 this.fireEvent('changed', this, state);
14268 * @class Roo.bootstrap.DateField
14269 * @extends Roo.bootstrap.Input
14270 * Bootstrap DateField class
14271 * @cfg {Number} weekStart default 0
14272 * @cfg {Number} weekStart default 0
14273 * @cfg {Number} viewMode default empty, (months|years)
14274 * @cfg {Number} minViewMode default empty, (months|years)
14275 * @cfg {Number} startDate default -Infinity
14276 * @cfg {Number} endDate default Infinity
14277 * @cfg {Boolean} todayHighlight default false
14278 * @cfg {Boolean} todayBtn default false
14279 * @cfg {Boolean} calendarWeeks default false
14280 * @cfg {Object} daysOfWeekDisabled default empty
14282 * @cfg {Boolean} keyboardNavigation default true
14283 * @cfg {String} language default en
14286 * Create a new DateField
14287 * @param {Object} config The config object
14290 Roo.bootstrap.DateField = function(config){
14291 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14295 * Fires when this field show.
14296 * @param {Roo.bootstrap.DateField} this
14297 * @param {Mixed} date The date value
14302 * Fires when this field hide.
14303 * @param {Roo.bootstrap.DateField} this
14304 * @param {Mixed} date The date value
14309 * Fires when select a date.
14310 * @param {Roo.bootstrap.DateField} this
14311 * @param {Mixed} date The date value
14317 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14320 * @cfg {String} format
14321 * The default date format string which can be overriden for localization support. The format must be
14322 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14326 * @cfg {String} altFormats
14327 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14328 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14330 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14338 todayHighlight : false,
14344 keyboardNavigation: true,
14346 calendarWeeks: false,
14348 startDate: -Infinity,
14352 daysOfWeekDisabled: [],
14356 UTCDate: function()
14358 return new Date(Date.UTC.apply(Date, arguments));
14361 UTCToday: function()
14363 var today = new Date();
14364 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14367 getDate: function() {
14368 var d = this.getUTCDate();
14369 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14372 getUTCDate: function() {
14376 setDate: function(d) {
14377 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14380 setUTCDate: function(d) {
14382 this.setValue(this.formatDate(this.date));
14385 onRender: function(ct, position)
14388 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14390 this.language = this.language || 'en';
14391 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14392 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14394 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14395 this.format = this.format || 'm/d/y';
14396 this.isInline = false;
14397 this.isInput = true;
14398 this.component = this.el.select('.add-on', true).first() || false;
14399 this.component = (this.component && this.component.length === 0) ? false : this.component;
14400 this.hasInput = this.component && this.inputEL().length;
14402 if (typeof(this.minViewMode === 'string')) {
14403 switch (this.minViewMode) {
14405 this.minViewMode = 1;
14408 this.minViewMode = 2;
14411 this.minViewMode = 0;
14416 if (typeof(this.viewMode === 'string')) {
14417 switch (this.viewMode) {
14430 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14432 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14434 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14436 this.picker().on('mousedown', this.onMousedown, this);
14437 this.picker().on('click', this.onClick, this);
14439 this.picker().addClass('datepicker-dropdown');
14441 this.startViewMode = this.viewMode;
14444 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14445 if(!this.calendarWeeks){
14450 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14451 v.attr('colspan', function(i, val){
14452 return parseInt(val) + 1;
14457 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14459 this.setStartDate(this.startDate);
14460 this.setEndDate(this.endDate);
14462 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14469 if(this.isInline) {
14474 picker : function()
14476 return this.pickerEl;
14477 // return this.el.select('.datepicker', true).first();
14480 fillDow: function()
14482 var dowCnt = this.weekStart;
14491 if(this.calendarWeeks){
14499 while (dowCnt < this.weekStart + 7) {
14503 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14507 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14510 fillMonths: function()
14513 var months = this.picker().select('>.datepicker-months td', true).first();
14515 months.dom.innerHTML = '';
14521 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14524 months.createChild(month);
14531 this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14533 if (this.date < this.startDate) {
14534 this.viewDate = new Date(this.startDate);
14535 } else if (this.date > this.endDate) {
14536 this.viewDate = new Date(this.endDate);
14538 this.viewDate = new Date(this.date);
14546 var d = new Date(this.viewDate),
14547 year = d.getUTCFullYear(),
14548 month = d.getUTCMonth(),
14549 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14550 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14551 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14552 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14553 currentDate = this.date && this.date.valueOf(),
14554 today = this.UTCToday();
14556 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14558 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14560 // this.picker.select('>tfoot th.today').
14561 // .text(dates[this.language].today)
14562 // .toggle(this.todayBtn !== false);
14564 this.updateNavArrows();
14567 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14569 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14571 prevMonth.setUTCDate(day);
14573 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14575 var nextMonth = new Date(prevMonth);
14577 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14579 nextMonth = nextMonth.valueOf();
14581 var fillMonths = false;
14583 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14585 while(prevMonth.valueOf() < nextMonth) {
14588 if (prevMonth.getUTCDay() === this.weekStart) {
14590 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14598 if(this.calendarWeeks){
14599 // ISO 8601: First week contains first thursday.
14600 // ISO also states week starts on Monday, but we can be more abstract here.
14602 // Start of current week: based on weekstart/current date
14603 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14604 // Thursday of this week
14605 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14606 // First Thursday of year, year from thursday
14607 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14608 // Calendar week: ms between thursdays, div ms per day, div 7 days
14609 calWeek = (th - yth) / 864e5 / 7 + 1;
14611 fillMonths.cn.push({
14619 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14621 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14624 if (this.todayHighlight &&
14625 prevMonth.getUTCFullYear() == today.getFullYear() &&
14626 prevMonth.getUTCMonth() == today.getMonth() &&
14627 prevMonth.getUTCDate() == today.getDate()) {
14628 clsName += ' today';
14631 if (currentDate && prevMonth.valueOf() === currentDate) {
14632 clsName += ' active';
14635 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14636 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14637 clsName += ' disabled';
14640 fillMonths.cn.push({
14642 cls: 'day ' + clsName,
14643 html: prevMonth.getDate()
14646 prevMonth.setDate(prevMonth.getDate()+1);
14649 var currentYear = this.date && this.date.getUTCFullYear();
14650 var currentMonth = this.date && this.date.getUTCMonth();
14652 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14654 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14655 v.removeClass('active');
14657 if(currentYear === year && k === currentMonth){
14658 v.addClass('active');
14661 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14662 v.addClass('disabled');
14668 year = parseInt(year/10, 10) * 10;
14670 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14672 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14675 for (var i = -1; i < 11; i++) {
14676 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14678 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14686 showMode: function(dir)
14689 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14691 Roo.each(this.picker().select('>div',true).elements, function(v){
14692 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14695 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14700 if(this.isInline) return;
14702 this.picker().removeClass(['bottom', 'top']);
14704 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14706 * place to the top of element!
14710 this.picker().addClass('top');
14711 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14716 this.picker().addClass('bottom');
14718 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14721 parseDate : function(value)
14723 if(!value || value instanceof Date){
14726 var v = Date.parseDate(value, this.format);
14727 if (!v && this.useIso) {
14728 v = Date.parseDate(value, 'Y-m-d');
14730 if(!v && this.altFormats){
14731 if(!this.altFormatsArray){
14732 this.altFormatsArray = this.altFormats.split("|");
14734 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14735 v = Date.parseDate(value, this.altFormatsArray[i]);
14741 formatDate : function(date, fmt)
14743 return (!date || !(date instanceof Date)) ?
14744 date : date.dateFormat(fmt || this.format);
14747 onFocus : function()
14749 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14753 onBlur : function()
14755 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14757 var d = this.inputEl().getValue();
14766 this.picker().show();
14770 this.fireEvent('show', this, this.date);
14775 if(this.isInline) return;
14776 this.picker().hide();
14777 this.viewMode = this.startViewMode;
14780 this.fireEvent('hide', this, this.date);
14784 onMousedown: function(e)
14786 e.stopPropagation();
14787 e.preventDefault();
14792 Roo.bootstrap.DateField.superclass.keyup.call(this);
14796 setValue: function(v)
14798 var d = new Date(v).clearTime();
14800 if(isNaN(d.getTime())){
14801 this.date = this.viewDate = '';
14802 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14806 v = this.formatDate(d);
14808 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14810 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14814 this.fireEvent('select', this, this.date);
14818 getValue: function()
14820 return this.formatDate(this.date);
14823 fireKey: function(e)
14825 if (!this.picker().isVisible()){
14826 if (e.keyCode == 27) // allow escape to hide and re-show picker
14831 var dateChanged = false,
14833 newDate, newViewDate;
14838 e.preventDefault();
14842 if (!this.keyboardNavigation) break;
14843 dir = e.keyCode == 37 ? -1 : 1;
14846 newDate = this.moveYear(this.date, dir);
14847 newViewDate = this.moveYear(this.viewDate, dir);
14848 } else if (e.shiftKey){
14849 newDate = this.moveMonth(this.date, dir);
14850 newViewDate = this.moveMonth(this.viewDate, dir);
14852 newDate = new Date(this.date);
14853 newDate.setUTCDate(this.date.getUTCDate() + dir);
14854 newViewDate = new Date(this.viewDate);
14855 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14857 if (this.dateWithinRange(newDate)){
14858 this.date = newDate;
14859 this.viewDate = newViewDate;
14860 this.setValue(this.formatDate(this.date));
14862 e.preventDefault();
14863 dateChanged = true;
14868 if (!this.keyboardNavigation) break;
14869 dir = e.keyCode == 38 ? -1 : 1;
14871 newDate = this.moveYear(this.date, dir);
14872 newViewDate = this.moveYear(this.viewDate, dir);
14873 } else if (e.shiftKey){
14874 newDate = this.moveMonth(this.date, dir);
14875 newViewDate = this.moveMonth(this.viewDate, dir);
14877 newDate = new Date(this.date);
14878 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14879 newViewDate = new Date(this.viewDate);
14880 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14882 if (this.dateWithinRange(newDate)){
14883 this.date = newDate;
14884 this.viewDate = newViewDate;
14885 this.setValue(this.formatDate(this.date));
14887 e.preventDefault();
14888 dateChanged = true;
14892 this.setValue(this.formatDate(this.date));
14894 e.preventDefault();
14897 this.setValue(this.formatDate(this.date));
14911 onClick: function(e)
14913 e.stopPropagation();
14914 e.preventDefault();
14916 var target = e.getTarget();
14918 if(target.nodeName.toLowerCase() === 'i'){
14919 target = Roo.get(target).dom.parentNode;
14922 var nodeName = target.nodeName;
14923 var className = target.className;
14924 var html = target.innerHTML;
14926 switch(nodeName.toLowerCase()) {
14928 switch(className) {
14934 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14935 switch(this.viewMode){
14937 this.viewDate = this.moveMonth(this.viewDate, dir);
14941 this.viewDate = this.moveYear(this.viewDate, dir);
14947 var date = new Date();
14948 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14950 this.setValue(this.formatDate(this.date));
14957 if (className.indexOf('disabled') === -1) {
14958 this.viewDate.setUTCDate(1);
14959 if (className.indexOf('month') !== -1) {
14960 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14962 var year = parseInt(html, 10) || 0;
14963 this.viewDate.setUTCFullYear(year);
14972 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14973 var day = parseInt(html, 10) || 1;
14974 var year = this.viewDate.getUTCFullYear(),
14975 month = this.viewDate.getUTCMonth();
14977 if (className.indexOf('old') !== -1) {
14984 } else if (className.indexOf('new') !== -1) {
14992 this.date = this.UTCDate(year, month, day,0,0,0,0);
14993 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14995 this.setValue(this.formatDate(this.date));
15002 setStartDate: function(startDate)
15004 this.startDate = startDate || -Infinity;
15005 if (this.startDate !== -Infinity) {
15006 this.startDate = this.parseDate(this.startDate);
15009 this.updateNavArrows();
15012 setEndDate: function(endDate)
15014 this.endDate = endDate || Infinity;
15015 if (this.endDate !== Infinity) {
15016 this.endDate = this.parseDate(this.endDate);
15019 this.updateNavArrows();
15022 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15024 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15025 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15026 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15028 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15029 return parseInt(d, 10);
15032 this.updateNavArrows();
15035 updateNavArrows: function()
15037 var d = new Date(this.viewDate),
15038 year = d.getUTCFullYear(),
15039 month = d.getUTCMonth();
15041 Roo.each(this.picker().select('.prev', true).elements, function(v){
15043 switch (this.viewMode) {
15046 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15052 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15059 Roo.each(this.picker().select('.next', true).elements, function(v){
15061 switch (this.viewMode) {
15064 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15070 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15078 moveMonth: function(date, dir)
15080 if (!dir) return date;
15081 var new_date = new Date(date.valueOf()),
15082 day = new_date.getUTCDate(),
15083 month = new_date.getUTCMonth(),
15084 mag = Math.abs(dir),
15086 dir = dir > 0 ? 1 : -1;
15089 // If going back one month, make sure month is not current month
15090 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15092 return new_date.getUTCMonth() == month;
15094 // If going forward one month, make sure month is as expected
15095 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15097 return new_date.getUTCMonth() != new_month;
15099 new_month = month + dir;
15100 new_date.setUTCMonth(new_month);
15101 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15102 if (new_month < 0 || new_month > 11)
15103 new_month = (new_month + 12) % 12;
15105 // For magnitudes >1, move one month at a time...
15106 for (var i=0; i<mag; i++)
15107 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15108 new_date = this.moveMonth(new_date, dir);
15109 // ...then reset the day, keeping it in the new month
15110 new_month = new_date.getUTCMonth();
15111 new_date.setUTCDate(day);
15113 return new_month != new_date.getUTCMonth();
15116 // Common date-resetting loop -- if date is beyond end of month, make it
15119 new_date.setUTCDate(--day);
15120 new_date.setUTCMonth(new_month);
15125 moveYear: function(date, dir)
15127 return this.moveMonth(date, dir*12);
15130 dateWithinRange: function(date)
15132 return date >= this.startDate && date <= this.endDate;
15138 this.picker().remove();
15143 Roo.apply(Roo.bootstrap.DateField, {
15154 html: '<i class="fa fa-arrow-left"/>'
15164 html: '<i class="fa fa-arrow-right"/>'
15206 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15207 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15208 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15209 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15210 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15223 navFnc: 'FullYear',
15228 navFnc: 'FullYear',
15233 Roo.apply(Roo.bootstrap.DateField, {
15237 cls: 'datepicker dropdown-menu',
15241 cls: 'datepicker-days',
15245 cls: 'table-condensed',
15247 Roo.bootstrap.DateField.head,
15251 Roo.bootstrap.DateField.footer
15258 cls: 'datepicker-months',
15262 cls: 'table-condensed',
15264 Roo.bootstrap.DateField.head,
15265 Roo.bootstrap.DateField.content,
15266 Roo.bootstrap.DateField.footer
15273 cls: 'datepicker-years',
15277 cls: 'table-condensed',
15279 Roo.bootstrap.DateField.head,
15280 Roo.bootstrap.DateField.content,
15281 Roo.bootstrap.DateField.footer
15300 * @class Roo.bootstrap.TimeField
15301 * @extends Roo.bootstrap.Input
15302 * Bootstrap DateField class
15306 * Create a new TimeField
15307 * @param {Object} config The config object
15310 Roo.bootstrap.TimeField = function(config){
15311 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15315 * Fires when this field show.
15316 * @param {Roo.bootstrap.DateField} this
15317 * @param {Mixed} date The date value
15322 * Fires when this field hide.
15323 * @param {Roo.bootstrap.DateField} this
15324 * @param {Mixed} date The date value
15329 * Fires when select a date.
15330 * @param {Roo.bootstrap.DateField} this
15331 * @param {Mixed} date The date value
15337 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15340 * @cfg {String} format
15341 * The default time format string which can be overriden for localization support. The format must be
15342 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15346 onRender: function(ct, position)
15349 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15351 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15353 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15355 this.pop = this.picker().select('>.datepicker-time',true).first();
15356 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15358 this.picker().on('mousedown', this.onMousedown, this);
15359 this.picker().on('click', this.onClick, this);
15361 this.picker().addClass('datepicker-dropdown');
15366 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15367 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15368 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15369 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15370 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15371 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15375 fireKey: function(e){
15376 if (!this.picker().isVisible()){
15377 if (e.keyCode == 27) // allow escape to hide and re-show picker
15382 e.preventDefault();
15390 this.onTogglePeriod();
15393 this.onIncrementMinutes();
15396 this.onDecrementMinutes();
15405 onClick: function(e) {
15406 e.stopPropagation();
15407 e.preventDefault();
15410 picker : function()
15412 return this.el.select('.datepicker', true).first();
15415 fillTime: function()
15417 var time = this.pop.select('tbody', true).first();
15419 time.dom.innerHTML = '';
15434 cls: 'hours-up glyphicon glyphicon-chevron-up'
15454 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15475 cls: 'timepicker-hour',
15490 cls: 'timepicker-minute',
15505 cls: 'btn btn-primary period',
15527 cls: 'hours-down glyphicon glyphicon-chevron-down'
15547 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15565 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15572 var hours = this.time.getHours();
15573 var minutes = this.time.getMinutes();
15586 hours = hours - 12;
15590 hours = '0' + hours;
15594 minutes = '0' + minutes;
15597 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15598 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15599 this.pop.select('button', true).first().dom.innerHTML = period;
15605 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15607 var cls = ['bottom'];
15609 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15616 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15621 this.picker().addClass(cls.join('-'));
15625 Roo.each(cls, function(c){
15627 _this.picker().setTop(_this.inputEl().getHeight());
15631 _this.picker().setTop(0 - _this.picker().getHeight());
15636 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15640 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15647 onFocus : function()
15649 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15653 onBlur : function()
15655 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15661 this.picker().show();
15666 this.fireEvent('show', this, this.date);
15671 this.picker().hide();
15674 this.fireEvent('hide', this, this.date);
15677 setTime : function()
15680 this.setValue(this.time.format(this.format));
15682 this.fireEvent('select', this, this.date);
15687 onMousedown: function(e){
15688 e.stopPropagation();
15689 e.preventDefault();
15692 onIncrementHours: function()
15694 Roo.log('onIncrementHours');
15695 this.time = this.time.add(Date.HOUR, 1);
15700 onDecrementHours: function()
15702 Roo.log('onDecrementHours');
15703 this.time = this.time.add(Date.HOUR, -1);
15707 onIncrementMinutes: function()
15709 Roo.log('onIncrementMinutes');
15710 this.time = this.time.add(Date.MINUTE, 1);
15714 onDecrementMinutes: function()
15716 Roo.log('onDecrementMinutes');
15717 this.time = this.time.add(Date.MINUTE, -1);
15721 onTogglePeriod: function()
15723 Roo.log('onTogglePeriod');
15724 this.time = this.time.add(Date.HOUR, 12);
15731 Roo.apply(Roo.bootstrap.TimeField, {
15761 cls: 'btn btn-info ok',
15773 Roo.apply(Roo.bootstrap.TimeField, {
15777 cls: 'datepicker dropdown-menu',
15781 cls: 'datepicker-time',
15785 cls: 'table-condensed',
15787 Roo.bootstrap.TimeField.content,
15788 Roo.bootstrap.TimeField.footer
15807 * @class Roo.bootstrap.CheckBox
15808 * @extends Roo.bootstrap.Input
15809 * Bootstrap CheckBox class
15811 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15812 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15813 * @cfg {String} boxLabel The text that appears beside the checkbox
15814 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15815 * @cfg {Boolean} checked initnal the element
15819 * Create a new CheckBox
15820 * @param {Object} config The config object
15823 Roo.bootstrap.CheckBox = function(config){
15824 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15829 * Fires when the element is checked or unchecked.
15830 * @param {Roo.bootstrap.CheckBox} this This input
15831 * @param {Boolean} checked The new checked value
15837 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15839 inputType: 'checkbox',
15846 getAutoCreate : function()
15848 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15854 cfg.cls = 'form-group checkbox' //input-group
15862 type : this.inputType,
15863 value : (!this.checked) ? this.valueOff : this.inputValue,
15864 cls : 'roo-checkbox', //'form-box',
15865 placeholder : this.placeholder || ''
15869 if (this.weight) { // Validity check?
15870 cfg.cls += " checkbox-" + this.weight;
15873 if (this.disabled) {
15874 input.disabled=true;
15878 input.checked = this.checked;
15882 input.name = this.name;
15886 input.cls += ' input-' + this.size;
15890 ['xs','sm','md','lg'].map(function(size){
15891 if (settings[size]) {
15892 cfg.cls += ' col-' + size + '-' + settings[size];
15898 var inputblock = input;
15903 if (this.before || this.after) {
15906 cls : 'input-group',
15910 inputblock.cn.push({
15912 cls : 'input-group-addon',
15916 inputblock.cn.push(input);
15918 inputblock.cn.push({
15920 cls : 'input-group-addon',
15927 if (align ==='left' && this.fieldLabel.length) {
15928 Roo.log("left and has label");
15934 cls : 'control-label col-md-' + this.labelWidth,
15935 html : this.fieldLabel
15939 cls : "col-md-" + (12 - this.labelWidth),
15946 } else if ( this.fieldLabel.length) {
15951 tag: this.boxLabel ? 'span' : 'label',
15953 cls: 'control-label box-input-label',
15954 //cls : 'input-group-addon',
15955 html : this.fieldLabel
15965 Roo.log(" no label && no align");
15966 cfg.cn = [ inputblock ] ;
15975 html: this.boxLabel
15987 * return the real input element.
15989 inputEl: function ()
15991 return this.el.select('input.roo-checkbox',true).first();
15996 return this.el.select('label.control-label',true).first();
15999 initEvents : function()
16001 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16003 this.inputEl().on('click', this.onClick, this);
16007 onClick : function()
16009 this.setChecked(!this.checked);
16012 setChecked : function(state,suppressEvent)
16014 this.checked = state;
16016 this.inputEl().dom.checked = state;
16018 if(suppressEvent !== true){
16019 this.fireEvent('check', this, state);
16022 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16026 setValue : function(v,suppressEvent)
16028 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16042 * @class Roo.bootstrap.Radio
16043 * @extends Roo.bootstrap.CheckBox
16044 * Bootstrap Radio class
16047 * Create a new Radio
16048 * @param {Object} config The config object
16051 Roo.bootstrap.Radio = function(config){
16052 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16056 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16058 inputType: 'radio',
16062 getAutoCreate : function()
16064 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16070 cfg.cls = 'form-group radio' //input-group
16075 type : this.inputType,
16076 value : (!this.checked) ? this.valueOff : this.inputValue,
16078 placeholder : this.placeholder || ''
16081 if (this.weight) { // Validity check?
16082 cfg.cls += " radio-" + this.weight;
16084 if (this.disabled) {
16085 input.disabled=true;
16089 input.checked = this.checked;
16093 input.name = this.name;
16097 input.cls += ' input-' + this.size;
16101 ['xs','sm','md','lg'].map(function(size){
16102 if (settings[size]) {
16103 cfg.cls += ' col-' + size + '-' + settings[size];
16107 var inputblock = input;
16109 if (this.before || this.after) {
16112 cls : 'input-group',
16116 inputblock.cn.push({
16118 cls : 'input-group-addon',
16122 inputblock.cn.push(input);
16124 inputblock.cn.push({
16126 cls : 'input-group-addon',
16133 if (align ==='left' && this.fieldLabel.length) {
16134 Roo.log("left and has label");
16140 cls : 'control-label col-md-' + this.labelWidth,
16141 html : this.fieldLabel
16145 cls : "col-md-" + (12 - this.labelWidth),
16152 } else if ( this.fieldLabel.length) {
16159 cls: 'control-label box-input-label',
16160 //cls : 'input-group-addon',
16161 html : this.fieldLabel
16171 Roo.log(" no label && no align");
16186 html: this.boxLabel
16193 inputEl: function ()
16195 return this.el.select('input.roo-radio',true).first();
16197 onClick : function()
16199 this.setChecked(true);
16202 setChecked : function(state,suppressEvent)
16205 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16206 v.dom.checked = false;
16210 this.checked = state;
16211 this.inputEl().dom.checked = state;
16213 if(suppressEvent !== true){
16214 this.fireEvent('check', this, state);
16217 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16221 getGroupValue : function()
16224 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16225 if(v.dom.checked == true){
16226 value = v.dom.value;
16234 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16235 * @return {Mixed} value The field value
16237 getValue : function(){
16238 return this.getGroupValue();
16244 //<script type="text/javascript">
16247 * Based Ext JS Library 1.1.1
16248 * Copyright(c) 2006-2007, Ext JS, LLC.
16254 * @class Roo.HtmlEditorCore
16255 * @extends Roo.Component
16256 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16258 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16261 Roo.HtmlEditorCore = function(config){
16264 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16267 * @event initialize
16268 * Fires when the editor is fully initialized (including the iframe)
16269 * @param {Roo.HtmlEditorCore} this
16274 * Fires when the editor is first receives the focus. Any insertion must wait
16275 * until after this event.
16276 * @param {Roo.HtmlEditorCore} this
16280 * @event beforesync
16281 * Fires before the textarea is updated with content from the editor iframe. Return false
16282 * to cancel the sync.
16283 * @param {Roo.HtmlEditorCore} this
16284 * @param {String} html
16288 * @event beforepush
16289 * Fires before the iframe editor is updated with content from the textarea. Return false
16290 * to cancel the push.
16291 * @param {Roo.HtmlEditorCore} this
16292 * @param {String} html
16297 * Fires when the textarea is updated with content from the editor iframe.
16298 * @param {Roo.HtmlEditorCore} this
16299 * @param {String} html
16304 * Fires when the iframe editor is updated with content from the textarea.
16305 * @param {Roo.HtmlEditorCore} this
16306 * @param {String} html
16311 * @event editorevent
16312 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16313 * @param {Roo.HtmlEditorCore} this
16321 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16325 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16331 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16336 * @cfg {Number} height (in pixels)
16340 * @cfg {Number} width (in pixels)
16345 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16348 stylesheets: false,
16353 // private properties
16354 validationEvent : false,
16356 initialized : false,
16358 sourceEditMode : false,
16359 onFocus : Roo.emptyFn,
16361 hideMode:'offsets',
16369 * Protected method that will not generally be called directly. It
16370 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16371 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16373 getDocMarkup : function(){
16376 Roo.log(this.stylesheets);
16378 // inherit styels from page...??
16379 if (this.stylesheets === false) {
16381 Roo.get(document.head).select('style').each(function(node) {
16382 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16385 Roo.get(document.head).select('link').each(function(node) {
16386 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16389 } else if (!this.stylesheets.length) {
16391 st = '<style type="text/css">' +
16392 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16395 Roo.each(this.stylesheets, function(s) {
16396 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16401 st += '<style type="text/css">' +
16402 'IMG { cursor: pointer } ' +
16406 return '<html><head>' + st +
16407 //<style type="text/css">' +
16408 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16410 ' </head><body class="roo-htmleditor-body"></body></html>';
16414 onRender : function(ct, position)
16417 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16418 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16421 this.el.dom.style.border = '0 none';
16422 this.el.dom.setAttribute('tabIndex', -1);
16423 this.el.addClass('x-hidden hide');
16427 if(Roo.isIE){ // fix IE 1px bogus margin
16428 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16432 this.frameId = Roo.id();
16436 var iframe = this.owner.wrap.createChild({
16438 cls: 'form-control', // bootstrap..
16440 name: this.frameId,
16441 frameBorder : 'no',
16442 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16447 this.iframe = iframe.dom;
16449 this.assignDocWin();
16451 this.doc.designMode = 'on';
16454 this.doc.write(this.getDocMarkup());
16458 var task = { // must defer to wait for browser to be ready
16460 //console.log("run task?" + this.doc.readyState);
16461 this.assignDocWin();
16462 if(this.doc.body || this.doc.readyState == 'complete'){
16464 this.doc.designMode="on";
16468 Roo.TaskMgr.stop(task);
16469 this.initEditor.defer(10, this);
16476 Roo.TaskMgr.start(task);
16483 onResize : function(w, h)
16485 Roo.log('resize: ' +w + ',' + h );
16486 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16490 if(typeof w == 'number'){
16492 this.iframe.style.width = w + 'px';
16494 if(typeof h == 'number'){
16496 this.iframe.style.height = h + 'px';
16498 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16505 * Toggles the editor between standard and source edit mode.
16506 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16508 toggleSourceEdit : function(sourceEditMode){
16510 this.sourceEditMode = sourceEditMode === true;
16512 if(this.sourceEditMode){
16514 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16517 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16518 //this.iframe.className = '';
16521 //this.setSize(this.owner.wrap.getSize());
16522 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16529 * Protected method that will not generally be called directly. If you need/want
16530 * custom HTML cleanup, this is the method you should override.
16531 * @param {String} html The HTML to be cleaned
16532 * return {String} The cleaned HTML
16534 cleanHtml : function(html){
16535 html = String(html);
16536 if(html.length > 5){
16537 if(Roo.isSafari){ // strip safari nonsense
16538 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16541 if(html == ' '){
16548 * HTML Editor -> Textarea
16549 * Protected method that will not generally be called directly. Syncs the contents
16550 * of the editor iframe with the textarea.
16552 syncValue : function(){
16553 if(this.initialized){
16554 var bd = (this.doc.body || this.doc.documentElement);
16555 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16556 var html = bd.innerHTML;
16558 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16559 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16561 html = '<div style="'+m[0]+'">' + html + '</div>';
16564 html = this.cleanHtml(html);
16565 // fix up the special chars.. normaly like back quotes in word...
16566 // however we do not want to do this with chinese..
16567 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16568 var cc = b.charCodeAt();
16570 (cc >= 0x4E00 && cc < 0xA000 ) ||
16571 (cc >= 0x3400 && cc < 0x4E00 ) ||
16572 (cc >= 0xf900 && cc < 0xfb00 )
16578 if(this.owner.fireEvent('beforesync', this, html) !== false){
16579 this.el.dom.value = html;
16580 this.owner.fireEvent('sync', this, html);
16586 * Protected method that will not generally be called directly. Pushes the value of the textarea
16587 * into the iframe editor.
16589 pushValue : function(){
16590 if(this.initialized){
16591 var v = this.el.dom.value.trim();
16593 // if(v.length < 1){
16597 if(this.owner.fireEvent('beforepush', this, v) !== false){
16598 var d = (this.doc.body || this.doc.documentElement);
16600 this.cleanUpPaste();
16601 this.el.dom.value = d.innerHTML;
16602 this.owner.fireEvent('push', this, v);
16608 deferFocus : function(){
16609 this.focus.defer(10, this);
16613 focus : function(){
16614 if(this.win && !this.sourceEditMode){
16621 assignDocWin: function()
16623 var iframe = this.iframe;
16626 this.doc = iframe.contentWindow.document;
16627 this.win = iframe.contentWindow;
16629 // if (!Roo.get(this.frameId)) {
16632 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16633 // this.win = Roo.get(this.frameId).dom.contentWindow;
16635 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16639 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16640 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16645 initEditor : function(){
16646 //console.log("INIT EDITOR");
16647 this.assignDocWin();
16651 this.doc.designMode="on";
16653 this.doc.write(this.getDocMarkup());
16656 var dbody = (this.doc.body || this.doc.documentElement);
16657 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16658 // this copies styles from the containing element into thsi one..
16659 // not sure why we need all of this..
16660 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16662 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16663 //ss['background-attachment'] = 'fixed'; // w3c
16664 dbody.bgProperties = 'fixed'; // ie
16665 //Roo.DomHelper.applyStyles(dbody, ss);
16666 Roo.EventManager.on(this.doc, {
16667 //'mousedown': this.onEditorEvent,
16668 'mouseup': this.onEditorEvent,
16669 'dblclick': this.onEditorEvent,
16670 'click': this.onEditorEvent,
16671 'keyup': this.onEditorEvent,
16676 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16678 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16679 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16681 this.initialized = true;
16683 this.owner.fireEvent('initialize', this);
16688 onDestroy : function(){
16694 //for (var i =0; i < this.toolbars.length;i++) {
16695 // // fixme - ask toolbars for heights?
16696 // this.toolbars[i].onDestroy();
16699 //this.wrap.dom.innerHTML = '';
16700 //this.wrap.remove();
16705 onFirstFocus : function(){
16707 this.assignDocWin();
16710 this.activated = true;
16713 if(Roo.isGecko){ // prevent silly gecko errors
16715 var s = this.win.getSelection();
16716 if(!s.focusNode || s.focusNode.nodeType != 3){
16717 var r = s.getRangeAt(0);
16718 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16723 this.execCmd('useCSS', true);
16724 this.execCmd('styleWithCSS', false);
16727 this.owner.fireEvent('activate', this);
16731 adjustFont: function(btn){
16732 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16733 //if(Roo.isSafari){ // safari
16736 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16737 if(Roo.isSafari){ // safari
16738 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16739 v = (v < 10) ? 10 : v;
16740 v = (v > 48) ? 48 : v;
16741 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16746 v = Math.max(1, v+adjust);
16748 this.execCmd('FontSize', v );
16751 onEditorEvent : function(e){
16752 this.owner.fireEvent('editorevent', this, e);
16753 // this.updateToolbar();
16754 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16757 insertTag : function(tg)
16759 // could be a bit smarter... -> wrap the current selected tRoo..
16760 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16762 range = this.createRange(this.getSelection());
16763 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16764 wrappingNode.appendChild(range.extractContents());
16765 range.insertNode(wrappingNode);
16772 this.execCmd("formatblock", tg);
16776 insertText : function(txt)
16780 var range = this.createRange();
16781 range.deleteContents();
16782 //alert(Sender.getAttribute('label'));
16784 range.insertNode(this.doc.createTextNode(txt));
16790 * Executes a Midas editor command on the editor document and performs necessary focus and
16791 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16792 * @param {String} cmd The Midas command
16793 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16795 relayCmd : function(cmd, value){
16797 this.execCmd(cmd, value);
16798 this.owner.fireEvent('editorevent', this);
16799 //this.updateToolbar();
16800 this.owner.deferFocus();
16804 * Executes a Midas editor command directly on the editor document.
16805 * For visual commands, you should use {@link #relayCmd} instead.
16806 * <b>This should only be called after the editor is initialized.</b>
16807 * @param {String} cmd The Midas command
16808 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16810 execCmd : function(cmd, value){
16811 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16818 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16820 * @param {String} text | dom node..
16822 insertAtCursor : function(text)
16827 if(!this.activated){
16833 var r = this.doc.selection.createRange();
16844 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16848 // from jquery ui (MIT licenced)
16850 var win = this.win;
16852 if (win.getSelection && win.getSelection().getRangeAt) {
16853 range = win.getSelection().getRangeAt(0);
16854 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16855 range.insertNode(node);
16856 } else if (win.document.selection && win.document.selection.createRange) {
16857 // no firefox support
16858 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16859 win.document.selection.createRange().pasteHTML(txt);
16861 // no firefox support
16862 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16863 this.execCmd('InsertHTML', txt);
16872 mozKeyPress : function(e){
16874 var c = e.getCharCode(), cmd;
16877 c = String.fromCharCode(c).toLowerCase();
16891 this.cleanUpPaste.defer(100, this);
16899 e.preventDefault();
16907 fixKeys : function(){ // load time branching for fastest keydown performance
16909 return function(e){
16910 var k = e.getKey(), r;
16913 r = this.doc.selection.createRange();
16916 r.pasteHTML('    ');
16923 r = this.doc.selection.createRange();
16925 var target = r.parentElement();
16926 if(!target || target.tagName.toLowerCase() != 'li'){
16928 r.pasteHTML('<br />');
16934 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16935 this.cleanUpPaste.defer(100, this);
16941 }else if(Roo.isOpera){
16942 return function(e){
16943 var k = e.getKey();
16947 this.execCmd('InsertHTML','    ');
16950 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16951 this.cleanUpPaste.defer(100, this);
16956 }else if(Roo.isSafari){
16957 return function(e){
16958 var k = e.getKey();
16962 this.execCmd('InsertText','\t');
16966 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16967 this.cleanUpPaste.defer(100, this);
16975 getAllAncestors: function()
16977 var p = this.getSelectedNode();
16980 a.push(p); // push blank onto stack..
16981 p = this.getParentElement();
16985 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16989 a.push(this.doc.body);
16993 lastSelNode : false,
16996 getSelection : function()
16998 this.assignDocWin();
16999 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17002 getSelectedNode: function()
17004 // this may only work on Gecko!!!
17006 // should we cache this!!!!
17011 var range = this.createRange(this.getSelection()).cloneRange();
17014 var parent = range.parentElement();
17016 var testRange = range.duplicate();
17017 testRange.moveToElementText(parent);
17018 if (testRange.inRange(range)) {
17021 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17024 parent = parent.parentElement;
17029 // is ancestor a text element.
17030 var ac = range.commonAncestorContainer;
17031 if (ac.nodeType == 3) {
17032 ac = ac.parentNode;
17035 var ar = ac.childNodes;
17038 var other_nodes = [];
17039 var has_other_nodes = false;
17040 for (var i=0;i<ar.length;i++) {
17041 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17044 // fullly contained node.
17046 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17051 // probably selected..
17052 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17053 other_nodes.push(ar[i]);
17057 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17062 has_other_nodes = true;
17064 if (!nodes.length && other_nodes.length) {
17065 nodes= other_nodes;
17067 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17073 createRange: function(sel)
17075 // this has strange effects when using with
17076 // top toolbar - not sure if it's a great idea.
17077 //this.editor.contentWindow.focus();
17078 if (typeof sel != "undefined") {
17080 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17082 return this.doc.createRange();
17085 return this.doc.createRange();
17088 getParentElement: function()
17091 this.assignDocWin();
17092 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17094 var range = this.createRange(sel);
17097 var p = range.commonAncestorContainer;
17098 while (p.nodeType == 3) { // text node
17109 * Range intersection.. the hard stuff...
17113 * [ -- selected range --- ]
17117 * if end is before start or hits it. fail.
17118 * if start is after end or hits it fail.
17120 * if either hits (but other is outside. - then it's not
17126 // @see http://www.thismuchiknow.co.uk/?p=64.
17127 rangeIntersectsNode : function(range, node)
17129 var nodeRange = node.ownerDocument.createRange();
17131 nodeRange.selectNode(node);
17133 nodeRange.selectNodeContents(node);
17136 var rangeStartRange = range.cloneRange();
17137 rangeStartRange.collapse(true);
17139 var rangeEndRange = range.cloneRange();
17140 rangeEndRange.collapse(false);
17142 var nodeStartRange = nodeRange.cloneRange();
17143 nodeStartRange.collapse(true);
17145 var nodeEndRange = nodeRange.cloneRange();
17146 nodeEndRange.collapse(false);
17148 return rangeStartRange.compareBoundaryPoints(
17149 Range.START_TO_START, nodeEndRange) == -1 &&
17150 rangeEndRange.compareBoundaryPoints(
17151 Range.START_TO_START, nodeStartRange) == 1;
17155 rangeCompareNode : function(range, node)
17157 var nodeRange = node.ownerDocument.createRange();
17159 nodeRange.selectNode(node);
17161 nodeRange.selectNodeContents(node);
17165 range.collapse(true);
17167 nodeRange.collapse(true);
17169 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17170 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17172 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17174 var nodeIsBefore = ss == 1;
17175 var nodeIsAfter = ee == -1;
17177 if (nodeIsBefore && nodeIsAfter)
17179 if (!nodeIsBefore && nodeIsAfter)
17180 return 1; //right trailed.
17182 if (nodeIsBefore && !nodeIsAfter)
17183 return 2; // left trailed.
17188 // private? - in a new class?
17189 cleanUpPaste : function()
17191 // cleans up the whole document..
17192 Roo.log('cleanuppaste');
17194 this.cleanUpChildren(this.doc.body);
17195 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17196 if (clean != this.doc.body.innerHTML) {
17197 this.doc.body.innerHTML = clean;
17202 cleanWordChars : function(input) {// change the chars to hex code
17203 var he = Roo.HtmlEditorCore;
17205 var output = input;
17206 Roo.each(he.swapCodes, function(sw) {
17207 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17209 output = output.replace(swapper, sw[1]);
17216 cleanUpChildren : function (n)
17218 if (!n.childNodes.length) {
17221 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17222 this.cleanUpChild(n.childNodes[i]);
17229 cleanUpChild : function (node)
17232 //console.log(node);
17233 if (node.nodeName == "#text") {
17234 // clean up silly Windows -- stuff?
17237 if (node.nodeName == "#comment") {
17238 node.parentNode.removeChild(node);
17239 // clean up silly Windows -- stuff?
17243 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17245 node.parentNode.removeChild(node);
17250 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17252 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17253 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17255 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17256 // remove_keep_children = true;
17259 if (remove_keep_children) {
17260 this.cleanUpChildren(node);
17261 // inserts everything just before this node...
17262 while (node.childNodes.length) {
17263 var cn = node.childNodes[0];
17264 node.removeChild(cn);
17265 node.parentNode.insertBefore(cn, node);
17267 node.parentNode.removeChild(node);
17271 if (!node.attributes || !node.attributes.length) {
17272 this.cleanUpChildren(node);
17276 function cleanAttr(n,v)
17279 if (v.match(/^\./) || v.match(/^\//)) {
17282 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17285 if (v.match(/^#/)) {
17288 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17289 node.removeAttribute(n);
17293 function cleanStyle(n,v)
17295 if (v.match(/expression/)) { //XSS?? should we even bother..
17296 node.removeAttribute(n);
17299 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17300 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17303 var parts = v.split(/;/);
17306 Roo.each(parts, function(p) {
17307 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17311 var l = p.split(':').shift().replace(/\s+/g,'');
17312 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17314 if ( cblack.indexOf(l) > -1) {
17315 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17316 //node.removeAttribute(n);
17320 // only allow 'c whitelisted system attributes'
17321 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17322 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17323 //node.removeAttribute(n);
17333 if (clean.length) {
17334 node.setAttribute(n, clean.join(';'));
17336 node.removeAttribute(n);
17342 for (var i = node.attributes.length-1; i > -1 ; i--) {
17343 var a = node.attributes[i];
17346 if (a.name.toLowerCase().substr(0,2)=='on') {
17347 node.removeAttribute(a.name);
17350 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17351 node.removeAttribute(a.name);
17354 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17355 cleanAttr(a.name,a.value); // fixme..
17358 if (a.name == 'style') {
17359 cleanStyle(a.name,a.value);
17362 /// clean up MS crap..
17363 // tecnically this should be a list of valid class'es..
17366 if (a.name == 'class') {
17367 if (a.value.match(/^Mso/)) {
17368 node.className = '';
17371 if (a.value.match(/body/)) {
17372 node.className = '';
17383 this.cleanUpChildren(node);
17388 * Clean up MS wordisms...
17390 cleanWord : function(node)
17393 var cleanWordChildren = function()
17395 if (!node.childNodes.length) {
17398 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17399 _t.cleanWord(node.childNodes[i]);
17405 this.cleanWord(this.doc.body);
17408 if (node.nodeName == "#text") {
17409 // clean up silly Windows -- stuff?
17412 if (node.nodeName == "#comment") {
17413 node.parentNode.removeChild(node);
17414 // clean up silly Windows -- stuff?
17418 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17419 node.parentNode.removeChild(node);
17423 // remove - but keep children..
17424 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17425 while (node.childNodes.length) {
17426 var cn = node.childNodes[0];
17427 node.removeChild(cn);
17428 node.parentNode.insertBefore(cn, node);
17430 node.parentNode.removeChild(node);
17431 cleanWordChildren();
17435 if (node.className.length) {
17437 var cn = node.className.split(/\W+/);
17439 Roo.each(cn, function(cls) {
17440 if (cls.match(/Mso[a-zA-Z]+/)) {
17445 node.className = cna.length ? cna.join(' ') : '';
17447 node.removeAttribute("class");
17451 if (node.hasAttribute("lang")) {
17452 node.removeAttribute("lang");
17455 if (node.hasAttribute("style")) {
17457 var styles = node.getAttribute("style").split(";");
17459 Roo.each(styles, function(s) {
17460 if (!s.match(/:/)) {
17463 var kv = s.split(":");
17464 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17467 // what ever is left... we allow.
17470 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17471 if (!nstyle.length) {
17472 node.removeAttribute('style');
17476 cleanWordChildren();
17480 domToHTML : function(currentElement, depth, nopadtext) {
17482 depth = depth || 0;
17483 nopadtext = nopadtext || false;
17485 if (!currentElement) {
17486 return this.domToHTML(this.doc.body);
17489 //Roo.log(currentElement);
17491 var allText = false;
17492 var nodeName = currentElement.nodeName;
17493 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17495 if (nodeName == '#text') {
17496 return currentElement.nodeValue;
17501 if (nodeName != 'BODY') {
17504 // Prints the node tagName, such as <A>, <IMG>, etc
17507 for(i = 0; i < currentElement.attributes.length;i++) {
17509 var aname = currentElement.attributes.item(i).name;
17510 if (!currentElement.attributes.item(i).value.length) {
17513 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17516 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17525 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17528 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17533 // Traverse the tree
17535 var currentElementChild = currentElement.childNodes.item(i);
17536 var allText = true;
17537 var innerHTML = '';
17539 while (currentElementChild) {
17540 // Formatting code (indent the tree so it looks nice on the screen)
17541 var nopad = nopadtext;
17542 if (lastnode == 'SPAN') {
17546 if (currentElementChild.nodeName == '#text') {
17547 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17548 if (!nopad && toadd.length > 80) {
17549 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17551 innerHTML += toadd;
17554 currentElementChild = currentElement.childNodes.item(i);
17560 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17562 // Recursively traverse the tree structure of the child node
17563 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17564 lastnode = currentElementChild.nodeName;
17566 currentElementChild=currentElement.childNodes.item(i);
17572 // The remaining code is mostly for formatting the tree
17573 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17578 ret+= "</"+tagName+">";
17584 // hide stuff that is not compatible
17598 * @event specialkey
17602 * @cfg {String} fieldClass @hide
17605 * @cfg {String} focusClass @hide
17608 * @cfg {String} autoCreate @hide
17611 * @cfg {String} inputType @hide
17614 * @cfg {String} invalidClass @hide
17617 * @cfg {String} invalidText @hide
17620 * @cfg {String} msgFx @hide
17623 * @cfg {String} validateOnBlur @hide
17627 Roo.HtmlEditorCore.white = [
17628 'area', 'br', 'img', 'input', 'hr', 'wbr',
17630 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17631 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17632 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17633 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17634 'table', 'ul', 'xmp',
17636 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17639 'dir', 'menu', 'ol', 'ul', 'dl',
17645 Roo.HtmlEditorCore.black = [
17646 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17648 'base', 'basefont', 'bgsound', 'blink', 'body',
17649 'frame', 'frameset', 'head', 'html', 'ilayer',
17650 'iframe', 'layer', 'link', 'meta', 'object',
17651 'script', 'style' ,'title', 'xml' // clean later..
17653 Roo.HtmlEditorCore.clean = [
17654 'script', 'style', 'title', 'xml'
17656 Roo.HtmlEditorCore.remove = [
17661 Roo.HtmlEditorCore.ablack = [
17665 Roo.HtmlEditorCore.aclean = [
17666 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17670 Roo.HtmlEditorCore.pwhite= [
17671 'http', 'https', 'mailto'
17674 // white listed style attributes.
17675 Roo.HtmlEditorCore.cwhite= [
17676 // 'text-align', /// default is to allow most things..
17682 // black listed style attributes.
17683 Roo.HtmlEditorCore.cblack= [
17684 // 'font-size' -- this can be set by the project
17688 Roo.HtmlEditorCore.swapCodes =[
17707 * @class Roo.bootstrap.HtmlEditor
17708 * @extends Roo.bootstrap.TextArea
17709 * Bootstrap HtmlEditor class
17712 * Create a new HtmlEditor
17713 * @param {Object} config The config object
17716 Roo.bootstrap.HtmlEditor = function(config){
17717 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17718 if (!this.toolbars) {
17719 this.toolbars = [];
17721 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17724 * @event initialize
17725 * Fires when the editor is fully initialized (including the iframe)
17726 * @param {HtmlEditor} this
17731 * Fires when the editor is first receives the focus. Any insertion must wait
17732 * until after this event.
17733 * @param {HtmlEditor} this
17737 * @event beforesync
17738 * Fires before the textarea is updated with content from the editor iframe. Return false
17739 * to cancel the sync.
17740 * @param {HtmlEditor} this
17741 * @param {String} html
17745 * @event beforepush
17746 * Fires before the iframe editor is updated with content from the textarea. Return false
17747 * to cancel the push.
17748 * @param {HtmlEditor} this
17749 * @param {String} html
17754 * Fires when the textarea is updated with content from the editor iframe.
17755 * @param {HtmlEditor} this
17756 * @param {String} html
17761 * Fires when the iframe editor is updated with content from the textarea.
17762 * @param {HtmlEditor} this
17763 * @param {String} html
17767 * @event editmodechange
17768 * Fires when the editor switches edit modes
17769 * @param {HtmlEditor} this
17770 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17772 editmodechange: true,
17774 * @event editorevent
17775 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17776 * @param {HtmlEditor} this
17780 * @event firstfocus
17781 * Fires when on first focus - needed by toolbars..
17782 * @param {HtmlEditor} this
17787 * Auto save the htmlEditor value as a file into Events
17788 * @param {HtmlEditor} this
17792 * @event savedpreview
17793 * preview the saved version of htmlEditor
17794 * @param {HtmlEditor} this
17801 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17805 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17810 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17815 * @cfg {Number} height (in pixels)
17819 * @cfg {Number} width (in pixels)
17824 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17827 stylesheets: false,
17832 // private properties
17833 validationEvent : false,
17835 initialized : false,
17838 onFocus : Roo.emptyFn,
17840 hideMode:'offsets',
17843 tbContainer : false,
17845 toolbarContainer :function() {
17846 return this.wrap.select('.x-html-editor-tb',true).first();
17850 * Protected method that will not generally be called directly. It
17851 * is called when the editor creates its toolbar. Override this method if you need to
17852 * add custom toolbar buttons.
17853 * @param {HtmlEditor} editor
17855 createToolbar : function(){
17857 Roo.log("create toolbars");
17859 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17860 this.toolbars[0].render(this.toolbarContainer());
17864 // if (!editor.toolbars || !editor.toolbars.length) {
17865 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17868 // for (var i =0 ; i < editor.toolbars.length;i++) {
17869 // editor.toolbars[i] = Roo.factory(
17870 // typeof(editor.toolbars[i]) == 'string' ?
17871 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17872 // Roo.bootstrap.HtmlEditor);
17873 // editor.toolbars[i].init(editor);
17879 onRender : function(ct, position)
17881 // Roo.log("Call onRender: " + this.xtype);
17883 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17885 this.wrap = this.inputEl().wrap({
17886 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17889 this.editorcore.onRender(ct, position);
17891 if (this.resizable) {
17892 this.resizeEl = new Roo.Resizable(this.wrap, {
17896 minHeight : this.height,
17897 height: this.height,
17898 handles : this.resizable,
17901 resize : function(r, w, h) {
17902 _t.onResize(w,h); // -something
17908 this.createToolbar(this);
17911 if(!this.width && this.resizable){
17912 this.setSize(this.wrap.getSize());
17914 if (this.resizeEl) {
17915 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17916 // should trigger onReize..
17922 onResize : function(w, h)
17924 Roo.log('resize: ' +w + ',' + h );
17925 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17929 if(this.inputEl() ){
17930 if(typeof w == 'number'){
17931 var aw = w - this.wrap.getFrameWidth('lr');
17932 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17935 if(typeof h == 'number'){
17936 var tbh = -11; // fixme it needs to tool bar size!
17937 for (var i =0; i < this.toolbars.length;i++) {
17938 // fixme - ask toolbars for heights?
17939 tbh += this.toolbars[i].el.getHeight();
17940 //if (this.toolbars[i].footer) {
17941 // tbh += this.toolbars[i].footer.el.getHeight();
17949 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17950 ah -= 5; // knock a few pixes off for look..
17951 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17955 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17956 this.editorcore.onResize(ew,eh);
17961 * Toggles the editor between standard and source edit mode.
17962 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17964 toggleSourceEdit : function(sourceEditMode)
17966 this.editorcore.toggleSourceEdit(sourceEditMode);
17968 if(this.editorcore.sourceEditMode){
17969 Roo.log('editor - showing textarea');
17972 // Roo.log(this.syncValue());
17974 this.inputEl().removeClass(['hide', 'x-hidden']);
17975 this.inputEl().dom.removeAttribute('tabIndex');
17976 this.inputEl().focus();
17978 Roo.log('editor - hiding textarea');
17980 // Roo.log(this.pushValue());
17983 this.inputEl().addClass(['hide', 'x-hidden']);
17984 this.inputEl().dom.setAttribute('tabIndex', -1);
17985 //this.deferFocus();
17988 if(this.resizable){
17989 this.setSize(this.wrap.getSize());
17992 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17995 // private (for BoxComponent)
17996 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17998 // private (for BoxComponent)
17999 getResizeEl : function(){
18003 // private (for BoxComponent)
18004 getPositionEl : function(){
18009 initEvents : function(){
18010 this.originalValue = this.getValue();
18014 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18017 // markInvalid : Roo.emptyFn,
18019 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18022 // clearInvalid : Roo.emptyFn,
18024 setValue : function(v){
18025 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18026 this.editorcore.pushValue();
18031 deferFocus : function(){
18032 this.focus.defer(10, this);
18036 focus : function(){
18037 this.editorcore.focus();
18043 onDestroy : function(){
18049 for (var i =0; i < this.toolbars.length;i++) {
18050 // fixme - ask toolbars for heights?
18051 this.toolbars[i].onDestroy();
18054 this.wrap.dom.innerHTML = '';
18055 this.wrap.remove();
18060 onFirstFocus : function(){
18061 //Roo.log("onFirstFocus");
18062 this.editorcore.onFirstFocus();
18063 for (var i =0; i < this.toolbars.length;i++) {
18064 this.toolbars[i].onFirstFocus();
18070 syncValue : function()
18072 this.editorcore.syncValue();
18075 pushValue : function()
18077 this.editorcore.pushValue();
18081 // hide stuff that is not compatible
18095 * @event specialkey
18099 * @cfg {String} fieldClass @hide
18102 * @cfg {String} focusClass @hide
18105 * @cfg {String} autoCreate @hide
18108 * @cfg {String} inputType @hide
18111 * @cfg {String} invalidClass @hide
18114 * @cfg {String} invalidText @hide
18117 * @cfg {String} msgFx @hide
18120 * @cfg {String} validateOnBlur @hide
18129 Roo.namespace('Roo.bootstrap.htmleditor');
18131 * @class Roo.bootstrap.HtmlEditorToolbar1
18136 new Roo.bootstrap.HtmlEditor({
18139 new Roo.bootstrap.HtmlEditorToolbar1({
18140 disable : { fonts: 1 , format: 1, ..., ... , ...],
18146 * @cfg {Object} disable List of elements to disable..
18147 * @cfg {Array} btns List of additional buttons.
18151 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18154 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18157 Roo.apply(this, config);
18159 // default disabled, based on 'good practice'..
18160 this.disable = this.disable || {};
18161 Roo.applyIf(this.disable, {
18164 specialElements : true
18166 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18168 this.editor = config.editor;
18169 this.editorcore = config.editor.editorcore;
18171 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18173 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18174 // dont call parent... till later.
18176 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18181 editorcore : false,
18186 "h1","h2","h3","h4","h5","h6",
18188 "abbr", "acronym", "address", "cite", "samp", "var",
18192 onRender : function(ct, position)
18194 // Roo.log("Call onRender: " + this.xtype);
18196 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18198 this.el.dom.style.marginBottom = '0';
18200 var editorcore = this.editorcore;
18201 var editor= this.editor;
18204 var btn = function(id,cmd , toggle, handler){
18206 var event = toggle ? 'toggle' : 'click';
18211 xns: Roo.bootstrap,
18214 enableToggle:toggle !== false,
18216 pressed : toggle ? false : null,
18219 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18220 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18229 xns: Roo.bootstrap,
18230 glyphicon : 'font',
18234 xns: Roo.bootstrap,
18238 Roo.each(this.formats, function(f) {
18239 style.menu.items.push({
18241 xns: Roo.bootstrap,
18242 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18247 editorcore.insertTag(this.tagname);
18254 children.push(style);
18257 btn('bold',false,true);
18258 btn('italic',false,true);
18259 btn('align-left', 'justifyleft',true);
18260 btn('align-center', 'justifycenter',true);
18261 btn('align-right' , 'justifyright',true);
18262 btn('link', false, false, function(btn) {
18263 //Roo.log("create link?");
18264 var url = prompt(this.createLinkText, this.defaultLinkValue);
18265 if(url && url != 'http:/'+'/'){
18266 this.editorcore.relayCmd('createlink', url);
18269 btn('list','insertunorderedlist',true);
18270 btn('pencil', false,true, function(btn){
18273 this.toggleSourceEdit(btn.pressed);
18279 xns: Roo.bootstrap,
18284 xns: Roo.bootstrap,
18289 cog.menu.items.push({
18291 xns: Roo.bootstrap,
18292 html : Clean styles,
18297 editorcore.insertTag(this.tagname);
18306 this.xtype = 'NavSimplebar';
18308 for(var i=0;i< children.length;i++) {
18310 this.buttons.add(this.addxtypeChild(children[i]));
18314 editor.on('editorevent', this.updateToolbar, this);
18316 onBtnClick : function(id)
18318 this.editorcore.relayCmd(id);
18319 this.editorcore.focus();
18323 * Protected method that will not generally be called directly. It triggers
18324 * a toolbar update by reading the markup state of the current selection in the editor.
18326 updateToolbar: function(){
18328 if(!this.editorcore.activated){
18329 this.editor.onFirstFocus(); // is this neeed?
18333 var btns = this.buttons;
18334 var doc = this.editorcore.doc;
18335 btns.get('bold').setActive(doc.queryCommandState('bold'));
18336 btns.get('italic').setActive(doc.queryCommandState('italic'));
18337 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18339 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18340 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18341 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18343 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18344 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18347 var ans = this.editorcore.getAllAncestors();
18348 if (this.formatCombo) {
18351 var store = this.formatCombo.store;
18352 this.formatCombo.setValue("");
18353 for (var i =0; i < ans.length;i++) {
18354 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18356 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18364 // hides menus... - so this cant be on a menu...
18365 Roo.bootstrap.MenuMgr.hideAll();
18367 Roo.bootstrap.MenuMgr.hideAll();
18368 //this.editorsyncValue();
18370 onFirstFocus: function() {
18371 this.buttons.each(function(item){
18375 toggleSourceEdit : function(sourceEditMode){
18378 if(sourceEditMode){
18379 Roo.log("disabling buttons");
18380 this.buttons.each( function(item){
18381 if(item.cmd != 'pencil'){
18387 Roo.log("enabling buttons");
18388 if(this.editorcore.initialized){
18389 this.buttons.each( function(item){
18395 Roo.log("calling toggole on editor");
18396 // tell the editor that it's been pressed..
18397 this.editor.toggleSourceEdit(sourceEditMode);
18407 * @class Roo.bootstrap.Table.AbstractSelectionModel
18408 * @extends Roo.util.Observable
18409 * Abstract base class for grid SelectionModels. It provides the interface that should be
18410 * implemented by descendant classes. This class should not be directly instantiated.
18413 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18414 this.locked = false;
18415 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18419 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18420 /** @ignore Called by the grid automatically. Do not call directly. */
18421 init : function(grid){
18427 * Locks the selections.
18430 this.locked = true;
18434 * Unlocks the selections.
18436 unlock : function(){
18437 this.locked = false;
18441 * Returns true if the selections are locked.
18442 * @return {Boolean}
18444 isLocked : function(){
18445 return this.locked;
18449 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18450 * @class Roo.bootstrap.Table.RowSelectionModel
18451 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18452 * It supports multiple selections and keyboard selection/navigation.
18454 * @param {Object} config
18457 Roo.bootstrap.Table.RowSelectionModel = function(config){
18458 Roo.apply(this, config);
18459 this.selections = new Roo.util.MixedCollection(false, function(o){
18464 this.lastActive = false;
18468 * @event selectionchange
18469 * Fires when the selection changes
18470 * @param {SelectionModel} this
18472 "selectionchange" : true,
18474 * @event afterselectionchange
18475 * Fires after the selection changes (eg. by key press or clicking)
18476 * @param {SelectionModel} this
18478 "afterselectionchange" : true,
18480 * @event beforerowselect
18481 * Fires when a row is selected being selected, return false to cancel.
18482 * @param {SelectionModel} this
18483 * @param {Number} rowIndex The selected index
18484 * @param {Boolean} keepExisting False if other selections will be cleared
18486 "beforerowselect" : true,
18489 * Fires when a row is selected.
18490 * @param {SelectionModel} this
18491 * @param {Number} rowIndex The selected index
18492 * @param {Roo.data.Record} r The record
18494 "rowselect" : true,
18496 * @event rowdeselect
18497 * Fires when a row is deselected.
18498 * @param {SelectionModel} this
18499 * @param {Number} rowIndex The selected index
18501 "rowdeselect" : true
18503 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18504 this.locked = false;
18507 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18509 * @cfg {Boolean} singleSelect
18510 * True to allow selection of only one row at a time (defaults to false)
18512 singleSelect : false,
18515 initEvents : function(){
18517 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18518 this.grid.on("mousedown", this.handleMouseDown, this);
18519 }else{ // allow click to work like normal
18520 this.grid.on("rowclick", this.handleDragableRowClick, this);
18523 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18524 "up" : function(e){
18526 this.selectPrevious(e.shiftKey);
18527 }else if(this.last !== false && this.lastActive !== false){
18528 var last = this.last;
18529 this.selectRange(this.last, this.lastActive-1);
18530 this.grid.getView().focusRow(this.lastActive);
18531 if(last !== false){
18535 this.selectFirstRow();
18537 this.fireEvent("afterselectionchange", this);
18539 "down" : function(e){
18541 this.selectNext(e.shiftKey);
18542 }else if(this.last !== false && this.lastActive !== false){
18543 var last = this.last;
18544 this.selectRange(this.last, this.lastActive+1);
18545 this.grid.getView().focusRow(this.lastActive);
18546 if(last !== false){
18550 this.selectFirstRow();
18552 this.fireEvent("afterselectionchange", this);
18557 var view = this.grid.view;
18558 view.on("refresh", this.onRefresh, this);
18559 view.on("rowupdated", this.onRowUpdated, this);
18560 view.on("rowremoved", this.onRemove, this);
18564 onRefresh : function(){
18565 var ds = this.grid.dataSource, i, v = this.grid.view;
18566 var s = this.selections;
18567 s.each(function(r){
18568 if((i = ds.indexOfId(r.id)) != -1){
18577 onRemove : function(v, index, r){
18578 this.selections.remove(r);
18582 onRowUpdated : function(v, index, r){
18583 if(this.isSelected(r)){
18584 v.onRowSelect(index);
18590 * @param {Array} records The records to select
18591 * @param {Boolean} keepExisting (optional) True to keep existing selections
18593 selectRecords : function(records, keepExisting){
18595 this.clearSelections();
18597 var ds = this.grid.dataSource;
18598 for(var i = 0, len = records.length; i < len; i++){
18599 this.selectRow(ds.indexOf(records[i]), true);
18604 * Gets the number of selected rows.
18607 getCount : function(){
18608 return this.selections.length;
18612 * Selects the first row in the grid.
18614 selectFirstRow : function(){
18619 * Select the last row.
18620 * @param {Boolean} keepExisting (optional) True to keep existing selections
18622 selectLastRow : function(keepExisting){
18623 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18627 * Selects the row immediately following the last selected row.
18628 * @param {Boolean} keepExisting (optional) True to keep existing selections
18630 selectNext : function(keepExisting){
18631 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18632 this.selectRow(this.last+1, keepExisting);
18633 this.grid.getView().focusRow(this.last);
18638 * Selects the row that precedes the last selected row.
18639 * @param {Boolean} keepExisting (optional) True to keep existing selections
18641 selectPrevious : function(keepExisting){
18643 this.selectRow(this.last-1, keepExisting);
18644 this.grid.getView().focusRow(this.last);
18649 * Returns the selected records
18650 * @return {Array} Array of selected records
18652 getSelections : function(){
18653 return [].concat(this.selections.items);
18657 * Returns the first selected record.
18660 getSelected : function(){
18661 return this.selections.itemAt(0);
18666 * Clears all selections.
18668 clearSelections : function(fast){
18669 if(this.locked) return;
18671 var ds = this.grid.dataSource;
18672 var s = this.selections;
18673 s.each(function(r){
18674 this.deselectRow(ds.indexOfId(r.id));
18678 this.selections.clear();
18685 * Selects all rows.
18687 selectAll : function(){
18688 if(this.locked) return;
18689 this.selections.clear();
18690 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18691 this.selectRow(i, true);
18696 * Returns True if there is a selection.
18697 * @return {Boolean}
18699 hasSelection : function(){
18700 return this.selections.length > 0;
18704 * Returns True if the specified row is selected.
18705 * @param {Number/Record} record The record or index of the record to check
18706 * @return {Boolean}
18708 isSelected : function(index){
18709 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18710 return (r && this.selections.key(r.id) ? true : false);
18714 * Returns True if the specified record id is selected.
18715 * @param {String} id The id of record to check
18716 * @return {Boolean}
18718 isIdSelected : function(id){
18719 return (this.selections.key(id) ? true : false);
18723 handleMouseDown : function(e, t){
18724 var view = this.grid.getView(), rowIndex;
18725 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18728 if(e.shiftKey && this.last !== false){
18729 var last = this.last;
18730 this.selectRange(last, rowIndex, e.ctrlKey);
18731 this.last = last; // reset the last
18732 view.focusRow(rowIndex);
18734 var isSelected = this.isSelected(rowIndex);
18735 if(e.button !== 0 && isSelected){
18736 view.focusRow(rowIndex);
18737 }else if(e.ctrlKey && isSelected){
18738 this.deselectRow(rowIndex);
18739 }else if(!isSelected){
18740 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18741 view.focusRow(rowIndex);
18744 this.fireEvent("afterselectionchange", this);
18747 handleDragableRowClick : function(grid, rowIndex, e)
18749 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18750 this.selectRow(rowIndex, false);
18751 grid.view.focusRow(rowIndex);
18752 this.fireEvent("afterselectionchange", this);
18757 * Selects multiple rows.
18758 * @param {Array} rows Array of the indexes of the row to select
18759 * @param {Boolean} keepExisting (optional) True to keep existing selections
18761 selectRows : function(rows, keepExisting){
18763 this.clearSelections();
18765 for(var i = 0, len = rows.length; i < len; i++){
18766 this.selectRow(rows[i], true);
18771 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18772 * @param {Number} startRow The index of the first row in the range
18773 * @param {Number} endRow The index of the last row in the range
18774 * @param {Boolean} keepExisting (optional) True to retain existing selections
18776 selectRange : function(startRow, endRow, keepExisting){
18777 if(this.locked) return;
18779 this.clearSelections();
18781 if(startRow <= endRow){
18782 for(var i = startRow; i <= endRow; i++){
18783 this.selectRow(i, true);
18786 for(var i = startRow; i >= endRow; i--){
18787 this.selectRow(i, true);
18793 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18794 * @param {Number} startRow The index of the first row in the range
18795 * @param {Number} endRow The index of the last row in the range
18797 deselectRange : function(startRow, endRow, preventViewNotify){
18798 if(this.locked) return;
18799 for(var i = startRow; i <= endRow; i++){
18800 this.deselectRow(i, preventViewNotify);
18806 * @param {Number} row The index of the row to select
18807 * @param {Boolean} keepExisting (optional) True to keep existing selections
18809 selectRow : function(index, keepExisting, preventViewNotify){
18810 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18811 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18812 if(!keepExisting || this.singleSelect){
18813 this.clearSelections();
18815 var r = this.grid.dataSource.getAt(index);
18816 this.selections.add(r);
18817 this.last = this.lastActive = index;
18818 if(!preventViewNotify){
18819 this.grid.getView().onRowSelect(index);
18821 this.fireEvent("rowselect", this, index, r);
18822 this.fireEvent("selectionchange", this);
18828 * @param {Number} row The index of the row to deselect
18830 deselectRow : function(index, preventViewNotify){
18831 if(this.locked) return;
18832 if(this.last == index){
18835 if(this.lastActive == index){
18836 this.lastActive = false;
18838 var r = this.grid.dataSource.getAt(index);
18839 this.selections.remove(r);
18840 if(!preventViewNotify){
18841 this.grid.getView().onRowDeselect(index);
18843 this.fireEvent("rowdeselect", this, index);
18844 this.fireEvent("selectionchange", this);
18848 restoreLast : function(){
18850 this.last = this._last;
18855 acceptsNav : function(row, col, cm){
18856 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18860 onEditorKey : function(field, e){
18861 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18866 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18868 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18870 }else if(k == e.ENTER && !e.ctrlKey){
18874 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18876 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18878 }else if(k == e.ESC){
18882 g.startEditing(newCell[0], newCell[1]);
18887 * Ext JS Library 1.1.1
18888 * Copyright(c) 2006-2007, Ext JS, LLC.
18890 * Originally Released Under LGPL - original licence link has changed is not relivant.
18893 * <script type="text/javascript">
18897 * @class Roo.bootstrap.PagingToolbar
18899 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18901 * Create a new PagingToolbar
18902 * @param {Object} config The config object
18904 Roo.bootstrap.PagingToolbar = function(config)
18906 // old args format still supported... - xtype is prefered..
18907 // created from xtype...
18908 var ds = config.dataSource;
18909 this.toolbarItems = [];
18910 if (config.items) {
18911 this.toolbarItems = config.items;
18912 // config.items = [];
18915 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18922 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18926 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18928 * @cfg {Roo.data.Store} dataSource
18929 * The underlying data store providing the paged data
18932 * @cfg {String/HTMLElement/Element} container
18933 * container The id or element that will contain the toolbar
18936 * @cfg {Boolean} displayInfo
18937 * True to display the displayMsg (defaults to false)
18940 * @cfg {Number} pageSize
18941 * The number of records to display per page (defaults to 20)
18945 * @cfg {String} displayMsg
18946 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18948 displayMsg : 'Displaying {0} - {1} of {2}',
18950 * @cfg {String} emptyMsg
18951 * The message to display when no records are found (defaults to "No data to display")
18953 emptyMsg : 'No data to display',
18955 * Customizable piece of the default paging text (defaults to "Page")
18958 beforePageText : "Page",
18960 * Customizable piece of the default paging text (defaults to "of %0")
18963 afterPageText : "of {0}",
18965 * Customizable piece of the default paging text (defaults to "First Page")
18968 firstText : "First Page",
18970 * Customizable piece of the default paging text (defaults to "Previous Page")
18973 prevText : "Previous Page",
18975 * Customizable piece of the default paging text (defaults to "Next Page")
18978 nextText : "Next Page",
18980 * Customizable piece of the default paging text (defaults to "Last Page")
18983 lastText : "Last Page",
18985 * Customizable piece of the default paging text (defaults to "Refresh")
18988 refreshText : "Refresh",
18992 onRender : function(ct, position)
18994 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18995 this.navgroup.parentId = this.id;
18996 this.navgroup.onRender(this.el, null);
18997 // add the buttons to the navgroup
18999 if(this.displayInfo){
19000 Roo.log(this.el.select('ul.navbar-nav',true).first());
19001 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19002 this.displayEl = this.el.select('.x-paging-info', true).first();
19003 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19004 // this.displayEl = navel.el.select('span',true).first();
19010 Roo.each(_this.buttons, function(e){
19011 Roo.factory(e).onRender(_this.el, null);
19015 Roo.each(_this.toolbarItems, function(e) {
19016 _this.navgroup.addItem(e);
19019 this.first = this.navgroup.addItem({
19020 tooltip: this.firstText,
19022 icon : 'fa fa-backward',
19024 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19027 this.prev = this.navgroup.addItem({
19028 tooltip: this.prevText,
19030 icon : 'fa fa-step-backward',
19032 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19034 //this.addSeparator();
19037 var field = this.navgroup.addItem( {
19039 cls : 'x-paging-position',
19041 html : this.beforePageText +
19042 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19043 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19046 this.field = field.el.select('input', true).first();
19047 this.field.on("keydown", this.onPagingKeydown, this);
19048 this.field.on("focus", function(){this.dom.select();});
19051 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19052 //this.field.setHeight(18);
19053 //this.addSeparator();
19054 this.next = this.navgroup.addItem({
19055 tooltip: this.nextText,
19057 html : ' <i class="fa fa-step-forward">',
19059 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19061 this.last = this.navgroup.addItem({
19062 tooltip: this.lastText,
19063 icon : 'fa fa-forward',
19066 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19068 //this.addSeparator();
19069 this.loading = this.navgroup.addItem({
19070 tooltip: this.refreshText,
19071 icon: 'fa fa-refresh',
19073 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19079 updateInfo : function(){
19080 if(this.displayEl){
19081 var count = this.ds.getCount();
19082 var msg = count == 0 ?
19086 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19088 this.displayEl.update(msg);
19093 onLoad : function(ds, r, o){
19094 this.cursor = o.params ? o.params.start : 0;
19095 var d = this.getPageData(),
19099 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19100 this.field.dom.value = ap;
19101 this.first.setDisabled(ap == 1);
19102 this.prev.setDisabled(ap == 1);
19103 this.next.setDisabled(ap == ps);
19104 this.last.setDisabled(ap == ps);
19105 this.loading.enable();
19110 getPageData : function(){
19111 var total = this.ds.getTotalCount();
19114 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19115 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19120 onLoadError : function(){
19121 this.loading.enable();
19125 onPagingKeydown : function(e){
19126 var k = e.getKey();
19127 var d = this.getPageData();
19129 var v = this.field.dom.value, pageNum;
19130 if(!v || isNaN(pageNum = parseInt(v, 10))){
19131 this.field.dom.value = d.activePage;
19134 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19135 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19138 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
19140 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19141 this.field.dom.value = pageNum;
19142 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19145 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19147 var v = this.field.dom.value, pageNum;
19148 var increment = (e.shiftKey) ? 10 : 1;
19149 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19151 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19152 this.field.dom.value = d.activePage;
19155 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19157 this.field.dom.value = parseInt(v, 10) + increment;
19158 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19159 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19166 beforeLoad : function(){
19168 this.loading.disable();
19173 onClick : function(which){
19180 ds.load({params:{start: 0, limit: this.pageSize}});
19183 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19186 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19189 var total = ds.getTotalCount();
19190 var extra = total % this.pageSize;
19191 var lastStart = extra ? (total - extra) : total-this.pageSize;
19192 ds.load({params:{start: lastStart, limit: this.pageSize}});
19195 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19201 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19202 * @param {Roo.data.Store} store The data store to unbind
19204 unbind : function(ds){
19205 ds.un("beforeload", this.beforeLoad, this);
19206 ds.un("load", this.onLoad, this);
19207 ds.un("loadexception", this.onLoadError, this);
19208 ds.un("remove", this.updateInfo, this);
19209 ds.un("add", this.updateInfo, this);
19210 this.ds = undefined;
19214 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19215 * @param {Roo.data.Store} store The data store to bind
19217 bind : function(ds){
19218 ds.on("beforeload", this.beforeLoad, this);
19219 ds.on("load", this.onLoad, this);
19220 ds.on("loadexception", this.onLoadError, this);
19221 ds.on("remove", this.updateInfo, this);
19222 ds.on("add", this.updateInfo, this);
19233 * @class Roo.bootstrap.MessageBar
19234 * @extends Roo.bootstrap.Component
19235 * Bootstrap MessageBar class
19236 * @cfg {String} html contents of the MessageBar
19237 * @cfg {String} weight (info | success | warning | danger) default info
19238 * @cfg {String} beforeClass insert the bar before the given class
19239 * @cfg {Boolean} closable (true | false) default false
19240 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19243 * Create a new Element
19244 * @param {Object} config The config object
19247 Roo.bootstrap.MessageBar = function(config){
19248 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19251 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19257 beforeClass: 'bootstrap-sticky-wrap',
19259 getAutoCreate : function(){
19263 cls: 'alert alert-dismissable alert-' + this.weight,
19268 html: this.html || ''
19274 cfg.cls += ' alert-messages-fixed';
19288 onRender : function(ct, position)
19290 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19293 var cfg = Roo.apply({}, this.getAutoCreate());
19297 cfg.cls += ' ' + this.cls;
19300 cfg.style = this.style;
19302 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19304 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19307 this.el.select('>button.close').on('click', this.hide, this);
19313 if (!this.rendered) {
19319 this.fireEvent('show', this);
19325 if (!this.rendered) {
19331 this.fireEvent('hide', this);
19334 update : function()
19336 // var e = this.el.dom.firstChild;
19338 // if(this.closable){
19339 // e = e.nextSibling;
19342 // e.data = this.html || '';
19344 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19360 * @class Roo.bootstrap.Graph
19361 * @extends Roo.bootstrap.Component
19362 * Bootstrap Graph class
19366 @cfg {String} graphtype bar | vbar | pie
19367 @cfg {number} g_x coodinator | centre x (pie)
19368 @cfg {number} g_y coodinator | centre y (pie)
19369 @cfg {number} g_r radius (pie)
19370 @cfg {number} g_height height of the chart (respected by all elements in the set)
19371 @cfg {number} g_width width of the chart (respected by all elements in the set)
19372 @cfg {Object} title The title of the chart
19375 -opts (object) options for the chart
19377 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19378 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19380 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
19381 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19383 o stretch (boolean)
19385 -opts (object) options for the pie
19388 o startAngle (number)
19389 o endAngle (number)
19393 * Create a new Input
19394 * @param {Object} config The config object
19397 Roo.bootstrap.Graph = function(config){
19398 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19404 * The img click event for the img.
19405 * @param {Roo.EventObject} e
19411 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19422 //g_colors: this.colors,
19429 getAutoCreate : function(){
19440 onRender : function(ct,position){
19441 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19442 this.raphael = Raphael(this.el.dom);
19444 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19445 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19446 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19447 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19449 r.text(160, 10, "Single Series Chart").attr(txtattr);
19450 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19451 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19452 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19454 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19455 r.barchart(330, 10, 300, 220, data1);
19456 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19457 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19460 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19461 // r.barchart(30, 30, 560, 250, xdata, {
19462 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19463 // axis : "0 0 1 1",
19464 // axisxlabels : xdata
19465 // //yvalues : cols,
19468 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19470 // this.load(null,xdata,{
19471 // axis : "0 0 1 1",
19472 // axisxlabels : xdata
19477 load : function(graphtype,xdata,opts){
19478 this.raphael.clear();
19480 graphtype = this.graphtype;
19485 var r = this.raphael,
19486 fin = function () {
19487 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19489 fout = function () {
19490 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19492 pfin = function() {
19493 this.sector.stop();
19494 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19497 this.label[0].stop();
19498 this.label[0].attr({ r: 7.5 });
19499 this.label[1].attr({ "font-weight": 800 });
19502 pfout = function() {
19503 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19506 this.label[0].animate({ r: 5 }, 500, "bounce");
19507 this.label[1].attr({ "font-weight": 400 });
19513 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19516 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19519 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19520 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19522 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19529 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19534 setTitle: function(o)
19539 initEvents: function() {
19542 this.el.on('click', this.onClick, this);
19546 onClick : function(e)
19548 Roo.log('img onclick');
19549 this.fireEvent('click', this, e);
19561 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19564 * @class Roo.bootstrap.dash.NumberBox
19565 * @extends Roo.bootstrap.Component
19566 * Bootstrap NumberBox class
19567 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19568 * @cfg {String} headline Box headline
19569 * @cfg {String} content Box content
19570 * @cfg {String} icon Box icon
19571 * @cfg {String} footer Footer text
19572 * @cfg {String} fhref Footer href
19575 * Create a new NumberBox
19576 * @param {Object} config The config object
19580 Roo.bootstrap.dash.NumberBox = function(config){
19581 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19585 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19595 getAutoCreate : function(){
19599 cls : 'small-box bg-' + this.bgcolor,
19607 cls : 'roo-headline',
19608 html : this.headline
19612 cls : 'roo-content',
19613 html : this.content
19627 cls : 'ion ' + this.icon
19636 cls : 'small-box-footer',
19637 href : this.fhref || '#',
19641 cfg.cn.push(footer);
19648 onRender : function(ct,position){
19649 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19656 setHeadline: function (value)
19658 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19661 setFooter: function (value, href)
19663 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19666 this.el.select('a.small-box-footer',true).first().attr('href', href);
19671 setContent: function (value)
19673 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19676 initEvents: function()
19690 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19693 * @class Roo.bootstrap.dash.TabBox
19694 * @extends Roo.bootstrap.Component
19695 * Bootstrap TabBox class
19696 * @cfg {String} title Title of the TabBox
19697 * @cfg {String} icon Icon of the TabBox
19698 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19701 * Create a new TabBox
19702 * @param {Object} config The config object
19706 Roo.bootstrap.dash.TabBox = function(config){
19707 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19712 * When a pane is added
19713 * @param {Roo.bootstrap.dash.TabPane} pane
19720 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19726 getChildContainer : function()
19728 return this.el.select('.tab-content', true).first();
19731 getAutoCreate : function(){
19735 cls: 'pull-left header',
19743 cls: 'fa ' + this.icon
19750 cls: 'nav-tabs-custom',
19754 cls: 'nav nav-tabs pull-right',
19761 cls: 'tab-content no-padding',
19769 initEvents : function()
19771 //Roo.log('add add pane handler');
19772 this.on('addpane', this.onAddPane, this);
19775 * Updates the box title
19776 * @param {String} html to set the title to.
19778 setTitle : function(value)
19780 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19782 onAddPane : function(pane)
19784 //Roo.log('addpane');
19786 // tabs are rendere left to right..
19787 if(!this.showtabs){
19791 var ctr = this.el.select('.nav-tabs', true).first();
19794 var existing = ctr.select('.nav-tab',true);
19795 var qty = existing.getCount();;
19798 var tab = ctr.createChild({
19800 cls : 'nav-tab' + (qty ? '' : ' active'),
19808 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19811 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19813 pane.el.addClass('active');
19818 onTabClick : function(ev,un,ob,pane)
19820 //Roo.log('tab - prev default');
19821 ev.preventDefault();
19824 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19825 pane.tab.addClass('active');
19826 //Roo.log(pane.title);
19827 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19828 // technically we should have a deactivate event.. but maybe add later.
19829 // and it should not de-activate the selected tab...
19831 pane.el.addClass('active');
19832 pane.fireEvent('activate');
19847 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19849 * @class Roo.bootstrap.TabPane
19850 * @extends Roo.bootstrap.Component
19851 * Bootstrap TabPane class
19852 * @cfg {Boolean} active (false | true) Default false
19853 * @cfg {String} title title of panel
19857 * Create a new TabPane
19858 * @param {Object} config The config object
19861 Roo.bootstrap.dash.TabPane = function(config){
19862 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19868 * When a pane is activated
19869 * @param {Roo.bootstrap.dash.TabPane} pane
19876 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19881 // the tabBox that this is attached to.
19884 getAutoCreate : function()
19892 cfg.cls += ' active';
19897 initEvents : function()
19899 //Roo.log('trigger add pane handler');
19900 this.parent().fireEvent('addpane', this)
19904 * Updates the tab title
19905 * @param {String} html to set the title to.
19907 setTitle: function(str)
19913 this.tab.select('a', true).first().dom.innerHTML = str;
19930 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19933 * @class Roo.bootstrap.menu.Menu
19934 * @extends Roo.bootstrap.Component
19935 * Bootstrap Menu class - container for Menu
19936 * @cfg {String} html Text of the menu
19937 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19938 * @cfg {String} icon Font awesome icon
19939 * @cfg {String} pos Menu align to (top | bottom) default bottom
19943 * Create a new Menu
19944 * @param {Object} config The config object
19948 Roo.bootstrap.menu.Menu = function(config){
19949 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19953 * @event beforeshow
19954 * Fires before this menu is displayed
19955 * @param {Roo.bootstrap.menu.Menu} this
19959 * @event beforehide
19960 * Fires before this menu is hidden
19961 * @param {Roo.bootstrap.menu.Menu} this
19966 * Fires after this menu is displayed
19967 * @param {Roo.bootstrap.menu.Menu} this
19972 * Fires after this menu is hidden
19973 * @param {Roo.bootstrap.menu.Menu} this
19978 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19979 * @param {Roo.bootstrap.menu.Menu} this
19980 * @param {Roo.EventObject} e
19987 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19991 weight : 'default',
19996 getChildContainer : function() {
19997 if(this.isSubMenu){
20001 return this.el.select('ul.dropdown-menu', true).first();
20004 getAutoCreate : function()
20009 cls : 'roo-menu-text',
20017 cls : 'fa ' + this.icon
20028 cls : 'dropdown-button btn btn-' + this.weight,
20033 cls : 'dropdown-toggle btn btn-' + this.weight,
20043 cls : 'dropdown-menu'
20049 if(this.pos == 'top'){
20050 cfg.cls += ' dropup';
20053 if(this.isSubMenu){
20056 cls : 'dropdown-menu'
20063 onRender : function(ct, position)
20065 this.isSubMenu = ct.hasClass('dropdown-submenu');
20067 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20070 initEvents : function()
20072 if(this.isSubMenu){
20076 this.hidden = true;
20078 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20079 this.triggerEl.on('click', this.onTriggerPress, this);
20081 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20082 this.buttonEl.on('click', this.onClick, this);
20088 if(this.isSubMenu){
20092 return this.el.select('ul.dropdown-menu', true).first();
20095 onClick : function(e)
20097 this.fireEvent("click", this, e);
20100 onTriggerPress : function(e)
20102 if (this.isVisible()) {
20109 isVisible : function(){
20110 return !this.hidden;
20115 this.fireEvent("beforeshow", this);
20117 this.hidden = false;
20118 this.el.addClass('open');
20120 Roo.get(document).on("mouseup", this.onMouseUp, this);
20122 this.fireEvent("show", this);
20129 this.fireEvent("beforehide", this);
20131 this.hidden = true;
20132 this.el.removeClass('open');
20134 Roo.get(document).un("mouseup", this.onMouseUp);
20136 this.fireEvent("hide", this);
20139 onMouseUp : function()
20153 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20156 * @class Roo.bootstrap.menu.Item
20157 * @extends Roo.bootstrap.Component
20158 * Bootstrap MenuItem class
20159 * @cfg {Boolean} submenu (true | false) default false
20160 * @cfg {String} html text of the item
20161 * @cfg {String} href the link
20162 * @cfg {Boolean} disable (true | false) default false
20163 * @cfg {Boolean} preventDefault (true | false) default true
20164 * @cfg {String} icon Font awesome icon
20165 * @cfg {String} pos Submenu align to (left | right) default right
20169 * Create a new Item
20170 * @param {Object} config The config object
20174 Roo.bootstrap.menu.Item = function(config){
20175 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20179 * Fires when the mouse is hovering over this menu
20180 * @param {Roo.bootstrap.menu.Item} this
20181 * @param {Roo.EventObject} e
20186 * Fires when the mouse exits this menu
20187 * @param {Roo.bootstrap.menu.Item} this
20188 * @param {Roo.EventObject} e
20194 * The raw click event for the entire grid.
20195 * @param {Roo.EventObject} e
20201 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20206 preventDefault: true,
20211 getAutoCreate : function()
20216 cls : 'roo-menu-item-text',
20224 cls : 'fa ' + this.icon
20233 href : this.href || '#',
20240 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20244 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20246 if(this.pos == 'left'){
20247 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20254 initEvents : function()
20256 this.el.on('mouseover', this.onMouseOver, this);
20257 this.el.on('mouseout', this.onMouseOut, this);
20259 this.el.select('a', true).first().on('click', this.onClick, this);
20263 onClick : function(e)
20265 if(this.preventDefault){
20266 e.preventDefault();
20269 this.fireEvent("click", this, e);
20272 onMouseOver : function(e)
20274 if(this.submenu && this.pos == 'left'){
20275 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20278 this.fireEvent("mouseover", this, e);
20281 onMouseOut : function(e)
20283 this.fireEvent("mouseout", this, e);
20295 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20298 * @class Roo.bootstrap.menu.Separator
20299 * @extends Roo.bootstrap.Component
20300 * Bootstrap Separator class
20303 * Create a new Separator
20304 * @param {Object} config The config object
20308 Roo.bootstrap.menu.Separator = function(config){
20309 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20312 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20314 getAutoCreate : function(){