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');
192 skip_children = false;
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 Roo.log('skipping all children');
236 skip_children = true;
241 // actually if flexy:foreach is found, we really want to create
242 // multiple copies here...
244 //Roo.log(this[cntr]());
245 cn.render(this[cntr](true));
247 // then add the element..
255 if (typeof (tree.menu) != 'undefined') {
256 tree.menu.parentType = cn.xtype;
257 tree.menu.triggerEl = cn.el;
258 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
262 if (!tree.items || !tree.items.length) {
266 var items = tree.items;
269 //Roo.log(items.length);
271 if (!skip_children) {
272 for(var i =0;i < items.length;i++) {
273 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
295 * @class Roo.bootstrap.Body
296 * @extends Roo.bootstrap.Component
297 * Bootstrap Body class
301 * @param {Object} config The config object
304 Roo.bootstrap.Body = function(config){
305 Roo.bootstrap.Body.superclass.constructor.call(this, config);
306 this.el = Roo.get(document.body);
307 if (this.cls && this.cls.length) {
308 Roo.get(document.body).addClass(this.cls);
312 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
317 onRender : function(ct, position)
319 /* Roo.log("Roo.bootstrap.Body - onRender");
320 if (this.cls && this.cls.length) {
321 Roo.get(document.body).addClass(this.cls);
341 * @class Roo.bootstrap.ButtonGroup
342 * @extends Roo.bootstrap.Component
343 * Bootstrap ButtonGroup class
344 * @cfg {String} size lg | sm | xs (default empty normal)
345 * @cfg {String} align vertical | justified (default none)
346 * @cfg {String} direction up | down (default down)
347 * @cfg {Boolean} toolbar false | true
348 * @cfg {Boolean} btn true | false
353 * @param {Object} config The config object
356 Roo.bootstrap.ButtonGroup = function(config){
357 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
360 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
368 getAutoCreate : function(){
374 cfg.html = this.html || cfg.html;
385 if (['vertical','justified'].indexOf(this.align)!==-1) {
386 cfg.cls = 'btn-group-' + this.align;
388 if (this.align == 'justified') {
389 console.log(this.items);
393 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
394 cfg.cls += ' btn-group-' + this.size;
397 if (this.direction == 'up') {
398 cfg.cls += ' dropup' ;
414 * @class Roo.bootstrap.Button
415 * @extends Roo.bootstrap.Component
416 * Bootstrap Button class
417 * @cfg {String} html The button content
418 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
419 * @cfg {String} size empty | lg | sm | xs
420 * @cfg {String} tag empty | a | input | submit
421 * @cfg {String} href empty or href
422 * @cfg {Boolean} disabled false | true
423 * @cfg {Boolean} isClose false | true
424 * @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
425 * @cfg {String} badge text for badge
426 * @cfg {String} theme default (or empty) | glow
427 * @cfg {Boolean} inverse false | true
428 * @cfg {Boolean} toggle false | true
429 * @cfg {String} ontext text for on toggle state
430 * @cfg {String} offtext text for off toggle state
431 * @cfg {Boolean} defaulton true | false
432 * @cfg {Boolean} preventDefault (true | false) default true
433 * @cfg {Boolean} removeClass true | false remove the standard class..
434 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
437 * Create a new button
438 * @param {Object} config The config object
442 Roo.bootstrap.Button = function(config){
443 Roo.bootstrap.Button.superclass.constructor.call(this, config);
448 * When a butotn is pressed
449 * @param {Roo.EventObject} e
454 * After the button has been toggles
455 * @param {Roo.EventObject} e
456 * @param {boolean} pressed (also available as button.pressed)
462 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
480 preventDefault: true,
489 getAutoCreate : function(){
497 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
498 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
503 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
505 if (this.toggle == true) {
508 cls: 'slider-frame roo-button',
513 'data-off-text':'OFF',
514 cls: 'slider-button',
520 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
521 cfg.cls += ' '+this.weight;
530 cfg["aria-hidden"] = true;
532 cfg.html = "×";
538 if (this.theme==='default') {
539 cfg.cls = 'btn roo-button';
541 //if (this.parentType != 'Navbar') {
542 this.weight = this.weight.length ? this.weight : 'default';
544 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
546 cfg.cls += ' btn-' + this.weight;
548 } else if (this.theme==='glow') {
551 cfg.cls = 'btn-glow roo-button';
553 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
555 cfg.cls += ' ' + this.weight;
561 this.cls += ' inverse';
566 cfg.cls += ' active';
570 cfg.disabled = 'disabled';
574 Roo.log('changing to ul' );
576 this.glyphicon = 'caret';
579 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
581 //gsRoo.log(this.parentType);
582 if (this.parentType === 'Navbar' && !this.parent().bar) {
583 Roo.log('changing to li?');
592 href : this.href || '#'
595 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
596 cfg.cls += ' dropdown';
603 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
605 if (this.glyphicon) {
606 cfg.html = ' ' + cfg.html;
611 cls: 'glyphicon glyphicon-' + this.glyphicon
621 // cfg.cls='btn roo-button';
625 var value = cfg.html;
630 cls: 'glyphicon glyphicon-' + this.glyphicon,
649 cfg.cls += ' dropdown';
650 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
653 if (cfg.tag !== 'a' && this.href !== '') {
654 throw "Tag must be a to set href.";
655 } else if (this.href.length > 0) {
656 cfg.href = this.href;
659 if(this.removeClass){
664 cfg.target = this.target;
669 initEvents: function() {
670 // Roo.log('init events?');
671 // Roo.log(this.el.dom);
674 if (typeof (this.menu) != 'undefined') {
675 this.menu.parentType = this.xtype;
676 this.menu.triggerEl = this.el;
677 this.addxtype(Roo.apply({}, this.menu));
681 if (this.el.hasClass('roo-button')) {
682 this.el.on('click', this.onClick, this);
684 this.el.select('.roo-button').on('click', this.onClick, this);
687 if(this.removeClass){
688 this.el.on('click', this.onClick, this);
691 this.el.enableDisplayMode();
694 onClick : function(e)
700 Roo.log('button on click ');
701 if(this.preventDefault){
704 if (this.pressed === true || this.pressed === false) {
705 this.pressed = !this.pressed;
706 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
707 this.fireEvent('toggle', this, e, this.pressed);
711 this.fireEvent('click', this, e);
715 * Enables this button
719 this.disabled = false;
720 this.el.removeClass('disabled');
724 * Disable this button
728 this.disabled = true;
729 this.el.addClass('disabled');
732 * sets the active state on/off,
733 * @param {Boolean} state (optional) Force a particular state
735 setActive : function(v) {
737 this.el[v ? 'addClass' : 'removeClass']('active');
740 * toggles the current active state
742 toggleActive : function()
744 var active = this.el.hasClass('active');
745 this.setActive(!active);
749 setText : function(str)
751 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
755 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
778 * @class Roo.bootstrap.Column
779 * @extends Roo.bootstrap.Component
780 * Bootstrap Column class
781 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
782 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
783 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
784 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
785 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
786 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
787 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
788 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
791 * @cfg {Boolean} hidden (true|false) hide the element
792 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
793 * @cfg {String} fa (ban|check|...) font awesome icon
794 * @cfg {Number} fasize (1|2|....) font awsome size
796 * @cfg {String} icon (info-sign|check|...) glyphicon name
798 * @cfg {String} html content of column.
801 * Create a new Column
802 * @param {Object} config The config object
805 Roo.bootstrap.Column = function(config){
806 Roo.bootstrap.Column.superclass.constructor.call(this, config);
809 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
827 getAutoCreate : function(){
828 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
836 ['xs','sm','md','lg'].map(function(size){
837 //Roo.log( size + ':' + settings[size]);
839 if (settings[size+'off'] !== false) {
840 cfg.cls += ' col-' + settings[size+'off'] + '-offset';
843 if (settings[size] === false) {
846 Roo.log(settings[size]);
847 if (!settings[size]) { // 0 = hidden
848 cfg.cls += ' hidden-' + size;
851 cfg.cls += ' col-' + size + '-' + settings[size];
856 cfg.cls += ' hidden';
859 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
860 cfg.cls +=' alert alert-' + this.alert;
864 if (this.html.length) {
865 cfg.html = this.html;
869 if (this.fasize > 1) {
870 fasize = ' fa-' + this.fasize + 'x';
872 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
877 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
896 * @class Roo.bootstrap.Container
897 * @extends Roo.bootstrap.Component
898 * Bootstrap Container class
899 * @cfg {Boolean} jumbotron is it a jumbotron element
900 * @cfg {String} html content of element
901 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
902 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
903 * @cfg {String} header content of header (for panel)
904 * @cfg {String} footer content of footer (for panel)
905 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
906 * @cfg {String} tag (header|aside|section) type of HTML tag.
907 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
908 * @cfg {String} fa (ban|check|...) font awesome icon
909 * @cfg {String} icon (info-sign|check|...) glyphicon name
910 * @cfg {Boolean} hidden (true|false) hide the element
914 * Create a new Container
915 * @param {Object} config The config object
918 Roo.bootstrap.Container = function(config){
919 Roo.bootstrap.Container.superclass.constructor.call(this, config);
922 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
936 getChildContainer : function() {
942 if (this.panel.length) {
943 return this.el.select('.panel-body',true).first();
950 getAutoCreate : function(){
953 tag : this.tag || 'div',
957 if (this.jumbotron) {
958 cfg.cls = 'jumbotron';
963 // - this is applied by the parent..
965 // cfg.cls = this.cls + '';
968 if (this.sticky.length) {
970 var bd = Roo.get(document.body);
971 if (!bd.hasClass('bootstrap-sticky')) {
972 bd.addClass('bootstrap-sticky');
973 Roo.select('html',true).setStyle('height', '100%');
976 cfg.cls += 'bootstrap-sticky-' + this.sticky;
980 if (this.well.length) {
984 cfg.cls +=' well well-' +this.well;
993 cfg.cls += ' hidden';
997 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
998 cfg.cls +=' alert alert-' + this.alert;
1003 if (this.panel.length) {
1004 cfg.cls += ' panel panel-' + this.panel;
1006 if (this.header.length) {
1009 cls : 'panel-heading',
1012 cls : 'panel-title',
1025 if (this.footer.length) {
1027 cls : 'panel-footer',
1036 body.html = this.html || cfg.html;
1037 // prefix with the icons..
1039 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1042 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1047 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1048 cfg.cls = 'container';
1054 titleEl : function()
1056 if(!this.el || !this.panel.length || !this.header.length){
1060 return this.el.select('.panel-title',true).first();
1063 setTitle : function(v)
1065 var titleEl = this.titleEl();
1071 titleEl.dom.innerHTML = v;
1074 getTitle : function()
1077 var titleEl = this.titleEl();
1083 return titleEl.dom.innerHTML;
1097 * @class Roo.bootstrap.Img
1098 * @extends Roo.bootstrap.Component
1099 * Bootstrap Img class
1100 * @cfg {Boolean} imgResponsive false | true
1101 * @cfg {String} border rounded | circle | thumbnail
1102 * @cfg {String} src image source
1103 * @cfg {String} alt image alternative text
1104 * @cfg {String} href a tag href
1105 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1108 * Create a new Input
1109 * @param {Object} config The config object
1112 Roo.bootstrap.Img = function(config){
1113 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1119 * The img click event for the img.
1120 * @param {Roo.EventObject} e
1126 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1128 imgResponsive: true,
1134 getAutoCreate : function(){
1138 cls: (this.imgResponsive) ? 'img-responsive' : '',
1142 cfg.html = this.html || cfg.html;
1144 cfg.src = this.src || cfg.src;
1146 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1147 cfg.cls += ' img-' + this.border;
1164 a.target = this.target;
1170 return (this.href) ? a : cfg;
1173 initEvents: function() {
1176 this.el.on('click', this.onClick, this);
1180 onClick : function(e)
1182 Roo.log('img onclick');
1183 this.fireEvent('click', this, e);
1197 * @class Roo.bootstrap.Link
1198 * @extends Roo.bootstrap.Component
1199 * Bootstrap Link Class
1200 * @cfg {String} alt image alternative text
1201 * @cfg {String} href a tag href
1202 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1203 * @cfg {String} html the content of the link.
1204 * @cfg {String} anchor name for the anchor link
1206 * @cfg {Boolean} preventDefault (true | false) default false
1210 * Create a new Input
1211 * @param {Object} config The config object
1214 Roo.bootstrap.Link = function(config){
1215 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1221 * The img click event for the img.
1222 * @param {Roo.EventObject} e
1228 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1232 preventDefault: false,
1236 getAutoCreate : function()
1242 // anchor's do not require html/href...
1243 if (this.anchor === false) {
1244 cfg.html = this.html || 'html-missing';
1245 cfg.href = this.href || '#';
1247 cfg.name = this.anchor;
1248 if (this.html !== false) {
1249 cfg.html = this.html;
1251 if (this.href !== false) {
1252 cfg.href = this.href;
1256 if(this.alt !== false){
1261 if(this.target !== false) {
1262 cfg.target = this.target;
1268 initEvents: function() {
1270 if(!this.href || this.preventDefault){
1271 this.el.on('click', this.onClick, this);
1275 onClick : function(e)
1277 if(this.preventDefault){
1280 //Roo.log('img onclick');
1281 this.fireEvent('click', this, e);
1294 * @class Roo.bootstrap.Header
1295 * @extends Roo.bootstrap.Component
1296 * Bootstrap Header class
1297 * @cfg {String} html content of header
1298 * @cfg {Number} level (1|2|3|4|5|6) default 1
1301 * Create a new Header
1302 * @param {Object} config The config object
1306 Roo.bootstrap.Header = function(config){
1307 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1310 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1318 getAutoCreate : function(){
1321 tag: 'h' + (1 *this.level),
1322 html: this.html || 'fill in html'
1334 * Ext JS Library 1.1.1
1335 * Copyright(c) 2006-2007, Ext JS, LLC.
1337 * Originally Released Under LGPL - original licence link has changed is not relivant.
1340 * <script type="text/javascript">
1344 * @class Roo.bootstrap.MenuMgr
1345 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1348 Roo.bootstrap.MenuMgr = function(){
1349 var menus, active, groups = {}, attached = false, lastShow = new Date();
1351 // private - called when first menu is created
1354 active = new Roo.util.MixedCollection();
1355 Roo.get(document).addKeyListener(27, function(){
1356 if(active.length > 0){
1364 if(active && active.length > 0){
1365 var c = active.clone();
1375 if(active.length < 1){
1376 Roo.get(document).un("mouseup", onMouseDown);
1384 var last = active.last();
1385 lastShow = new Date();
1388 Roo.get(document).on("mouseup", onMouseDown);
1393 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1394 m.parentMenu.activeChild = m;
1395 }else if(last && last.isVisible()){
1396 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1401 function onBeforeHide(m){
1403 m.activeChild.hide();
1405 if(m.autoHideTimer){
1406 clearTimeout(m.autoHideTimer);
1407 delete m.autoHideTimer;
1412 function onBeforeShow(m){
1413 var pm = m.parentMenu;
1414 if(!pm && !m.allowOtherMenus){
1416 }else if(pm && pm.activeChild && active != m){
1417 pm.activeChild.hide();
1422 function onMouseDown(e){
1423 Roo.log("on MouseDown");
1424 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1432 function onBeforeCheck(mi, state){
1434 var g = groups[mi.group];
1435 for(var i = 0, l = g.length; i < l; i++){
1437 g[i].setChecked(false);
1446 * Hides all menus that are currently visible
1448 hideAll : function(){
1453 register : function(menu){
1457 menus[menu.id] = menu;
1458 menu.on("beforehide", onBeforeHide);
1459 menu.on("hide", onHide);
1460 menu.on("beforeshow", onBeforeShow);
1461 menu.on("show", onShow);
1463 if(g && menu.events["checkchange"]){
1467 groups[g].push(menu);
1468 menu.on("checkchange", onCheck);
1473 * Returns a {@link Roo.menu.Menu} object
1474 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1475 * be used to generate and return a new Menu instance.
1477 get : function(menu){
1478 if(typeof menu == "string"){ // menu id
1480 }else if(menu.events){ // menu instance
1483 /*else if(typeof menu.length == 'number'){ // array of menu items?
1484 return new Roo.bootstrap.Menu({items:menu});
1485 }else{ // otherwise, must be a config
1486 return new Roo.bootstrap.Menu(menu);
1493 unregister : function(menu){
1494 delete menus[menu.id];
1495 menu.un("beforehide", onBeforeHide);
1496 menu.un("hide", onHide);
1497 menu.un("beforeshow", onBeforeShow);
1498 menu.un("show", onShow);
1500 if(g && menu.events["checkchange"]){
1501 groups[g].remove(menu);
1502 menu.un("checkchange", onCheck);
1507 registerCheckable : function(menuItem){
1508 var g = menuItem.group;
1513 groups[g].push(menuItem);
1514 menuItem.on("beforecheckchange", onBeforeCheck);
1519 unregisterCheckable : function(menuItem){
1520 var g = menuItem.group;
1522 groups[g].remove(menuItem);
1523 menuItem.un("beforecheckchange", onBeforeCheck);
1535 * @class Roo.bootstrap.Menu
1536 * @extends Roo.bootstrap.Component
1537 * Bootstrap Menu class - container for MenuItems
1538 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1542 * @param {Object} config The config object
1546 Roo.bootstrap.Menu = function(config){
1547 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1548 if (this.registerMenu) {
1549 Roo.bootstrap.MenuMgr.register(this);
1554 * Fires before this menu is displayed
1555 * @param {Roo.menu.Menu} this
1560 * Fires before this menu is hidden
1561 * @param {Roo.menu.Menu} this
1566 * Fires after this menu is displayed
1567 * @param {Roo.menu.Menu} this
1572 * Fires after this menu is hidden
1573 * @param {Roo.menu.Menu} this
1578 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1579 * @param {Roo.menu.Menu} this
1580 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1581 * @param {Roo.EventObject} e
1586 * Fires when the mouse is hovering over this menu
1587 * @param {Roo.menu.Menu} this
1588 * @param {Roo.EventObject} e
1589 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1594 * Fires when the mouse exits this menu
1595 * @param {Roo.menu.Menu} this
1596 * @param {Roo.EventObject} e
1597 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1602 * Fires when a menu item contained in this menu is clicked
1603 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1604 * @param {Roo.EventObject} e
1608 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1611 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1615 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1618 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1620 registerMenu : true,
1622 menuItems :false, // stores the menu items..
1628 getChildContainer : function() {
1632 getAutoCreate : function(){
1634 //if (['right'].indexOf(this.align)!==-1) {
1635 // cfg.cn[1].cls += ' pull-right'
1641 cls : 'dropdown-menu' ,
1642 style : 'z-index:1000'
1646 if (this.type === 'submenu') {
1647 cfg.cls = 'submenu active';
1649 if (this.type === 'treeview') {
1650 cfg.cls = 'treeview-menu';
1655 initEvents : function() {
1657 // Roo.log("ADD event");
1658 // Roo.log(this.triggerEl.dom);
1659 this.triggerEl.on('click', this.onTriggerPress, this);
1660 this.triggerEl.addClass('dropdown-toggle');
1661 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1663 this.el.on("mouseover", this.onMouseOver, this);
1664 this.el.on("mouseout", this.onMouseOut, this);
1668 findTargetItem : function(e){
1669 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1673 //Roo.log(t); Roo.log(t.id);
1675 //Roo.log(this.menuitems);
1676 return this.menuitems.get(t.id);
1678 //return this.items.get(t.menuItemId);
1683 onClick : function(e){
1684 Roo.log("menu.onClick");
1685 var t = this.findTargetItem(e);
1691 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1692 if(t == this.activeItem && t.shouldDeactivate(e)){
1693 this.activeItem.deactivate();
1694 delete this.activeItem;
1698 this.setActiveItem(t, true);
1705 Roo.log('pass click event');
1709 this.fireEvent("click", this, t, e);
1713 onMouseOver : function(e){
1714 var t = this.findTargetItem(e);
1717 // if(t.canActivate && !t.disabled){
1718 // this.setActiveItem(t, true);
1722 this.fireEvent("mouseover", this, e, t);
1724 isVisible : function(){
1725 return !this.hidden;
1727 onMouseOut : function(e){
1728 var t = this.findTargetItem(e);
1731 // if(t == this.activeItem && t.shouldDeactivate(e)){
1732 // this.activeItem.deactivate();
1733 // delete this.activeItem;
1736 this.fireEvent("mouseout", this, e, t);
1741 * Displays this menu relative to another element
1742 * @param {String/HTMLElement/Roo.Element} element The element to align to
1743 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1744 * the element (defaults to this.defaultAlign)
1745 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1747 show : function(el, pos, parentMenu){
1748 this.parentMenu = parentMenu;
1752 this.fireEvent("beforeshow", this);
1753 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1756 * Displays this menu at a specific xy position
1757 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1758 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1760 showAt : function(xy, parentMenu, /* private: */_e){
1761 this.parentMenu = parentMenu;
1766 this.fireEvent("beforeshow", this);
1768 //xy = this.el.adjustForConstraints(xy);
1770 //this.el.setXY(xy);
1772 this.hideMenuItems();
1773 this.hidden = false;
1774 this.triggerEl.addClass('open');
1776 this.fireEvent("show", this);
1782 this.doFocus.defer(50, this);
1786 doFocus : function(){
1788 this.focusEl.focus();
1793 * Hides this menu and optionally all parent menus
1794 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1796 hide : function(deep){
1798 this.hideMenuItems();
1799 if(this.el && this.isVisible()){
1800 this.fireEvent("beforehide", this);
1801 if(this.activeItem){
1802 this.activeItem.deactivate();
1803 this.activeItem = null;
1805 this.triggerEl.removeClass('open');;
1807 this.fireEvent("hide", this);
1809 if(deep === true && this.parentMenu){
1810 this.parentMenu.hide(true);
1814 onTriggerPress : function(e)
1817 Roo.log('trigger press');
1818 //Roo.log(e.getTarget());
1819 // Roo.log(this.triggerEl.dom);
1820 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1823 if (this.isVisible()) {
1827 this.show(this.triggerEl, false, false);
1836 hideMenuItems : function()
1838 //$(backdrop).remove()
1839 Roo.select('.open',true).each(function(aa) {
1841 aa.removeClass('open');
1842 //var parent = getParent($(this))
1843 //var relatedTarget = { relatedTarget: this }
1845 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1846 //if (e.isDefaultPrevented()) return
1847 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1850 addxtypeChild : function (tree, cntr) {
1851 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1853 this.menuitems.add(comp);
1874 * @class Roo.bootstrap.MenuItem
1875 * @extends Roo.bootstrap.Component
1876 * Bootstrap MenuItem class
1877 * @cfg {String} html the menu label
1878 * @cfg {String} href the link
1879 * @cfg {Boolean} preventDefault (true | false) default true
1883 * Create a new MenuItem
1884 * @param {Object} config The config object
1888 Roo.bootstrap.MenuItem = function(config){
1889 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1894 * The raw click event for the entire grid.
1895 * @param {Roo.EventObject} e
1901 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1905 preventDefault: true,
1907 getAutoCreate : function(){
1910 cls: 'dropdown-menu-item',
1919 if (this.parent().type == 'treeview') {
1920 cfg.cls = 'treeview-menu';
1923 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1924 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1928 initEvents: function() {
1930 //this.el.select('a').on('click', this.onClick, this);
1933 onClick : function(e)
1935 Roo.log('item on click ');
1936 //if(this.preventDefault){
1937 // e.preventDefault();
1939 //this.parent().hideMenuItems();
1941 this.fireEvent('click', this, e);
1960 * @class Roo.bootstrap.MenuSeparator
1961 * @extends Roo.bootstrap.Component
1962 * Bootstrap MenuSeparator class
1965 * Create a new MenuItem
1966 * @param {Object} config The config object
1970 Roo.bootstrap.MenuSeparator = function(config){
1971 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1974 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1976 getAutoCreate : function(){
1991 <div class="modal fade">
1992 <div class="modal-dialog">
1993 <div class="modal-content">
1994 <div class="modal-header">
1995 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1996 <h4 class="modal-title">Modal title</h4>
1998 <div class="modal-body">
1999 <p>One fine body…</p>
2001 <div class="modal-footer">
2002 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2003 <button type="button" class="btn btn-primary">Save changes</button>
2005 </div><!-- /.modal-content -->
2006 </div><!-- /.modal-dialog -->
2007 </div><!-- /.modal -->
2017 * @class Roo.bootstrap.Modal
2018 * @extends Roo.bootstrap.Component
2019 * Bootstrap Modal class
2020 * @cfg {String} title Title of dialog
2021 * @cfg {Boolean} specificTitle (true|false) default false
2022 * @cfg {Array} buttons Array of buttons or standard button set..
2023 * @cfg {String} buttonPosition (left|right|center) default right
2026 * Create a new Modal Dialog
2027 * @param {Object} config The config object
2030 Roo.bootstrap.Modal = function(config){
2031 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2036 * The raw btnclick event for the button
2037 * @param {Roo.EventObject} e
2041 this.buttons = this.buttons || [];
2044 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2046 title : 'test dialog',
2053 specificTitle: false,
2055 buttonPosition: 'right',
2057 onRender : function(ct, position)
2059 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2062 var cfg = Roo.apply({}, this.getAutoCreate());
2065 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2067 //if (!cfg.name.length) {
2071 cfg.cls += ' ' + this.cls;
2074 cfg.style = this.style;
2076 this.el = Roo.get(document.body).createChild(cfg, position);
2078 //var type = this.el.dom.type;
2080 if(this.tabIndex !== undefined){
2081 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2086 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2087 this.maskEl.enableDisplayMode("block");
2089 //this.el.addClass("x-dlg-modal");
2091 if (this.buttons.length) {
2092 Roo.each(this.buttons, function(bb) {
2093 b = Roo.apply({}, bb);
2094 b.xns = b.xns || Roo.bootstrap;
2095 b.xtype = b.xtype || 'Button';
2096 if (typeof(b.listeners) == 'undefined') {
2097 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2100 var btn = Roo.factory(b);
2102 btn.onRender(this.el.select('.modal-footer div').first());
2106 // render the children.
2109 if(typeof(this.items) != 'undefined'){
2110 var items = this.items;
2113 for(var i =0;i < items.length;i++) {
2114 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2118 this.items = nitems;
2120 this.body = this.el.select('.modal-body',true).first();
2121 this.close = this.el.select('.modal-header .close', true).first();
2122 this.footer = this.el.select('.modal-footer',true).first();
2124 //this.el.addClass([this.fieldClass, this.cls]);
2127 getAutoCreate : function(){
2132 html : this.html || ''
2137 cls : 'modal-title',
2141 if(this.specificTitle){
2147 style : 'display: none',
2150 cls: "modal-dialog",
2153 cls : "modal-content",
2156 cls : 'modal-header',
2168 cls : 'modal-footer',
2172 cls: 'btn-' + this.buttonPosition
2191 getChildContainer : function() {
2193 return this.el.select('.modal-body',true).first();
2196 getButtonContainer : function() {
2197 return this.el.select('.modal-footer div',true).first();
2200 initEvents : function()
2202 this.el.select('.modal-header .close').on('click', this.hide, this);
2204 // this.addxtype(this);
2208 if (!this.rendered) {
2212 this.el.addClass('on');
2213 this.el.removeClass('fade');
2214 this.el.setStyle('display', 'block');
2215 Roo.get(document.body).addClass("x-body-masked");
2216 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2218 this.el.setStyle('zIndex', '10001');
2219 this.fireEvent('show', this);
2225 Roo.log('Modal hide?!');
2227 Roo.get(document.body).removeClass("x-body-masked");
2228 this.el.removeClass('on');
2229 this.el.addClass('fade');
2230 this.el.setStyle('display', 'none');
2231 this.fireEvent('hide', this);
2234 addButton : function(str, cb)
2238 var b = Roo.apply({}, { html : str } );
2239 b.xns = b.xns || Roo.bootstrap;
2240 b.xtype = b.xtype || 'Button';
2241 if (typeof(b.listeners) == 'undefined') {
2242 b.listeners = { click : cb.createDelegate(this) };
2245 var btn = Roo.factory(b);
2247 btn.onRender(this.el.select('.modal-footer div').first());
2253 setDefaultButton : function(btn)
2255 //this.el.select('.modal-footer').()
2257 resizeTo: function(w,h)
2261 setContentSize : function(w, h)
2265 onButtonClick: function(btn,e)
2268 this.fireEvent('btnclick', btn.name, e);
2270 setTitle: function(str) {
2271 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2277 Roo.apply(Roo.bootstrap.Modal, {
2279 * Button config that displays a single OK button
2288 * Button config that displays Yes and No buttons
2304 * Button config that displays OK and Cancel buttons
2319 * Button config that displays Yes, No and Cancel buttons
2341 * messagebox - can be used as a replace
2345 * @class Roo.MessageBox
2346 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2350 Roo.Msg.alert('Status', 'Changes saved successfully.');
2352 // Prompt for user data:
2353 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2355 // process text value...
2359 // Show a dialog using config options:
2361 title:'Save Changes?',
2362 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2363 buttons: Roo.Msg.YESNOCANCEL,
2370 Roo.bootstrap.MessageBox = function(){
2371 var dlg, opt, mask, waitTimer;
2372 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2373 var buttons, activeTextEl, bwidth;
2377 var handleButton = function(button){
2379 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2383 var handleHide = function(){
2385 dlg.el.removeClass(opt.cls);
2388 // Roo.TaskMgr.stop(waitTimer);
2389 // waitTimer = null;
2394 var updateButtons = function(b){
2397 buttons["ok"].hide();
2398 buttons["cancel"].hide();
2399 buttons["yes"].hide();
2400 buttons["no"].hide();
2401 //dlg.footer.dom.style.display = 'none';
2404 dlg.footer.dom.style.display = '';
2405 for(var k in buttons){
2406 if(typeof buttons[k] != "function"){
2409 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2410 width += buttons[k].el.getWidth()+15;
2420 var handleEsc = function(d, k, e){
2421 if(opt && opt.closable !== false){
2431 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2432 * @return {Roo.BasicDialog} The BasicDialog element
2434 getDialog : function(){
2436 dlg = new Roo.bootstrap.Modal( {
2439 //constraintoviewport:false,
2441 //collapsible : false,
2446 //buttonAlign:"center",
2447 closeClick : function(){
2448 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2451 handleButton("cancel");
2456 dlg.on("hide", handleHide);
2458 //dlg.addKeyListener(27, handleEsc);
2460 this.buttons = buttons;
2461 var bt = this.buttonText;
2462 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2463 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2464 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2465 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2467 bodyEl = dlg.body.createChild({
2469 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2470 '<textarea class="roo-mb-textarea"></textarea>' +
2471 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2473 msgEl = bodyEl.dom.firstChild;
2474 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2475 textboxEl.enableDisplayMode();
2476 textboxEl.addKeyListener([10,13], function(){
2477 if(dlg.isVisible() && opt && opt.buttons){
2480 }else if(opt.buttons.yes){
2481 handleButton("yes");
2485 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2486 textareaEl.enableDisplayMode();
2487 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2488 progressEl.enableDisplayMode();
2489 var pf = progressEl.dom.firstChild;
2491 pp = Roo.get(pf.firstChild);
2492 pp.setHeight(pf.offsetHeight);
2500 * Updates the message box body text
2501 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2502 * the XHTML-compliant non-breaking space character '&#160;')
2503 * @return {Roo.MessageBox} This message box
2505 updateText : function(text){
2506 if(!dlg.isVisible() && !opt.width){
2507 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2509 msgEl.innerHTML = text || ' ';
2511 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2512 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2514 Math.min(opt.width || cw , this.maxWidth),
2515 Math.max(opt.minWidth || this.minWidth, bwidth)
2518 activeTextEl.setWidth(w);
2520 if(dlg.isVisible()){
2521 dlg.fixedcenter = false;
2523 // to big, make it scroll. = But as usual stupid IE does not support
2526 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2527 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2528 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2530 bodyEl.dom.style.height = '';
2531 bodyEl.dom.style.overflowY = '';
2534 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2536 bodyEl.dom.style.overflowX = '';
2539 dlg.setContentSize(w, bodyEl.getHeight());
2540 if(dlg.isVisible()){
2541 dlg.fixedcenter = true;
2547 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2548 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2549 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2550 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2551 * @return {Roo.MessageBox} This message box
2553 updateProgress : function(value, text){
2555 this.updateText(text);
2557 if (pp) { // weird bug on my firefox - for some reason this is not defined
2558 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2564 * Returns true if the message box is currently displayed
2565 * @return {Boolean} True if the message box is visible, else false
2567 isVisible : function(){
2568 return dlg && dlg.isVisible();
2572 * Hides the message box if it is displayed
2575 if(this.isVisible()){
2581 * Displays a new message box, or reinitializes an existing message box, based on the config options
2582 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2583 * The following config object properties are supported:
2585 Property Type Description
2586 ---------- --------------- ------------------------------------------------------------------------------------
2587 animEl String/Element An id or Element from which the message box should animate as it opens and
2588 closes (defaults to undefined)
2589 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2590 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2591 closable Boolean False to hide the top-right close button (defaults to true). Note that
2592 progress and wait dialogs will ignore this property and always hide the
2593 close button as they can only be closed programmatically.
2594 cls String A custom CSS class to apply to the message box element
2595 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2596 displayed (defaults to 75)
2597 fn Function A callback function to execute after closing the dialog. The arguments to the
2598 function will be btn (the name of the button that was clicked, if applicable,
2599 e.g. "ok"), and text (the value of the active text field, if applicable).
2600 Progress and wait dialogs will ignore this option since they do not respond to
2601 user actions and can only be closed programmatically, so any required function
2602 should be called by the same code after it closes the dialog.
2603 icon String A CSS class that provides a background image to be used as an icon for
2604 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2605 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2606 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2607 modal Boolean False to allow user interaction with the page while the message box is
2608 displayed (defaults to true)
2609 msg String A string that will replace the existing message box body text (defaults
2610 to the XHTML-compliant non-breaking space character ' ')
2611 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2612 progress Boolean True to display a progress bar (defaults to false)
2613 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2614 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2615 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2616 title String The title text
2617 value String The string value to set into the active textbox element if displayed
2618 wait Boolean True to display a progress bar (defaults to false)
2619 width Number The width of the dialog in pixels
2626 msg: 'Please enter your address:',
2628 buttons: Roo.MessageBox.OKCANCEL,
2631 animEl: 'addAddressBtn'
2634 * @param {Object} config Configuration options
2635 * @return {Roo.MessageBox} This message box
2637 show : function(options)
2640 // this causes nightmares if you show one dialog after another
2641 // especially on callbacks..
2643 if(this.isVisible()){
2646 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2647 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2648 Roo.log("New Dialog Message:" + options.msg )
2649 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2650 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2653 var d = this.getDialog();
2655 d.setTitle(opt.title || " ");
2656 d.close.setDisplayed(opt.closable !== false);
2657 activeTextEl = textboxEl;
2658 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2663 textareaEl.setHeight(typeof opt.multiline == "number" ?
2664 opt.multiline : this.defaultTextHeight);
2665 activeTextEl = textareaEl;
2674 progressEl.setDisplayed(opt.progress === true);
2675 this.updateProgress(0);
2676 activeTextEl.dom.value = opt.value || "";
2678 dlg.setDefaultButton(activeTextEl);
2680 var bs = opt.buttons;
2684 }else if(bs && bs.yes){
2685 db = buttons["yes"];
2687 dlg.setDefaultButton(db);
2689 bwidth = updateButtons(opt.buttons);
2690 this.updateText(opt.msg);
2692 d.el.addClass(opt.cls);
2694 d.proxyDrag = opt.proxyDrag === true;
2695 d.modal = opt.modal !== false;
2696 d.mask = opt.modal !== false ? mask : false;
2698 // force it to the end of the z-index stack so it gets a cursor in FF
2699 document.body.appendChild(dlg.el.dom);
2700 d.animateTarget = null;
2701 d.show(options.animEl);
2707 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2708 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2709 * and closing the message box when the process is complete.
2710 * @param {String} title The title bar text
2711 * @param {String} msg The message box body text
2712 * @return {Roo.MessageBox} This message box
2714 progress : function(title, msg){
2721 minWidth: this.minProgressWidth,
2728 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2729 * If a callback function is passed it will be called after the user clicks the button, and the
2730 * id of the button that was clicked will be passed as the only parameter to the callback
2731 * (could also be the top-right close button).
2732 * @param {String} title The title bar text
2733 * @param {String} msg The message box body text
2734 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2735 * @param {Object} scope (optional) The scope of the callback function
2736 * @return {Roo.MessageBox} This message box
2738 alert : function(title, msg, fn, scope){
2751 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2752 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2753 * You are responsible for closing the message box when the process is complete.
2754 * @param {String} msg The message box body text
2755 * @param {String} title (optional) The title bar text
2756 * @return {Roo.MessageBox} This message box
2758 wait : function(msg, title){
2769 waitTimer = Roo.TaskMgr.start({
2771 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2779 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2780 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2781 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2782 * @param {String} title The title bar text
2783 * @param {String} msg The message box body text
2784 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2785 * @param {Object} scope (optional) The scope of the callback function
2786 * @return {Roo.MessageBox} This message box
2788 confirm : function(title, msg, fn, scope){
2792 buttons: this.YESNO,
2801 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2802 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2803 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2804 * (could also be the top-right close button) and the text that was entered will be passed as the two
2805 * parameters to the callback.
2806 * @param {String} title The title bar text
2807 * @param {String} msg The message box body text
2808 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2809 * @param {Object} scope (optional) The scope of the callback function
2810 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2811 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2812 * @return {Roo.MessageBox} This message box
2814 prompt : function(title, msg, fn, scope, multiline){
2818 buttons: this.OKCANCEL,
2823 multiline: multiline,
2830 * Button config that displays a single OK button
2835 * Button config that displays Yes and No buttons
2838 YESNO : {yes:true, no:true},
2840 * Button config that displays OK and Cancel buttons
2843 OKCANCEL : {ok:true, cancel:true},
2845 * Button config that displays Yes, No and Cancel buttons
2848 YESNOCANCEL : {yes:true, no:true, cancel:true},
2851 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2854 defaultTextHeight : 75,
2856 * The maximum width in pixels of the message box (defaults to 600)
2861 * The minimum width in pixels of the message box (defaults to 100)
2866 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2867 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2870 minProgressWidth : 250,
2872 * An object containing the default button text strings that can be overriden for localized language support.
2873 * Supported properties are: ok, cancel, yes and no.
2874 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2887 * Shorthand for {@link Roo.MessageBox}
2889 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2890 Roo.Msg = Roo.Msg || Roo.MessageBox;
2899 * @class Roo.bootstrap.Navbar
2900 * @extends Roo.bootstrap.Component
2901 * Bootstrap Navbar class
2904 * Create a new Navbar
2905 * @param {Object} config The config object
2909 Roo.bootstrap.Navbar = function(config){
2910 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2914 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2923 getAutoCreate : function(){
2926 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2930 initEvents :function ()
2932 //Roo.log(this.el.select('.navbar-toggle',true));
2933 this.el.select('.navbar-toggle',true).on('click', function() {
2934 // Roo.log('click');
2935 this.el.select('.navbar-collapse',true).toggleClass('in');
2943 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2945 var size = this.el.getSize();
2946 this.maskEl.setSize(size.width, size.height);
2947 this.maskEl.enableDisplayMode("block");
2956 getChildContainer : function()
2958 if (this.el.select('.collapse').getCount()) {
2959 return this.el.select('.collapse',true).first();
2992 * @class Roo.bootstrap.NavSimplebar
2993 * @extends Roo.bootstrap.Navbar
2994 * Bootstrap Sidebar class
2996 * @cfg {Boolean} inverse is inverted color
2998 * @cfg {String} type (nav | pills | tabs)
2999 * @cfg {Boolean} arrangement stacked | justified
3000 * @cfg {String} align (left | right) alignment
3002 * @cfg {Boolean} main (true|false) main nav bar? default false
3003 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3005 * @cfg {String} tag (header|footer|nav|div) default is nav
3011 * Create a new Sidebar
3012 * @param {Object} config The config object
3016 Roo.bootstrap.NavSimplebar = function(config){
3017 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3020 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3036 getAutoCreate : function(){
3040 tag : this.tag || 'div',
3053 this.type = this.type || 'nav';
3054 if (['tabs','pills'].indexOf(this.type)!==-1) {
3055 cfg.cn[0].cls += ' nav-' + this.type
3059 if (this.type!=='nav') {
3060 Roo.log('nav type must be nav/tabs/pills')
3062 cfg.cn[0].cls += ' navbar-nav'
3068 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3069 cfg.cn[0].cls += ' nav-' + this.arrangement;
3073 if (this.align === 'right') {
3074 cfg.cn[0].cls += ' navbar-right';
3078 cfg.cls += ' navbar-inverse';
3105 * @class Roo.bootstrap.NavHeaderbar
3106 * @extends Roo.bootstrap.NavSimplebar
3107 * Bootstrap Sidebar class
3109 * @cfg {String} brand what is brand
3110 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3111 * @cfg {String} brand_href href of the brand
3112 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3113 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3116 * Create a new Sidebar
3117 * @param {Object} config The config object
3121 Roo.bootstrap.NavHeaderbar = function(config){
3122 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3125 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3133 getAutoCreate : function(){
3136 tag: this.nav || 'nav',
3145 cls: 'navbar-header',
3150 cls: 'navbar-toggle',
3151 'data-toggle': 'collapse',
3156 html: 'Toggle navigation'
3178 cls: 'collapse navbar-collapse',
3182 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3184 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3185 cfg.cls += ' navbar-' + this.position;
3187 // tag can override this..
3189 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3192 if (this.brand !== '') {
3195 href: this.brand_href ? this.brand_href : '#',
3196 cls: 'navbar-brand',
3204 cfg.cls += ' main-nav';
3212 initEvents : function()
3214 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3216 if (this.autohide) {
3221 Roo.get(document).on('scroll',function(e) {
3222 var ns = Roo.get(document).getScroll().top;
3223 var os = prevScroll;
3227 ft.removeClass('slideDown');
3228 ft.addClass('slideUp');
3231 ft.removeClass('slideUp');
3232 ft.addClass('slideDown');
3256 * @class Roo.bootstrap.NavSidebar
3257 * @extends Roo.bootstrap.Navbar
3258 * Bootstrap Sidebar class
3261 * Create a new Sidebar
3262 * @param {Object} config The config object
3266 Roo.bootstrap.NavSidebar = function(config){
3267 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3270 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3272 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3274 getAutoCreate : function(){
3279 cls: 'sidebar sidebar-nav'
3301 * @class Roo.bootstrap.NavGroup
3302 * @extends Roo.bootstrap.Component
3303 * Bootstrap NavGroup class
3304 * @cfg {String} align left | right
3305 * @cfg {Boolean} inverse false | true
3306 * @cfg {String} type (nav|pills|tab) default nav
3307 * @cfg {String} navId - reference Id for navbar.
3311 * Create a new nav group
3312 * @param {Object} config The config object
3315 Roo.bootstrap.NavGroup = function(config){
3316 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3319 Roo.bootstrap.NavGroup.register(this);
3323 * Fires when the active item changes
3324 * @param {Roo.bootstrap.NavGroup} this
3325 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3326 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3333 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3344 getAutoCreate : function()
3346 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3353 if (['tabs','pills'].indexOf(this.type)!==-1) {
3354 cfg.cls += ' nav-' + this.type
3356 if (this.type!=='nav') {
3357 Roo.log('nav type must be nav/tabs/pills')
3359 cfg.cls += ' navbar-nav'
3362 if (this.parent().sidebar) {
3365 cls: 'dashboard-menu sidebar-menu'
3371 if (this.form === true) {
3377 if (this.align === 'right') {
3378 cfg.cls += ' navbar-right';
3380 cfg.cls += ' navbar-left';
3384 if (this.align === 'right') {
3385 cfg.cls += ' navbar-right';
3389 cfg.cls += ' navbar-inverse';
3397 * sets the active Navigation item
3398 * @param {Roo.bootstrap.NavItem} the new current navitem
3400 setActiveItem : function(item)
3403 Roo.each(this.navItems, function(v){
3408 v.setActive(false, true);
3415 item.setActive(true, true);
3416 this.fireEvent('changed', this, item, prev);
3421 * gets the active Navigation item
3422 * @return {Roo.bootstrap.NavItem} the current navitem
3424 getActive : function()
3428 Roo.each(this.navItems, function(v){
3439 indexOfNav : function()
3443 Roo.each(this.navItems, function(v,i){
3454 * adds a Navigation item
3455 * @param {Roo.bootstrap.NavItem} the navitem to add
3457 addItem : function(cfg)
3459 var cn = new Roo.bootstrap.NavItem(cfg);
3461 cn.parentId = this.id;
3462 cn.onRender(this.el, null);
3466 * register a Navigation item
3467 * @param {Roo.bootstrap.NavItem} the navitem to add
3469 register : function(item)
3471 this.navItems.push( item);
3472 item.navId = this.navId;
3477 getNavItem: function(tabId)
3480 Roo.each(this.navItems, function(e) {
3481 if (e.tabId == tabId) {
3491 setActiveNext : function()
3493 var i = this.indexOfNav(this.getActive());
3494 if (i > this.navItems.length) {
3497 this.setActiveItem(this.navItems[i+1]);
3499 setActivePrev : function()
3501 var i = this.indexOfNav(this.getActive());
3505 this.setActiveItem(this.navItems[i-1]);
3507 clearWasActive : function(except) {
3508 Roo.each(this.navItems, function(e) {
3509 if (e.tabId != except.tabId && e.was_active) {
3510 e.was_active = false;
3517 getWasActive : function ()
3520 Roo.each(this.navItems, function(e) {
3535 Roo.apply(Roo.bootstrap.NavGroup, {
3539 * register a Navigation Group
3540 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3542 register : function(navgrp)
3544 this.groups[navgrp.navId] = navgrp;
3548 * fetch a Navigation Group based on the navigation ID
3549 * @param {string} the navgroup to add
3550 * @returns {Roo.bootstrap.NavGroup} the navgroup
3552 get: function(navId) {
3553 if (typeof(this.groups[navId]) == 'undefined') {
3555 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3557 return this.groups[navId] ;
3572 * @class Roo.bootstrap.NavItem
3573 * @extends Roo.bootstrap.Component
3574 * Bootstrap Navbar.NavItem class
3575 * @cfg {String} href link to
3576 * @cfg {String} html content of button
3577 * @cfg {String} badge text inside badge
3578 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3579 * @cfg {String} glyphicon name of glyphicon
3580 * @cfg {String} icon name of font awesome icon
3581 * @cfg {Boolean} active Is item active
3582 * @cfg {Boolean} disabled Is item disabled
3584 * @cfg {Boolean} preventDefault (true | false) default false
3585 * @cfg {String} tabId the tab that this item activates.
3586 * @cfg {String} tagtype (a|span) render as a href or span?
3589 * Create a new Navbar Item
3590 * @param {Object} config The config object
3592 Roo.bootstrap.NavItem = function(config){
3593 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3598 * The raw click event for the entire grid.
3599 * @param {Roo.EventObject} e
3604 * Fires when the active item active state changes
3605 * @param {Roo.bootstrap.NavItem} this
3606 * @param {boolean} state the new state
3614 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3622 preventDefault : false,
3629 getAutoCreate : function(){
3637 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3639 if (this.disabled) {
3640 cfg.cls += ' disabled';
3643 if (this.href || this.html || this.glyphicon || this.icon) {
3647 href : this.href || "#",
3648 html: this.html || ''
3653 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3656 if(this.glyphicon) {
3657 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3662 cfg.cn[0].html += " <span class='caret'></span>";
3666 if (this.badge !== '') {
3668 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3676 initEvents: function() {
3677 // Roo.log('init events?');
3678 // Roo.log(this.el.dom);
3679 if (typeof (this.menu) != 'undefined') {
3680 this.menu.parentType = this.xtype;
3681 this.menu.triggerEl = this.el;
3682 this.addxtype(Roo.apply({}, this.menu));
3686 this.el.select('a',true).on('click', this.onClick, this);
3687 // at this point parent should be available..
3688 this.parent().register(this);
3691 onClick : function(e)
3694 if(this.preventDefault){
3697 if (this.disabled) {
3701 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3702 if (tg && tg.transition) {
3703 Roo.log("waiting for the transitionend");
3707 Roo.log("fire event clicked");
3708 if(this.fireEvent('click', this, e) === false){
3711 var p = this.parent();
3712 if (['tabs','pills'].indexOf(p.type)!==-1) {
3713 if (typeof(p.setActiveItem) !== 'undefined') {
3714 p.setActiveItem(this);
3717 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3718 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3719 // remove the collapsed menu expand...
3720 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3725 isActive: function () {
3728 setActive : function(state, fire, is_was_active)
3730 if (this.active && !state & this.navId) {
3731 this.was_active = true;
3732 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3734 nv.clearWasActive(this);
3738 this.active = state;
3741 this.el.removeClass('active');
3742 } else if (!this.el.hasClass('active')) {
3743 this.el.addClass('active');
3746 this.fireEvent('changed', this, state);
3749 // show a panel if it's registered and related..
3751 if (!this.navId || !this.tabId || !state || is_was_active) {
3755 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3759 var pan = tg.getPanelByName(this.tabId);
3763 // if we can not flip to new panel - go back to old nav highlight..
3764 if (false == tg.showPanel(pan)) {
3765 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3767 var onav = nv.getWasActive();
3769 onav.setActive(true, false, true);
3778 // this should not be here...
3779 setDisabled : function(state)
3781 this.disabled = state;
3783 this.el.removeClass('disabled');
3784 } else if (!this.el.hasClass('disabled')) {
3785 this.el.addClass('disabled');
3798 * <span> icon </span>
3799 * <span> text </span>
3800 * <span>badge </span>
3804 * @class Roo.bootstrap.NavSidebarItem
3805 * @extends Roo.bootstrap.NavItem
3806 * Bootstrap Navbar.NavSidebarItem class
3808 * Create a new Navbar Button
3809 * @param {Object} config The config object
3811 Roo.bootstrap.NavSidebarItem = function(config){
3812 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3817 * The raw click event for the entire grid.
3818 * @param {Roo.EventObject} e
3823 * Fires when the active item active state changes
3824 * @param {Roo.bootstrap.NavSidebarItem} this
3825 * @param {boolean} state the new state
3833 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3836 getAutoCreate : function(){
3841 href : this.href || '#',
3853 html : this.html || ''
3858 cfg.cls += ' active';
3862 if (this.glyphicon || this.icon) {
3863 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3864 a.cn.push({ tag : 'i', cls : c }) ;
3869 if (this.badge !== '') {
3870 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3874 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3875 a.cls += 'dropdown-toggle treeview' ;
3899 * @class Roo.bootstrap.Row
3900 * @extends Roo.bootstrap.Component
3901 * Bootstrap Row class (contains columns...)
3905 * @param {Object} config The config object
3908 Roo.bootstrap.Row = function(config){
3909 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3912 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3914 getAutoCreate : function(){
3933 * @class Roo.bootstrap.Element
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap Element class
3936 * @cfg {String} html contents of the element
3937 * @cfg {String} tag tag of the element
3938 * @cfg {String} cls class of the element
3941 * Create a new Element
3942 * @param {Object} config The config object
3945 Roo.bootstrap.Element = function(config){
3946 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3949 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3956 getAutoCreate : function(){
3981 * @class Roo.bootstrap.Pagination
3982 * @extends Roo.bootstrap.Component
3983 * Bootstrap Pagination class
3984 * @cfg {String} size xs | sm | md | lg
3985 * @cfg {Boolean} inverse false | true
3988 * Create a new Pagination
3989 * @param {Object} config The config object
3992 Roo.bootstrap.Pagination = function(config){
3993 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3996 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4002 getAutoCreate : function(){
4008 cfg.cls += ' inverse';
4014 cfg.cls += " " + this.cls;
4032 * @class Roo.bootstrap.PaginationItem
4033 * @extends Roo.bootstrap.Component
4034 * Bootstrap PaginationItem class
4035 * @cfg {String} html text
4036 * @cfg {String} href the link
4037 * @cfg {Boolean} preventDefault (true | false) default true
4038 * @cfg {Boolean} active (true | false) default false
4042 * Create a new PaginationItem
4043 * @param {Object} config The config object
4047 Roo.bootstrap.PaginationItem = function(config){
4048 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4053 * The raw click event for the entire grid.
4054 * @param {Roo.EventObject} e
4060 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4064 preventDefault: true,
4068 getAutoCreate : function(){
4074 href : this.href ? this.href : '#',
4075 html : this.html ? this.html : ''
4085 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4091 initEvents: function() {
4093 this.el.on('click', this.onClick, this);
4096 onClick : function(e)
4098 Roo.log('PaginationItem on click ');
4099 if(this.preventDefault){
4103 this.fireEvent('click', this, e);
4119 * @class Roo.bootstrap.Slider
4120 * @extends Roo.bootstrap.Component
4121 * Bootstrap Slider class
4124 * Create a new Slider
4125 * @param {Object} config The config object
4128 Roo.bootstrap.Slider = function(config){
4129 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4132 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4134 getAutoCreate : function(){
4138 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4142 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4154 * Ext JS Library 1.1.1
4155 * Copyright(c) 2006-2007, Ext JS, LLC.
4157 * Originally Released Under LGPL - original licence link has changed is not relivant.
4160 * <script type="text/javascript">
4165 * @class Roo.grid.ColumnModel
4166 * @extends Roo.util.Observable
4167 * This is the default implementation of a ColumnModel used by the Grid. It defines
4168 * the columns in the grid.
4171 var colModel = new Roo.grid.ColumnModel([
4172 {header: "Ticker", width: 60, sortable: true, locked: true},
4173 {header: "Company Name", width: 150, sortable: true},
4174 {header: "Market Cap.", width: 100, sortable: true},
4175 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4176 {header: "Employees", width: 100, sortable: true, resizable: false}
4181 * The config options listed for this class are options which may appear in each
4182 * individual column definition.
4183 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4185 * @param {Object} config An Array of column config objects. See this class's
4186 * config objects for details.
4188 Roo.grid.ColumnModel = function(config){
4190 * The config passed into the constructor
4192 this.config = config;
4195 // if no id, create one
4196 // if the column does not have a dataIndex mapping,
4197 // map it to the order it is in the config
4198 for(var i = 0, len = config.length; i < len; i++){
4200 if(typeof c.dataIndex == "undefined"){
4203 if(typeof c.renderer == "string"){
4204 c.renderer = Roo.util.Format[c.renderer];
4206 if(typeof c.id == "undefined"){
4209 if(c.editor && c.editor.xtype){
4210 c.editor = Roo.factory(c.editor, Roo.grid);
4212 if(c.editor && c.editor.isFormField){
4213 c.editor = new Roo.grid.GridEditor(c.editor);
4215 this.lookup[c.id] = c;
4219 * The width of columns which have no width specified (defaults to 100)
4222 this.defaultWidth = 100;
4225 * Default sortable of columns which have no sortable specified (defaults to false)
4228 this.defaultSortable = false;
4232 * @event widthchange
4233 * Fires when the width of a column changes.
4234 * @param {ColumnModel} this
4235 * @param {Number} columnIndex The column index
4236 * @param {Number} newWidth The new width
4238 "widthchange": true,
4240 * @event headerchange
4241 * Fires when the text of a header changes.
4242 * @param {ColumnModel} this
4243 * @param {Number} columnIndex The column index
4244 * @param {Number} newText The new header text
4246 "headerchange": true,
4248 * @event hiddenchange
4249 * Fires when a column is hidden or "unhidden".
4250 * @param {ColumnModel} this
4251 * @param {Number} columnIndex The column index
4252 * @param {Boolean} hidden true if hidden, false otherwise
4254 "hiddenchange": true,
4256 * @event columnmoved
4257 * Fires when a column is moved.
4258 * @param {ColumnModel} this
4259 * @param {Number} oldIndex
4260 * @param {Number} newIndex
4262 "columnmoved" : true,
4264 * @event columlockchange
4265 * Fires when a column's locked state is changed
4266 * @param {ColumnModel} this
4267 * @param {Number} colIndex
4268 * @param {Boolean} locked true if locked
4270 "columnlockchange" : true
4272 Roo.grid.ColumnModel.superclass.constructor.call(this);
4274 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4276 * @cfg {String} header The header text to display in the Grid view.
4279 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4280 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4281 * specified, the column's index is used as an index into the Record's data Array.
4284 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4285 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4288 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4289 * Defaults to the value of the {@link #defaultSortable} property.
4290 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4293 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4296 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4299 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4302 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4305 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4306 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4307 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4308 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4311 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4314 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4318 * Returns the id of the column at the specified index.
4319 * @param {Number} index The column index
4320 * @return {String} the id
4322 getColumnId : function(index){
4323 return this.config[index].id;
4327 * Returns the column for a specified id.
4328 * @param {String} id The column id
4329 * @return {Object} the column
4331 getColumnById : function(id){
4332 return this.lookup[id];
4337 * Returns the column for a specified dataIndex.
4338 * @param {String} dataIndex The column dataIndex
4339 * @return {Object|Boolean} the column or false if not found
4341 getColumnByDataIndex: function(dataIndex){
4342 var index = this.findColumnIndex(dataIndex);
4343 return index > -1 ? this.config[index] : false;
4347 * Returns the index for a specified column id.
4348 * @param {String} id The column id
4349 * @return {Number} the index, or -1 if not found
4351 getIndexById : function(id){
4352 for(var i = 0, len = this.config.length; i < len; i++){
4353 if(this.config[i].id == id){
4361 * Returns the index for a specified column dataIndex.
4362 * @param {String} dataIndex The column dataIndex
4363 * @return {Number} the index, or -1 if not found
4366 findColumnIndex : function(dataIndex){
4367 for(var i = 0, len = this.config.length; i < len; i++){
4368 if(this.config[i].dataIndex == dataIndex){
4376 moveColumn : function(oldIndex, newIndex){
4377 var c = this.config[oldIndex];
4378 this.config.splice(oldIndex, 1);
4379 this.config.splice(newIndex, 0, c);
4380 this.dataMap = null;
4381 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4384 isLocked : function(colIndex){
4385 return this.config[colIndex].locked === true;
4388 setLocked : function(colIndex, value, suppressEvent){
4389 if(this.isLocked(colIndex) == value){
4392 this.config[colIndex].locked = value;
4394 this.fireEvent("columnlockchange", this, colIndex, value);
4398 getTotalLockedWidth : function(){
4400 for(var i = 0; i < this.config.length; i++){
4401 if(this.isLocked(i) && !this.isHidden(i)){
4402 this.totalWidth += this.getColumnWidth(i);
4408 getLockedCount : function(){
4409 for(var i = 0, len = this.config.length; i < len; i++){
4410 if(!this.isLocked(i)){
4417 * Returns the number of columns.
4420 getColumnCount : function(visibleOnly){
4421 if(visibleOnly === true){
4423 for(var i = 0, len = this.config.length; i < len; i++){
4424 if(!this.isHidden(i)){
4430 return this.config.length;
4434 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4435 * @param {Function} fn
4436 * @param {Object} scope (optional)
4437 * @return {Array} result
4439 getColumnsBy : function(fn, scope){
4441 for(var i = 0, len = this.config.length; i < len; i++){
4442 var c = this.config[i];
4443 if(fn.call(scope||this, c, i) === true){
4451 * Returns true if the specified column is sortable.
4452 * @param {Number} col The column index
4455 isSortable : function(col){
4456 if(typeof this.config[col].sortable == "undefined"){
4457 return this.defaultSortable;
4459 return this.config[col].sortable;
4463 * Returns the rendering (formatting) function defined for the column.
4464 * @param {Number} col The column index.
4465 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4467 getRenderer : function(col){
4468 if(!this.config[col].renderer){
4469 return Roo.grid.ColumnModel.defaultRenderer;
4471 return this.config[col].renderer;
4475 * Sets the rendering (formatting) function for a column.
4476 * @param {Number} col The column index
4477 * @param {Function} fn The function to use to process the cell's raw data
4478 * to return HTML markup for the grid view. The render function is called with
4479 * the following parameters:<ul>
4480 * <li>Data value.</li>
4481 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4482 * <li>css A CSS style string to apply to the table cell.</li>
4483 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4484 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4485 * <li>Row index</li>
4486 * <li>Column index</li>
4487 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4489 setRenderer : function(col, fn){
4490 this.config[col].renderer = fn;
4494 * Returns the width for the specified column.
4495 * @param {Number} col The column index
4498 getColumnWidth : function(col){
4499 return this.config[col].width * 1 || this.defaultWidth;
4503 * Sets the width for a column.
4504 * @param {Number} col The column index
4505 * @param {Number} width The new width
4507 setColumnWidth : function(col, width, suppressEvent){
4508 this.config[col].width = width;
4509 this.totalWidth = null;
4511 this.fireEvent("widthchange", this, col, width);
4516 * Returns the total width of all columns.
4517 * @param {Boolean} includeHidden True to include hidden column widths
4520 getTotalWidth : function(includeHidden){
4521 if(!this.totalWidth){
4522 this.totalWidth = 0;
4523 for(var i = 0, len = this.config.length; i < len; i++){
4524 if(includeHidden || !this.isHidden(i)){
4525 this.totalWidth += this.getColumnWidth(i);
4529 return this.totalWidth;
4533 * Returns the header for the specified column.
4534 * @param {Number} col The column index
4537 getColumnHeader : function(col){
4538 return this.config[col].header;
4542 * Sets the header for a column.
4543 * @param {Number} col The column index
4544 * @param {String} header The new header
4546 setColumnHeader : function(col, header){
4547 this.config[col].header = header;
4548 this.fireEvent("headerchange", this, col, header);
4552 * Returns the tooltip for the specified column.
4553 * @param {Number} col The column index
4556 getColumnTooltip : function(col){
4557 return this.config[col].tooltip;
4560 * Sets the tooltip for a column.
4561 * @param {Number} col The column index
4562 * @param {String} tooltip The new tooltip
4564 setColumnTooltip : function(col, tooltip){
4565 this.config[col].tooltip = tooltip;
4569 * Returns the dataIndex for the specified column.
4570 * @param {Number} col The column index
4573 getDataIndex : function(col){
4574 return this.config[col].dataIndex;
4578 * Sets the dataIndex for a column.
4579 * @param {Number} col The column index
4580 * @param {Number} dataIndex The new dataIndex
4582 setDataIndex : function(col, dataIndex){
4583 this.config[col].dataIndex = dataIndex;
4589 * Returns true if the cell is editable.
4590 * @param {Number} colIndex The column index
4591 * @param {Number} rowIndex The row index
4594 isCellEditable : function(colIndex, rowIndex){
4595 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4599 * Returns the editor defined for the cell/column.
4600 * return false or null to disable editing.
4601 * @param {Number} colIndex The column index
4602 * @param {Number} rowIndex The row index
4605 getCellEditor : function(colIndex, rowIndex){
4606 return this.config[colIndex].editor;
4610 * Sets if a column is editable.
4611 * @param {Number} col The column index
4612 * @param {Boolean} editable True if the column is editable
4614 setEditable : function(col, editable){
4615 this.config[col].editable = editable;
4620 * Returns true if the column is hidden.
4621 * @param {Number} colIndex The column index
4624 isHidden : function(colIndex){
4625 return this.config[colIndex].hidden;
4630 * Returns true if the column width cannot be changed
4632 isFixed : function(colIndex){
4633 return this.config[colIndex].fixed;
4637 * Returns true if the column can be resized
4640 isResizable : function(colIndex){
4641 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4644 * Sets if a column is hidden.
4645 * @param {Number} colIndex The column index
4646 * @param {Boolean} hidden True if the column is hidden
4648 setHidden : function(colIndex, hidden){
4649 this.config[colIndex].hidden = hidden;
4650 this.totalWidth = null;
4651 this.fireEvent("hiddenchange", this, colIndex, hidden);
4655 * Sets the editor for a column.
4656 * @param {Number} col The column index
4657 * @param {Object} editor The editor object
4659 setEditor : function(col, editor){
4660 this.config[col].editor = editor;
4664 Roo.grid.ColumnModel.defaultRenderer = function(value){
4665 if(typeof value == "string" && value.length < 1){
4671 // Alias for backwards compatibility
4672 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4675 * Ext JS Library 1.1.1
4676 * Copyright(c) 2006-2007, Ext JS, LLC.
4678 * Originally Released Under LGPL - original licence link has changed is not relivant.
4681 * <script type="text/javascript">
4685 * @class Roo.LoadMask
4686 * A simple utility class for generically masking elements while loading data. If the element being masked has
4687 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4688 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4689 * element's UpdateManager load indicator and will be destroyed after the initial load.
4691 * Create a new LoadMask
4692 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4693 * @param {Object} config The config object
4695 Roo.LoadMask = function(el, config){
4696 this.el = Roo.get(el);
4697 Roo.apply(this, config);
4699 this.store.on('beforeload', this.onBeforeLoad, this);
4700 this.store.on('load', this.onLoad, this);
4701 this.store.on('loadexception', this.onLoadException, this);
4702 this.removeMask = false;
4704 var um = this.el.getUpdateManager();
4705 um.showLoadIndicator = false; // disable the default indicator
4706 um.on('beforeupdate', this.onBeforeLoad, this);
4707 um.on('update', this.onLoad, this);
4708 um.on('failure', this.onLoad, this);
4709 this.removeMask = true;
4713 Roo.LoadMask.prototype = {
4715 * @cfg {Boolean} removeMask
4716 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4717 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4721 * The text to display in a centered loading message box (defaults to 'Loading...')
4725 * @cfg {String} msgCls
4726 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4728 msgCls : 'x-mask-loading',
4731 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4737 * Disables the mask to prevent it from being displayed
4739 disable : function(){
4740 this.disabled = true;
4744 * Enables the mask so that it can be displayed
4746 enable : function(){
4747 this.disabled = false;
4750 onLoadException : function()
4754 if (typeof(arguments[3]) != 'undefined') {
4755 Roo.MessageBox.alert("Error loading",arguments[3]);
4759 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4760 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4769 this.el.unmask(this.removeMask);
4774 this.el.unmask(this.removeMask);
4778 onBeforeLoad : function(){
4780 this.el.mask(this.msg, this.msgCls);
4785 destroy : function(){
4787 this.store.un('beforeload', this.onBeforeLoad, this);
4788 this.store.un('load', this.onLoad, this);
4789 this.store.un('loadexception', this.onLoadException, this);
4791 var um = this.el.getUpdateManager();
4792 um.un('beforeupdate', this.onBeforeLoad, this);
4793 um.un('update', this.onLoad, this);
4794 um.un('failure', this.onLoad, this);
4805 * @class Roo.bootstrap.Table
4806 * @extends Roo.bootstrap.Component
4807 * Bootstrap Table class
4808 * @cfg {String} cls table class
4809 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4810 * @cfg {String} bgcolor Specifies the background color for a table
4811 * @cfg {Number} border Specifies whether the table cells should have borders or not
4812 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4813 * @cfg {Number} cellspacing Specifies the space between cells
4814 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4815 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4816 * @cfg {String} sortable Specifies that the table should be sortable
4817 * @cfg {String} summary Specifies a summary of the content of a table
4818 * @cfg {Number} width Specifies the width of a table
4819 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4821 * @cfg {boolean} striped Should the rows be alternative striped
4822 * @cfg {boolean} bordered Add borders to the table
4823 * @cfg {boolean} hover Add hover highlighting
4824 * @cfg {boolean} condensed Format condensed
4825 * @cfg {boolean} responsive Format condensed
4826 * @cfg {Boolean} loadMask (true|false) default false
4827 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4828 * @cfg {Boolean} thead (true|false) generate thead, default true
4829 * @cfg {Boolean} RowSelection (true|false) default false
4830 * @cfg {Boolean} CellSelection (true|false) default false
4832 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4836 * Create a new Table
4837 * @param {Object} config The config object
4840 Roo.bootstrap.Table = function(config){
4841 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4844 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4845 this.sm = this.selModel;
4846 this.sm.xmodule = this.xmodule || false;
4848 if (this.cm && typeof(this.cm.config) == 'undefined') {
4849 this.colModel = new Roo.grid.ColumnModel(this.cm);
4850 this.cm = this.colModel;
4851 this.cm.xmodule = this.xmodule || false;
4854 this.store= Roo.factory(this.store, Roo.data);
4855 this.ds = this.store;
4856 this.ds.xmodule = this.xmodule || false;
4859 if (this.footer && this.store) {
4860 this.footer.dataSource = this.ds;
4861 this.footer = Roo.factory(this.footer);
4868 * Fires when a cell is clicked
4869 * @param {Roo.bootstrap.Table} this
4870 * @param {Roo.Element} el
4871 * @param {Number} rowIndex
4872 * @param {Number} columnIndex
4873 * @param {Roo.EventObject} e
4877 * @event celldblclick
4878 * Fires when a cell is double clicked
4879 * @param {Roo.bootstrap.Table} this
4880 * @param {Roo.Element} el
4881 * @param {Number} rowIndex
4882 * @param {Number} columnIndex
4883 * @param {Roo.EventObject} e
4885 "celldblclick" : true,
4888 * Fires when a row is clicked
4889 * @param {Roo.bootstrap.Table} this
4890 * @param {Roo.Element} el
4891 * @param {Number} rowIndex
4892 * @param {Roo.EventObject} e
4896 * @event rowdblclick
4897 * Fires when a row is double clicked
4898 * @param {Roo.bootstrap.Table} this
4899 * @param {Roo.Element} el
4900 * @param {Number} rowIndex
4901 * @param {Roo.EventObject} e
4903 "rowdblclick" : true,
4906 * Fires when a mouseover occur
4907 * @param {Roo.bootstrap.Table} this
4908 * @param {Roo.Element} el
4909 * @param {Number} rowIndex
4910 * @param {Number} columnIndex
4911 * @param {Roo.EventObject} e
4916 * Fires when a mouseout occur
4917 * @param {Roo.bootstrap.Table} this
4918 * @param {Roo.Element} el
4919 * @param {Number} rowIndex
4920 * @param {Number} columnIndex
4921 * @param {Roo.EventObject} e
4926 * Fires when a row is rendered, so you can change add a style to it.
4927 * @param {Roo.bootstrap.Table} this
4928 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4935 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4959 RowSelection : false,
4960 CellSelection : false,
4963 // Roo.Element - the tbody
4966 getAutoCreate : function(){
4967 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4976 cfg.cls += ' table-striped';
4980 cfg.cls += ' table-hover';
4982 if (this.bordered) {
4983 cfg.cls += ' table-bordered';
4985 if (this.condensed) {
4986 cfg.cls += ' table-condensed';
4988 if (this.responsive) {
4989 cfg.cls += ' table-responsive';
4993 cfg.cls+= ' ' +this.cls;
4996 // this lot should be simplifed...
4999 cfg.align=this.align;
5002 cfg.bgcolor=this.bgcolor;
5005 cfg.border=this.border;
5007 if (this.cellpadding) {
5008 cfg.cellpadding=this.cellpadding;
5010 if (this.cellspacing) {
5011 cfg.cellspacing=this.cellspacing;
5014 cfg.frame=this.frame;
5017 cfg.rules=this.rules;
5019 if (this.sortable) {
5020 cfg.sortable=this.sortable;
5023 cfg.summary=this.summary;
5026 cfg.width=this.width;
5029 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5032 if(this.store || this.cm){
5034 cfg.cn.push(this.renderHeader());
5037 cfg.cn.push(this.renderBody());
5040 cfg.cn.push(this.renderFooter());
5043 cfg.cls+= ' TableGrid';
5046 return { cn : [ cfg ] };
5049 initEvents : function()
5051 if(!this.store || !this.cm){
5055 //Roo.log('initEvents with ds!!!!');
5057 this.mainBody = this.el.select('tbody', true).first();
5062 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5063 e.on('click', _this.sort, _this);
5066 this.el.on("click", this.onClick, this);
5067 this.el.on("dblclick", this.onDblClick, this);
5069 this.parent().el.setStyle('position', 'relative');
5071 this.footer.parentId = this.id;
5072 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5075 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5077 this.store.on('load', this.onLoad, this);
5078 this.store.on('beforeload', this.onBeforeLoad, this);
5079 this.store.on('update', this.onUpdate, this);
5083 onMouseover : function(e, el)
5085 var cell = Roo.get(el);
5091 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5092 cell = cell.findParent('td', false, true);
5095 var row = cell.findParent('tr', false, true);
5096 var cellIndex = cell.dom.cellIndex;
5097 var rowIndex = row.dom.rowIndex - 1; // start from 0
5099 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5103 onMouseout : function(e, el)
5105 var cell = Roo.get(el);
5111 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5112 cell = cell.findParent('td', false, true);
5115 var row = cell.findParent('tr', false, true);
5116 var cellIndex = cell.dom.cellIndex;
5117 var rowIndex = row.dom.rowIndex - 1; // start from 0
5119 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5123 onClick : function(e, el)
5125 var cell = Roo.get(el);
5127 if(!cell || (!this.CellSelection && !this.RowSelection)){
5132 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5133 cell = cell.findParent('td', false, true);
5136 var row = cell.findParent('tr', false, true);
5137 var cellIndex = cell.dom.cellIndex;
5138 var rowIndex = row.dom.rowIndex - 1;
5140 if(this.CellSelection){
5141 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5144 if(this.RowSelection){
5145 this.fireEvent('rowclick', this, row, rowIndex, e);
5151 onDblClick : function(e,el)
5153 var cell = Roo.get(el);
5155 if(!cell || (!this.CellSelection && !this.RowSelection)){
5159 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5160 cell = cell.findParent('td', false, true);
5163 var row = cell.findParent('tr', false, true);
5164 var cellIndex = cell.dom.cellIndex;
5165 var rowIndex = row.dom.rowIndex - 1;
5167 if(this.CellSelection){
5168 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5171 if(this.RowSelection){
5172 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5176 sort : function(e,el)
5178 var col = Roo.get(el)
5180 if(!col.hasClass('sortable')){
5184 var sort = col.attr('sort');
5187 if(col.hasClass('glyphicon-arrow-up')){
5191 this.store.sortInfo = {field : sort, direction : dir};
5194 Roo.log("calling footer first");
5195 this.footer.onClick('first');
5198 this.store.load({ params : { start : 0 } });
5202 renderHeader : function()
5211 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5213 var config = cm.config[i];
5218 html: cm.getColumnHeader(i)
5221 if(typeof(config.hidden) != 'undefined' && config.hidden){
5222 c.style += ' display:none;';
5225 if(typeof(config.dataIndex) != 'undefined'){
5226 c.sort = config.dataIndex;
5229 if(typeof(config.sortable) != 'undefined' && config.sortable){
5233 if(typeof(config.align) != 'undefined' && config.align.length){
5234 c.style += ' text-align:' + config.align + ';';
5237 if(typeof(config.width) != 'undefined'){
5238 c.style += ' width:' + config.width + 'px;';
5247 renderBody : function()
5257 colspan : this.cm.getColumnCount()
5267 renderFooter : function()
5277 colspan : this.cm.getColumnCount()
5291 Roo.log('ds onload');
5296 var ds = this.store;
5298 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5299 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5301 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5302 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5305 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5306 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5310 var tbody = this.mainBody;
5312 if(ds.getCount() > 0){
5313 ds.data.each(function(d,rowIndex){
5314 var row = this.renderRow(cm, ds, rowIndex);
5316 tbody.createChild(row);
5320 if(row.cellObjects.length){
5321 Roo.each(row.cellObjects, function(r){
5322 _this.renderCellObject(r);
5329 Roo.each(this.el.select('tbody td', true).elements, function(e){
5330 e.on('mouseover', _this.onMouseover, _this);
5333 Roo.each(this.el.select('tbody td', true).elements, function(e){
5334 e.on('mouseout', _this.onMouseout, _this);
5337 //if(this.loadMask){
5338 // this.maskEl.hide();
5343 onUpdate : function(ds,record)
5345 this.refreshRow(record);
5347 onRemove : function(ds, record, index, isUpdate){
5348 if(isUpdate !== true){
5349 this.fireEvent("beforerowremoved", this, index, record);
5351 var bt = this.mainBody.dom;
5353 bt.removeChild(bt.rows[index]);
5356 if(isUpdate !== true){
5357 //this.stripeRows(index);
5358 //this.syncRowHeights(index, index);
5360 this.fireEvent("rowremoved", this, index, record);
5365 refreshRow : function(record){
5366 var ds = this.store, index;
5367 if(typeof record == 'number'){
5369 record = ds.getAt(index);
5371 index = ds.indexOf(record);
5373 this.insertRow(ds, index, true);
5374 this.onRemove(ds, record, index+1, true);
5375 //this.syncRowHeights(index, index);
5377 this.fireEvent("rowupdated", this, index, record);
5380 insertRow : function(dm, rowIndex, isUpdate){
5383 this.fireEvent("beforerowsinserted", this, rowIndex);
5385 //var s = this.getScrollState();
5386 var row = this.renderRow(this.cm, this.store, rowIndex);
5387 // insert before rowIndex..
5388 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5392 if(row.cellObjects.length){
5393 Roo.each(row.cellObjects, function(r){
5394 _this.renderCellObject(r);
5399 this.fireEvent("rowsinserted", this, rowIndex);
5400 //this.syncRowHeights(firstRow, lastRow);
5401 //this.stripeRows(firstRow);
5408 getRowDom : function(rowIndex)
5410 // not sure if I need to check this.. but let's do it anyway..
5411 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5412 this.mainBody.dom.rows[rowIndex] : false
5414 // returns the object tree for a tr..
5417 renderRow : function(cm, ds, rowIndex) {
5419 var d = ds.getAt(rowIndex);
5426 var cellObjects = [];
5428 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5429 var config = cm.config[i];
5431 var renderer = cm.getRenderer(i);
5435 if(typeof(renderer) !== 'undefined'){
5436 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5438 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5439 // and are rendered into the cells after the row is rendered - using the id for the element.
5441 if(typeof(value) === 'object'){
5451 rowIndex : rowIndex,
5456 this.fireEvent('rowclass', this, rowcfg);
5460 cls : rowcfg.rowClass,
5462 html: (typeof(value) === 'object') ? '' : value
5469 if(typeof(config.hidden) != 'undefined' && config.hidden){
5470 td.style += ' display:none;';
5473 if(typeof(config.align) != 'undefined' && config.align.length){
5474 td.style += ' text-align:' + config.align + ';';
5477 if(typeof(config.width) != 'undefined'){
5478 td.style += ' width:' + config.width + 'px;';
5485 row.cellObjects = cellObjects;
5493 onBeforeLoad : function()
5495 //Roo.log('ds onBeforeLoad');
5499 //if(this.loadMask){
5500 // this.maskEl.show();
5506 this.el.select('tbody', true).first().dom.innerHTML = '';
5509 getSelectionModel : function(){
5511 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5513 return this.selModel;
5516 * Render the Roo.bootstrap object from renderder
5518 renderCellObject : function(r)
5522 var t = r.cfg.render(r.container);
5525 Roo.each(r.cfg.cn, function(c){
5527 container: t.getChildContainer(),
5530 _this.renderCellObject(child);
5547 * @class Roo.bootstrap.TableCell
5548 * @extends Roo.bootstrap.Component
5549 * Bootstrap TableCell class
5550 * @cfg {String} html cell contain text
5551 * @cfg {String} cls cell class
5552 * @cfg {String} tag cell tag (td|th) default td
5553 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5554 * @cfg {String} align Aligns the content in a cell
5555 * @cfg {String} axis Categorizes cells
5556 * @cfg {String} bgcolor Specifies the background color of a cell
5557 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5558 * @cfg {Number} colspan Specifies the number of columns a cell should span
5559 * @cfg {String} headers Specifies one or more header cells a cell is related to
5560 * @cfg {Number} height Sets the height of a cell
5561 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5562 * @cfg {Number} rowspan Sets the number of rows a cell should span
5563 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5564 * @cfg {String} valign Vertical aligns the content in a cell
5565 * @cfg {Number} width Specifies the width of a cell
5568 * Create a new TableCell
5569 * @param {Object} config The config object
5572 Roo.bootstrap.TableCell = function(config){
5573 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5576 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5596 getAutoCreate : function(){
5597 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5617 cfg.align=this.align
5623 cfg.bgcolor=this.bgcolor
5626 cfg.charoff=this.charoff
5629 cfg.colspan=this.colspan
5632 cfg.headers=this.headers
5635 cfg.height=this.height
5638 cfg.nowrap=this.nowrap
5641 cfg.rowspan=this.rowspan
5644 cfg.scope=this.scope
5647 cfg.valign=this.valign
5650 cfg.width=this.width
5669 * @class Roo.bootstrap.TableRow
5670 * @extends Roo.bootstrap.Component
5671 * Bootstrap TableRow class
5672 * @cfg {String} cls row class
5673 * @cfg {String} align Aligns the content in a table row
5674 * @cfg {String} bgcolor Specifies a background color for a table row
5675 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5676 * @cfg {String} valign Vertical aligns the content in a table row
5679 * Create a new TableRow
5680 * @param {Object} config The config object
5683 Roo.bootstrap.TableRow = function(config){
5684 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5687 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5695 getAutoCreate : function(){
5696 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5706 cfg.align = this.align;
5709 cfg.bgcolor = this.bgcolor;
5712 cfg.charoff = this.charoff;
5715 cfg.valign = this.valign;
5733 * @class Roo.bootstrap.TableBody
5734 * @extends Roo.bootstrap.Component
5735 * Bootstrap TableBody class
5736 * @cfg {String} cls element class
5737 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5738 * @cfg {String} align Aligns the content inside the element
5739 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5740 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5743 * Create a new TableBody
5744 * @param {Object} config The config object
5747 Roo.bootstrap.TableBody = function(config){
5748 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5751 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5759 getAutoCreate : function(){
5760 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5774 cfg.align = this.align;
5777 cfg.charoff = this.charoff;
5780 cfg.valign = this.valign;
5787 // initEvents : function()
5794 // this.store = Roo.factory(this.store, Roo.data);
5795 // this.store.on('load', this.onLoad, this);
5797 // this.store.load();
5801 // onLoad: function ()
5803 // this.fireEvent('load', this);
5813 * Ext JS Library 1.1.1
5814 * Copyright(c) 2006-2007, Ext JS, LLC.
5816 * Originally Released Under LGPL - original licence link has changed is not relivant.
5819 * <script type="text/javascript">
5822 // as we use this in bootstrap.
5823 Roo.namespace('Roo.form');
5825 * @class Roo.form.Action
5826 * Internal Class used to handle form actions
5828 * @param {Roo.form.BasicForm} el The form element or its id
5829 * @param {Object} config Configuration options
5834 // define the action interface
5835 Roo.form.Action = function(form, options){
5837 this.options = options || {};
5840 * Client Validation Failed
5843 Roo.form.Action.CLIENT_INVALID = 'client';
5845 * Server Validation Failed
5848 Roo.form.Action.SERVER_INVALID = 'server';
5850 * Connect to Server Failed
5853 Roo.form.Action.CONNECT_FAILURE = 'connect';
5855 * Reading Data from Server Failed
5858 Roo.form.Action.LOAD_FAILURE = 'load';
5860 Roo.form.Action.prototype = {
5862 failureType : undefined,
5863 response : undefined,
5867 run : function(options){
5872 success : function(response){
5877 handleResponse : function(response){
5881 // default connection failure
5882 failure : function(response){
5884 this.response = response;
5885 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5886 this.form.afterAction(this, false);
5889 processResponse : function(response){
5890 this.response = response;
5891 if(!response.responseText){
5894 this.result = this.handleResponse(response);
5898 // utility functions used internally
5899 getUrl : function(appendParams){
5900 var url = this.options.url || this.form.url || this.form.el.dom.action;
5902 var p = this.getParams();
5904 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5910 getMethod : function(){
5911 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5914 getParams : function(){
5915 var bp = this.form.baseParams;
5916 var p = this.options.params;
5918 if(typeof p == "object"){
5919 p = Roo.urlEncode(Roo.applyIf(p, bp));
5920 }else if(typeof p == 'string' && bp){
5921 p += '&' + Roo.urlEncode(bp);
5924 p = Roo.urlEncode(bp);
5929 createCallback : function(){
5931 success: this.success,
5932 failure: this.failure,
5934 timeout: (this.form.timeout*1000),
5935 upload: this.form.fileUpload ? this.success : undefined
5940 Roo.form.Action.Submit = function(form, options){
5941 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5944 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5947 haveProgress : false,
5948 uploadComplete : false,
5950 // uploadProgress indicator.
5951 uploadProgress : function()
5953 if (!this.form.progressUrl) {
5957 if (!this.haveProgress) {
5958 Roo.MessageBox.progress("Uploading", "Uploading");
5960 if (this.uploadComplete) {
5961 Roo.MessageBox.hide();
5965 this.haveProgress = true;
5967 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5969 var c = new Roo.data.Connection();
5971 url : this.form.progressUrl,
5976 success : function(req){
5977 //console.log(data);
5981 rdata = Roo.decode(req.responseText)
5983 Roo.log("Invalid data from server..");
5987 if (!rdata || !rdata.success) {
5989 Roo.MessageBox.alert(Roo.encode(rdata));
5992 var data = rdata.data;
5994 if (this.uploadComplete) {
5995 Roo.MessageBox.hide();
6000 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6001 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6004 this.uploadProgress.defer(2000,this);
6007 failure: function(data) {
6008 Roo.log('progress url failed ');
6019 // run get Values on the form, so it syncs any secondary forms.
6020 this.form.getValues();
6022 var o = this.options;
6023 var method = this.getMethod();
6024 var isPost = method == 'POST';
6025 if(o.clientValidation === false || this.form.isValid()){
6027 if (this.form.progressUrl) {
6028 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6029 (new Date() * 1) + '' + Math.random());
6034 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6035 form:this.form.el.dom,
6036 url:this.getUrl(!isPost),
6038 params:isPost ? this.getParams() : null,
6039 isUpload: this.form.fileUpload
6042 this.uploadProgress();
6044 }else if (o.clientValidation !== false){ // client validation failed
6045 this.failureType = Roo.form.Action.CLIENT_INVALID;
6046 this.form.afterAction(this, false);
6050 success : function(response)
6052 this.uploadComplete= true;
6053 if (this.haveProgress) {
6054 Roo.MessageBox.hide();
6058 var result = this.processResponse(response);
6059 if(result === true || result.success){
6060 this.form.afterAction(this, true);
6064 this.form.markInvalid(result.errors);
6065 this.failureType = Roo.form.Action.SERVER_INVALID;
6067 this.form.afterAction(this, false);
6069 failure : function(response)
6071 this.uploadComplete= true;
6072 if (this.haveProgress) {
6073 Roo.MessageBox.hide();
6076 this.response = response;
6077 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6078 this.form.afterAction(this, false);
6081 handleResponse : function(response){
6082 if(this.form.errorReader){
6083 var rs = this.form.errorReader.read(response);
6086 for(var i = 0, len = rs.records.length; i < len; i++) {
6087 var r = rs.records[i];
6091 if(errors.length < 1){
6095 success : rs.success,
6101 ret = Roo.decode(response.responseText);
6105 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6115 Roo.form.Action.Load = function(form, options){
6116 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6117 this.reader = this.form.reader;
6120 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6125 Roo.Ajax.request(Roo.apply(
6126 this.createCallback(), {
6127 method:this.getMethod(),
6128 url:this.getUrl(false),
6129 params:this.getParams()
6133 success : function(response){
6135 var result = this.processResponse(response);
6136 if(result === true || !result.success || !result.data){
6137 this.failureType = Roo.form.Action.LOAD_FAILURE;
6138 this.form.afterAction(this, false);
6141 this.form.clearInvalid();
6142 this.form.setValues(result.data);
6143 this.form.afterAction(this, true);
6146 handleResponse : function(response){
6147 if(this.form.reader){
6148 var rs = this.form.reader.read(response);
6149 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6151 success : rs.success,
6155 return Roo.decode(response.responseText);
6159 Roo.form.Action.ACTION_TYPES = {
6160 'load' : Roo.form.Action.Load,
6161 'submit' : Roo.form.Action.Submit
6170 * @class Roo.bootstrap.Form
6171 * @extends Roo.bootstrap.Component
6172 * Bootstrap Form class
6173 * @cfg {String} method GET | POST (default POST)
6174 * @cfg {String} labelAlign top | left (default top)
6175 * @cfg {String} align left | right - for navbars
6176 * @cfg {Boolean} loadMask load mask when submit (default true)
6181 * @param {Object} config The config object
6185 Roo.bootstrap.Form = function(config){
6186 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6189 * @event clientvalidation
6190 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6191 * @param {Form} this
6192 * @param {Boolean} valid true if the form has passed client-side validation
6194 clientvalidation: true,
6196 * @event beforeaction
6197 * Fires before any action is performed. Return false to cancel the action.
6198 * @param {Form} this
6199 * @param {Action} action The action to be performed
6203 * @event actionfailed
6204 * Fires when an action fails.
6205 * @param {Form} this
6206 * @param {Action} action The action that failed
6208 actionfailed : true,
6210 * @event actioncomplete
6211 * Fires when an action is completed.
6212 * @param {Form} this
6213 * @param {Action} action The action that completed
6215 actioncomplete : true
6220 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6223 * @cfg {String} method
6224 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6229 * The URL to use for form actions if one isn't supplied in the action options.
6232 * @cfg {Boolean} fileUpload
6233 * Set to true if this form is a file upload.
6237 * @cfg {Object} baseParams
6238 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6242 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6246 * @cfg {Sting} align (left|right) for navbar forms
6251 activeAction : null,
6254 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6255 * element by passing it or its id or mask the form itself by passing in true.
6258 waitMsgTarget : false,
6262 getAutoCreate : function(){
6266 method : this.method || 'POST',
6267 id : this.id || Roo.id(),
6270 if (this.parent().xtype.match(/^Nav/)) {
6271 cfg.cls = 'navbar-form navbar-' + this.align;
6275 if (this.labelAlign == 'left' ) {
6276 cfg.cls += ' form-horizontal';
6282 initEvents : function()
6284 this.el.on('submit', this.onSubmit, this);
6285 // this was added as random key presses on the form where triggering form submit.
6286 this.el.on('keypress', function(e) {
6287 if (e.getCharCode() != 13) {
6290 // we might need to allow it for textareas.. and some other items.
6291 // check e.getTarget().
6293 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6297 Roo.log("keypress blocked");
6305 onSubmit : function(e){
6310 * Returns true if client-side validation on the form is successful.
6313 isValid : function(){
6314 var items = this.getItems();
6316 items.each(function(f){
6325 * Returns true if any fields in this form have changed since their original load.
6328 isDirty : function(){
6330 var items = this.getItems();
6331 items.each(function(f){
6341 * Performs a predefined action (submit or load) or custom actions you define on this form.
6342 * @param {String} actionName The name of the action type
6343 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6344 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6345 * accept other config options):
6347 Property Type Description
6348 ---------------- --------------- ----------------------------------------------------------------------------------
6349 url String The url for the action (defaults to the form's url)
6350 method String The form method to use (defaults to the form's method, or POST if not defined)
6351 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6352 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6353 validate the form on the client (defaults to false)
6355 * @return {BasicForm} this
6357 doAction : function(action, options){
6358 if(typeof action == 'string'){
6359 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6361 if(this.fireEvent('beforeaction', this, action) !== false){
6362 this.beforeAction(action);
6363 action.run.defer(100, action);
6369 beforeAction : function(action){
6370 var o = action.options;
6373 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6375 // not really supported yet.. ??
6377 //if(this.waitMsgTarget === true){
6378 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6379 //}else if(this.waitMsgTarget){
6380 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6381 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6383 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6389 afterAction : function(action, success){
6390 this.activeAction = null;
6391 var o = action.options;
6393 //if(this.waitMsgTarget === true){
6395 //}else if(this.waitMsgTarget){
6396 // this.waitMsgTarget.unmask();
6398 // Roo.MessageBox.updateProgress(1);
6399 // Roo.MessageBox.hide();
6406 Roo.callback(o.success, o.scope, [this, action]);
6407 this.fireEvent('actioncomplete', this, action);
6411 // failure condition..
6412 // we have a scenario where updates need confirming.
6413 // eg. if a locking scenario exists..
6414 // we look for { errors : { needs_confirm : true }} in the response.
6416 (typeof(action.result) != 'undefined') &&
6417 (typeof(action.result.errors) != 'undefined') &&
6418 (typeof(action.result.errors.needs_confirm) != 'undefined')
6421 Roo.log("not supported yet");
6424 Roo.MessageBox.confirm(
6425 "Change requires confirmation",
6426 action.result.errorMsg,
6431 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6441 Roo.callback(o.failure, o.scope, [this, action]);
6442 // show an error message if no failed handler is set..
6443 if (!this.hasListener('actionfailed')) {
6444 Roo.log("need to add dialog support");
6446 Roo.MessageBox.alert("Error",
6447 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6448 action.result.errorMsg :
6449 "Saving Failed, please check your entries or try again"
6454 this.fireEvent('actionfailed', this, action);
6459 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6460 * @param {String} id The value to search for
6463 findField : function(id){
6464 var items = this.getItems();
6465 var field = items.get(id);
6467 items.each(function(f){
6468 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6475 return field || null;
6478 * Mark fields in this form invalid in bulk.
6479 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6480 * @return {BasicForm} this
6482 markInvalid : function(errors){
6483 if(errors instanceof Array){
6484 for(var i = 0, len = errors.length; i < len; i++){
6485 var fieldError = errors[i];
6486 var f = this.findField(fieldError.id);
6488 f.markInvalid(fieldError.msg);
6494 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6495 field.markInvalid(errors[id]);
6499 //Roo.each(this.childForms || [], function (f) {
6500 // f.markInvalid(errors);
6507 * Set values for fields in this form in bulk.
6508 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6509 * @return {BasicForm} this
6511 setValues : function(values){
6512 if(values instanceof Array){ // array of objects
6513 for(var i = 0, len = values.length; i < len; i++){
6515 var f = this.findField(v.id);
6517 f.setValue(v.value);
6518 if(this.trackResetOnLoad){
6519 f.originalValue = f.getValue();
6523 }else{ // object hash
6526 if(typeof values[id] != 'function' && (field = this.findField(id))){
6528 if (field.setFromData &&
6530 field.displayField &&
6531 // combos' with local stores can
6532 // be queried via setValue()
6533 // to set their value..
6534 (field.store && !field.store.isLocal)
6538 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6539 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6540 field.setFromData(sd);
6543 field.setValue(values[id]);
6547 if(this.trackResetOnLoad){
6548 field.originalValue = field.getValue();
6554 //Roo.each(this.childForms || [], function (f) {
6555 // f.setValues(values);
6562 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6563 * they are returned as an array.
6564 * @param {Boolean} asString
6567 getValues : function(asString){
6568 //if (this.childForms) {
6569 // copy values from the child forms
6570 // Roo.each(this.childForms, function (f) {
6571 // this.setValues(f.getValues());
6577 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6578 if(asString === true){
6581 return Roo.urlDecode(fs);
6585 * Returns the fields in this form as an object with key/value pairs.
6586 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6589 getFieldValues : function(with_hidden)
6591 var items = this.getItems();
6593 items.each(function(f){
6597 var v = f.getValue();
6598 if (f.inputType =='radio') {
6599 if (typeof(ret[f.getName()]) == 'undefined') {
6600 ret[f.getName()] = ''; // empty..
6603 if (!f.el.dom.checked) {
6611 // not sure if this supported any more..
6612 if ((typeof(v) == 'object') && f.getRawValue) {
6613 v = f.getRawValue() ; // dates..
6615 // combo boxes where name != hiddenName...
6616 if (f.name != f.getName()) {
6617 ret[f.name] = f.getRawValue();
6619 ret[f.getName()] = v;
6626 * Clears all invalid messages in this form.
6627 * @return {BasicForm} this
6629 clearInvalid : function(){
6630 var items = this.getItems();
6632 items.each(function(f){
6643 * @return {BasicForm} this
6646 var items = this.getItems();
6647 items.each(function(f){
6651 Roo.each(this.childForms || [], function (f) {
6658 getItems : function()
6660 var r=new Roo.util.MixedCollection(false, function(o){
6661 return o.id || (o.id = Roo.id());
6663 var iter = function(el) {
6670 Roo.each(el.items,function(e) {
6689 * Ext JS Library 1.1.1
6690 * Copyright(c) 2006-2007, Ext JS, LLC.
6692 * Originally Released Under LGPL - original licence link has changed is not relivant.
6695 * <script type="text/javascript">
6698 * @class Roo.form.VTypes
6699 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6702 Roo.form.VTypes = function(){
6703 // closure these in so they are only created once.
6704 var alpha = /^[a-zA-Z_]+$/;
6705 var alphanum = /^[a-zA-Z0-9_]+$/;
6706 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6707 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6709 // All these messages and functions are configurable
6712 * The function used to validate email addresses
6713 * @param {String} value The email address
6715 'email' : function(v){
6716 return email.test(v);
6719 * The error text to display when the email validation function returns false
6722 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6724 * The keystroke filter mask to be applied on email input
6727 'emailMask' : /[a-z0-9_\.\-@]/i,
6730 * The function used to validate URLs
6731 * @param {String} value The URL
6733 'url' : function(v){
6737 * The error text to display when the url validation function returns false
6740 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6743 * The function used to validate alpha values
6744 * @param {String} value The value
6746 'alpha' : function(v){
6747 return alpha.test(v);
6750 * The error text to display when the alpha validation function returns false
6753 'alphaText' : 'This field should only contain letters and _',
6755 * The keystroke filter mask to be applied on alpha input
6758 'alphaMask' : /[a-z_]/i,
6761 * The function used to validate alphanumeric values
6762 * @param {String} value The value
6764 'alphanum' : function(v){
6765 return alphanum.test(v);
6768 * The error text to display when the alphanumeric validation function returns false
6771 'alphanumText' : 'This field should only contain letters, numbers and _',
6773 * The keystroke filter mask to be applied on alphanumeric input
6776 'alphanumMask' : /[a-z0-9_]/i
6786 * @class Roo.bootstrap.Input
6787 * @extends Roo.bootstrap.Component
6788 * Bootstrap Input class
6789 * @cfg {Boolean} disabled is it disabled
6790 * @cfg {String} fieldLabel - the label associated
6791 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6792 * @cfg {String} name name of the input
6793 * @cfg {string} fieldLabel - the label associated
6794 * @cfg {string} inputType - input / file submit ...
6795 * @cfg {string} placeholder - placeholder to put in text.
6796 * @cfg {string} before - input group add on before
6797 * @cfg {string} after - input group add on after
6798 * @cfg {string} size - (lg|sm) or leave empty..
6799 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6800 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6801 * @cfg {Number} md colspan out of 12 for computer-sized screens
6802 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6803 * @cfg {string} value default value of the input
6804 * @cfg {Number} labelWidth set the width of label (0-12)
6805 * @cfg {String} labelAlign (top|left)
6806 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6807 * @cfg {String} align (left|center|right) Default left
6811 * Create a new Input
6812 * @param {Object} config The config object
6815 Roo.bootstrap.Input = function(config){
6816 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6821 * Fires when this field receives input focus.
6822 * @param {Roo.form.Field} this
6827 * Fires when this field loses input focus.
6828 * @param {Roo.form.Field} this
6833 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6834 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6835 * @param {Roo.form.Field} this
6836 * @param {Roo.EventObject} e The event object
6841 * Fires just before the field blurs if the field value has changed.
6842 * @param {Roo.form.Field} this
6843 * @param {Mixed} newValue The new value
6844 * @param {Mixed} oldValue The original value
6849 * Fires after the field has been marked as invalid.
6850 * @param {Roo.form.Field} this
6851 * @param {String} msg The validation message
6856 * Fires after the field has been validated with no errors.
6857 * @param {Roo.form.Field} this
6862 * Fires after the key up
6863 * @param {Roo.form.Field} this
6864 * @param {Roo.EventObject} e The event Object
6870 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6872 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6873 automatic validation (defaults to "keyup").
6875 validationEvent : "keyup",
6877 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6879 validateOnBlur : true,
6881 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6883 validationDelay : 250,
6885 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6887 focusClass : "x-form-focus", // not needed???
6891 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6893 invalidClass : "has-error",
6896 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6898 selectOnFocus : false,
6901 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6905 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6910 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6912 disableKeyFilter : false,
6915 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6919 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6923 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6925 blankText : "This field is required",
6928 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6932 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6934 maxLength : Number.MAX_VALUE,
6936 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6938 minLengthText : "The minimum length for this field is {0}",
6940 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6942 maxLengthText : "The maximum length for this field is {0}",
6946 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6947 * If available, this function will be called only after the basic validators all return true, and will be passed the
6948 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6952 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6953 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6954 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6958 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6981 formatedValue : false,
6983 parentLabelAlign : function()
6986 while (parent.parent()) {
6987 parent = parent.parent();
6988 if (typeof(parent.labelAlign) !='undefined') {
6989 return parent.labelAlign;
6996 getAutoCreate : function(){
6998 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7004 if(this.inputType != 'hidden'){
7005 cfg.cls = 'form-group' //input-group
7011 type : this.inputType,
7013 cls : 'form-control',
7014 placeholder : this.placeholder || ''
7019 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7022 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7023 input.maxLength = this.maxLength;
7026 if (this.disabled) {
7027 input.disabled=true;
7030 if (this.readOnly) {
7031 input.readonly=true;
7035 input.name = this.name;
7038 input.cls += ' input-' + this.size;
7041 ['xs','sm','md','lg'].map(function(size){
7042 if (settings[size]) {
7043 cfg.cls += ' col-' + size + '-' + settings[size];
7047 var inputblock = input;
7049 if (this.before || this.after) {
7052 cls : 'input-group',
7055 if (this.before && typeof(this.before) == 'string') {
7057 inputblock.cn.push({
7059 cls : 'roo-input-before input-group-addon',
7063 if (this.before && typeof(this.before) == 'object') {
7064 this.before = Roo.factory(this.before);
7065 Roo.log(this.before);
7066 inputblock.cn.push({
7068 cls : 'roo-input-before input-group-' +
7069 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7073 inputblock.cn.push(input);
7075 if (this.after && typeof(this.after) == 'string') {
7076 inputblock.cn.push({
7078 cls : 'roo-input-after input-group-addon',
7082 if (this.after && typeof(this.after) == 'object') {
7083 this.after = Roo.factory(this.after);
7084 Roo.log(this.after);
7085 inputblock.cn.push({
7087 cls : 'roo-input-after input-group-' +
7088 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7093 if (align ==='left' && this.fieldLabel.length) {
7094 Roo.log("left and has label");
7100 cls : 'control-label col-sm-' + this.labelWidth,
7101 html : this.fieldLabel
7105 cls : "col-sm-" + (12 - this.labelWidth),
7112 } else if ( this.fieldLabel.length) {
7118 //cls : 'input-group-addon',
7119 html : this.fieldLabel
7129 Roo.log(" no label && no align");
7138 Roo.log('input-parentType: ' + this.parentType);
7140 if (this.parentType === 'Navbar' && this.parent().bar) {
7141 cfg.cls += ' navbar-form';
7149 * return the real input element.
7151 inputEl: function ()
7153 return this.el.select('input.form-control',true).first();
7155 setDisabled : function(v)
7157 var i = this.inputEl().dom;
7159 i.removeAttribute('disabled');
7163 i.setAttribute('disabled','true');
7165 initEvents : function()
7168 this.inputEl().on("keydown" , this.fireKey, this);
7169 this.inputEl().on("focus", this.onFocus, this);
7170 this.inputEl().on("blur", this.onBlur, this);
7172 this.inputEl().relayEvent('keyup', this);
7174 // reference to original value for reset
7175 this.originalValue = this.getValue();
7176 //Roo.form.TextField.superclass.initEvents.call(this);
7177 if(this.validationEvent == 'keyup'){
7178 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7179 this.inputEl().on('keyup', this.filterValidation, this);
7181 else if(this.validationEvent !== false){
7182 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7185 if(this.selectOnFocus){
7186 this.on("focus", this.preFocus, this);
7189 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7190 this.inputEl().on("keypress", this.filterKeys, this);
7193 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7194 this.el.on("click", this.autoSize, this);
7197 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7198 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7201 if (typeof(this.before) == 'object') {
7202 this.before.render(this.el.select('.roo-input-before',true).first());
7204 if (typeof(this.after) == 'object') {
7205 this.after.render(this.el.select('.roo-input-after',true).first());
7210 filterValidation : function(e){
7211 if(!e.isNavKeyPress()){
7212 this.validationTask.delay(this.validationDelay);
7216 * Validates the field value
7217 * @return {Boolean} True if the value is valid, else false
7219 validate : function(){
7220 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7221 if(this.disabled || this.validateValue(this.getRawValue())){
7222 this.clearInvalid();
7230 * Validates a value according to the field's validation rules and marks the field as invalid
7231 * if the validation fails
7232 * @param {Mixed} value The value to validate
7233 * @return {Boolean} True if the value is valid, else false
7235 validateValue : function(value){
7236 if(value.length < 1) { // if it's blank
7237 if(this.allowBlank){
7238 this.clearInvalid();
7241 this.markInvalid(this.blankText);
7245 if(value.length < this.minLength){
7246 this.markInvalid(String.format(this.minLengthText, this.minLength));
7249 if(value.length > this.maxLength){
7250 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7254 var vt = Roo.form.VTypes;
7255 if(!vt[this.vtype](value, this)){
7256 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7260 if(typeof this.validator == "function"){
7261 var msg = this.validator(value);
7263 this.markInvalid(msg);
7267 if(this.regex && !this.regex.test(value)){
7268 this.markInvalid(this.regexText);
7277 fireKey : function(e){
7278 //Roo.log('field ' + e.getKey());
7279 if(e.isNavKeyPress()){
7280 this.fireEvent("specialkey", this, e);
7283 focus : function (selectText){
7285 this.inputEl().focus();
7286 if(selectText === true){
7287 this.inputEl().dom.select();
7293 onFocus : function(){
7294 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7295 // this.el.addClass(this.focusClass);
7298 this.hasFocus = true;
7299 this.startValue = this.getValue();
7300 this.fireEvent("focus", this);
7304 beforeBlur : Roo.emptyFn,
7308 onBlur : function(){
7310 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7311 //this.el.removeClass(this.focusClass);
7313 this.hasFocus = false;
7314 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7317 var v = this.getValue();
7318 if(String(v) !== String(this.startValue)){
7319 this.fireEvent('change', this, v, this.startValue);
7321 this.fireEvent("blur", this);
7325 * Resets the current field value to the originally loaded value and clears any validation messages
7328 this.setValue(this.originalValue);
7329 this.clearInvalid();
7332 * Returns the name of the field
7333 * @return {Mixed} name The name field
7335 getName: function(){
7339 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7340 * @return {Mixed} value The field value
7342 getValue : function(){
7344 var v = this.inputEl().getValue();
7349 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7350 * @return {Mixed} value The field value
7352 getRawValue : function(){
7353 var v = this.inputEl().getValue();
7359 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7360 * @param {Mixed} value The value to set
7362 setRawValue : function(v){
7363 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7366 selectText : function(start, end){
7367 var v = this.getRawValue();
7369 start = start === undefined ? 0 : start;
7370 end = end === undefined ? v.length : end;
7371 var d = this.inputEl().dom;
7372 if(d.setSelectionRange){
7373 d.setSelectionRange(start, end);
7374 }else if(d.createTextRange){
7375 var range = d.createTextRange();
7376 range.moveStart("character", start);
7377 range.moveEnd("character", v.length-end);
7384 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7385 * @param {Mixed} value The value to set
7387 setValue : function(v){
7390 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7396 processValue : function(value){
7397 if(this.stripCharsRe){
7398 var newValue = value.replace(this.stripCharsRe, '');
7399 if(newValue !== value){
7400 this.setRawValue(newValue);
7407 preFocus : function(){
7409 if(this.selectOnFocus){
7410 this.inputEl().dom.select();
7413 filterKeys : function(e){
7415 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7418 var c = e.getCharCode(), cc = String.fromCharCode(c);
7419 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7422 if(!this.maskRe.test(cc)){
7427 * Clear any invalid styles/messages for this field
7429 clearInvalid : function(){
7431 if(!this.el || this.preventMark){ // not rendered
7434 this.el.removeClass(this.invalidClass);
7436 switch(this.msgTarget){
7438 this.el.dom.qtip = '';
7441 this.el.dom.title = '';
7445 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7450 this.errorIcon.dom.qtip = '';
7451 this.errorIcon.hide();
7452 this.un('resize', this.alignErrorIcon, this);
7456 var t = Roo.getDom(this.msgTarget);
7458 t.style.display = 'none';
7462 this.fireEvent('valid', this);
7465 * Mark this field as invalid
7466 * @param {String} msg The validation message
7468 markInvalid : function(msg){
7469 if(!this.el || this.preventMark){ // not rendered
7472 this.el.addClass(this.invalidClass);
7474 msg = msg || this.invalidText;
7475 switch(this.msgTarget){
7477 this.el.dom.qtip = msg;
7478 this.el.dom.qclass = 'x-form-invalid-tip';
7479 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7480 Roo.QuickTips.enable();
7484 this.el.dom.title = msg;
7488 var elp = this.el.findParent('.x-form-element', 5, true);
7489 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7490 this.errorEl.setWidth(elp.getWidth(true)-20);
7492 this.errorEl.update(msg);
7493 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7496 if(!this.errorIcon){
7497 var elp = this.el.findParent('.x-form-element', 5, true);
7498 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7500 this.alignErrorIcon();
7501 this.errorIcon.dom.qtip = msg;
7502 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7503 this.errorIcon.show();
7504 this.on('resize', this.alignErrorIcon, this);
7507 var t = Roo.getDom(this.msgTarget);
7509 t.style.display = this.msgDisplay;
7513 this.fireEvent('invalid', this, msg);
7516 SafariOnKeyDown : function(event)
7518 // this is a workaround for a password hang bug on chrome/ webkit.
7520 var isSelectAll = false;
7522 if(this.inputEl().dom.selectionEnd > 0){
7523 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7525 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7526 event.preventDefault();
7531 if(isSelectAll){ // backspace and delete key
7533 event.preventDefault();
7534 // this is very hacky as keydown always get's upper case.
7536 var cc = String.fromCharCode(event.getCharCode());
7537 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7541 adjustWidth : function(tag, w){
7542 tag = tag.toLowerCase();
7543 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7544 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7548 if(tag == 'textarea'){
7551 }else if(Roo.isOpera){
7555 if(tag == 'textarea'){
7574 * @class Roo.bootstrap.TextArea
7575 * @extends Roo.bootstrap.Input
7576 * Bootstrap TextArea class
7577 * @cfg {Number} cols Specifies the visible width of a text area
7578 * @cfg {Number} rows Specifies the visible number of lines in a text area
7579 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7580 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7581 * @cfg {string} html text
7584 * Create a new TextArea
7585 * @param {Object} config The config object
7588 Roo.bootstrap.TextArea = function(config){
7589 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7593 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7603 getAutoCreate : function(){
7605 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7616 value : this.value || '',
7617 html: this.html || '',
7618 cls : 'form-control',
7619 placeholder : this.placeholder || ''
7623 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7624 input.maxLength = this.maxLength;
7628 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7632 input.cols = this.cols;
7635 if (this.readOnly) {
7636 input.readonly = true;
7640 input.name = this.name;
7644 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7648 ['xs','sm','md','lg'].map(function(size){
7649 if (settings[size]) {
7650 cfg.cls += ' col-' + size + '-' + settings[size];
7654 var inputblock = input;
7656 if (this.before || this.after) {
7659 cls : 'input-group',
7663 inputblock.cn.push({
7665 cls : 'input-group-addon',
7669 inputblock.cn.push(input);
7671 inputblock.cn.push({
7673 cls : 'input-group-addon',
7680 if (align ==='left' && this.fieldLabel.length) {
7681 Roo.log("left and has label");
7687 cls : 'control-label col-sm-' + this.labelWidth,
7688 html : this.fieldLabel
7692 cls : "col-sm-" + (12 - this.labelWidth),
7699 } else if ( this.fieldLabel.length) {
7705 //cls : 'input-group-addon',
7706 html : this.fieldLabel
7716 Roo.log(" no label && no align");
7726 if (this.disabled) {
7727 input.disabled=true;
7734 * return the real textarea element.
7736 inputEl: function ()
7738 return this.el.select('textarea.form-control',true).first();
7746 * trigger field - base class for combo..
7751 * @class Roo.bootstrap.TriggerField
7752 * @extends Roo.bootstrap.Input
7753 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7754 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7755 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7756 * for which you can provide a custom implementation. For example:
7758 var trigger = new Roo.bootstrap.TriggerField();
7759 trigger.onTriggerClick = myTriggerFn;
7760 trigger.applyTo('my-field');
7763 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7764 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7765 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7766 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7768 * Create a new TriggerField.
7769 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7770 * to the base TextField)
7772 Roo.bootstrap.TriggerField = function(config){
7773 this.mimicing = false;
7774 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7777 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7779 * @cfg {String} triggerClass A CSS class to apply to the trigger
7782 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7786 /** @cfg {Boolean} grow @hide */
7787 /** @cfg {Number} growMin @hide */
7788 /** @cfg {Number} growMax @hide */
7794 autoSize: Roo.emptyFn,
7801 actionMode : 'wrap',
7805 getAutoCreate : function(){
7807 var align = this.labelAlign || this.parentLabelAlign();
7812 cls: 'form-group' //input-group
7819 type : this.inputType,
7820 cls : 'form-control',
7821 autocomplete: 'off',
7822 placeholder : this.placeholder || ''
7826 input.name = this.name;
7829 input.cls += ' input-' + this.size;
7832 if (this.disabled) {
7833 input.disabled=true;
7836 var inputblock = input;
7838 if (this.before || this.after) {
7841 cls : 'input-group',
7845 inputblock.cn.push({
7847 cls : 'input-group-addon',
7851 inputblock.cn.push(input);
7853 inputblock.cn.push({
7855 cls : 'input-group-addon',
7868 cls: 'form-hidden-field'
7876 Roo.log('multiple');
7884 cls: 'form-hidden-field'
7888 cls: 'select2-choices',
7892 cls: 'select2-search-field',
7905 cls: 'select2-container input-group',
7910 // cls: 'typeahead typeahead-long dropdown-menu',
7911 // style: 'display:none'
7916 if(!this.multiple && this.showToggleBtn){
7919 cls : 'input-group-addon btn dropdown-toggle',
7927 cls: 'combobox-clear',
7941 combobox.cls += ' select2-container-multi';
7944 if (align ==='left' && this.fieldLabel.length) {
7946 Roo.log("left and has label");
7952 cls : 'control-label col-sm-' + this.labelWidth,
7953 html : this.fieldLabel
7957 cls : "col-sm-" + (12 - this.labelWidth),
7964 } else if ( this.fieldLabel.length) {
7970 //cls : 'input-group-addon',
7971 html : this.fieldLabel
7981 Roo.log(" no label && no align");
7988 ['xs','sm','md','lg'].map(function(size){
7989 if (settings[size]) {
7990 cfg.cls += ' col-' + size + '-' + settings[size];
8001 onResize : function(w, h){
8002 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8003 // if(typeof w == 'number'){
8004 // var x = w - this.trigger.getWidth();
8005 // this.inputEl().setWidth(this.adjustWidth('input', x));
8006 // this.trigger.setStyle('left', x+'px');
8011 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8014 getResizeEl : function(){
8015 return this.inputEl();
8019 getPositionEl : function(){
8020 return this.inputEl();
8024 alignErrorIcon : function(){
8025 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8029 initEvents : function(){
8033 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8034 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8035 if(!this.multiple && this.showToggleBtn){
8036 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8037 if(this.hideTrigger){
8038 this.trigger.setDisplayed(false);
8040 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8044 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8047 //this.trigger.addClassOnOver('x-form-trigger-over');
8048 //this.trigger.addClassOnClick('x-form-trigger-click');
8051 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8055 createList : function()
8057 this.list = Roo.get(document.body).createChild({
8059 cls: 'typeahead typeahead-long dropdown-menu',
8060 style: 'display:none'
8063 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8068 initTrigger : function(){
8073 onDestroy : function(){
8075 this.trigger.removeAllListeners();
8076 // this.trigger.remove();
8079 // this.wrap.remove();
8081 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8085 onFocus : function(){
8086 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8089 this.wrap.addClass('x-trigger-wrap-focus');
8090 this.mimicing = true;
8091 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8092 if(this.monitorTab){
8093 this.el.on("keydown", this.checkTab, this);
8100 checkTab : function(e){
8101 if(e.getKey() == e.TAB){
8107 onBlur : function(){
8112 mimicBlur : function(e, t){
8114 if(!this.wrap.contains(t) && this.validateBlur()){
8121 triggerBlur : function(){
8122 this.mimicing = false;
8123 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8124 if(this.monitorTab){
8125 this.el.un("keydown", this.checkTab, this);
8127 //this.wrap.removeClass('x-trigger-wrap-focus');
8128 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8132 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8133 validateBlur : function(e, t){
8138 onDisable : function(){
8139 this.inputEl().dom.disabled = true;
8140 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8142 // this.wrap.addClass('x-item-disabled');
8147 onEnable : function(){
8148 this.inputEl().dom.disabled = false;
8149 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8151 // this.el.removeClass('x-item-disabled');
8156 onShow : function(){
8157 var ae = this.getActionEl();
8160 ae.dom.style.display = '';
8161 ae.dom.style.visibility = 'visible';
8167 onHide : function(){
8168 var ae = this.getActionEl();
8169 ae.dom.style.display = 'none';
8173 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8174 * by an implementing function.
8176 * @param {EventObject} e
8178 onTriggerClick : Roo.emptyFn
8182 * Ext JS Library 1.1.1
8183 * Copyright(c) 2006-2007, Ext JS, LLC.
8185 * Originally Released Under LGPL - original licence link has changed is not relivant.
8188 * <script type="text/javascript">
8193 * @class Roo.data.SortTypes
8195 * Defines the default sorting (casting?) comparison functions used when sorting data.
8197 Roo.data.SortTypes = {
8199 * Default sort that does nothing
8200 * @param {Mixed} s The value being converted
8201 * @return {Mixed} The comparison value
8208 * The regular expression used to strip tags
8212 stripTagsRE : /<\/?[^>]+>/gi,
8215 * Strips all HTML tags to sort on text only
8216 * @param {Mixed} s The value being converted
8217 * @return {String} The comparison value
8219 asText : function(s){
8220 return String(s).replace(this.stripTagsRE, "");
8224 * Strips all HTML tags to sort on text only - Case insensitive
8225 * @param {Mixed} s The value being converted
8226 * @return {String} The comparison value
8228 asUCText : function(s){
8229 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8233 * Case insensitive string
8234 * @param {Mixed} s The value being converted
8235 * @return {String} The comparison value
8237 asUCString : function(s) {
8238 return String(s).toUpperCase();
8243 * @param {Mixed} s The value being converted
8244 * @return {Number} The comparison value
8246 asDate : function(s) {
8250 if(s instanceof Date){
8253 return Date.parse(String(s));
8258 * @param {Mixed} s The value being converted
8259 * @return {Float} The comparison value
8261 asFloat : function(s) {
8262 var val = parseFloat(String(s).replace(/,/g, ""));
8263 if(isNaN(val)) val = 0;
8269 * @param {Mixed} s The value being converted
8270 * @return {Number} The comparison value
8272 asInt : function(s) {
8273 var val = parseInt(String(s).replace(/,/g, ""));
8274 if(isNaN(val)) val = 0;
8279 * Ext JS Library 1.1.1
8280 * Copyright(c) 2006-2007, Ext JS, LLC.
8282 * Originally Released Under LGPL - original licence link has changed is not relivant.
8285 * <script type="text/javascript">
8289 * @class Roo.data.Record
8290 * Instances of this class encapsulate both record <em>definition</em> information, and record
8291 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8292 * to access Records cached in an {@link Roo.data.Store} object.<br>
8294 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8295 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8298 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8300 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8301 * {@link #create}. The parameters are the same.
8302 * @param {Array} data An associative Array of data values keyed by the field name.
8303 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8304 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8305 * not specified an integer id is generated.
8307 Roo.data.Record = function(data, id){
8308 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8313 * Generate a constructor for a specific record layout.
8314 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8315 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8316 * Each field definition object may contain the following properties: <ul>
8317 * <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,
8318 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8319 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8320 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8321 * is being used, then this is a string containing the javascript expression to reference the data relative to
8322 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8323 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8324 * this may be omitted.</p></li>
8325 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8326 * <ul><li>auto (Default, implies no conversion)</li>
8331 * <li>date</li></ul></p></li>
8332 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8333 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8334 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8335 * by the Reader into an object that will be stored in the Record. It is passed the
8336 * following parameters:<ul>
8337 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8339 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8341 * <br>usage:<br><pre><code>
8342 var TopicRecord = Roo.data.Record.create(
8343 {name: 'title', mapping: 'topic_title'},
8344 {name: 'author', mapping: 'username'},
8345 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8346 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8347 {name: 'lastPoster', mapping: 'user2'},
8348 {name: 'excerpt', mapping: 'post_text'}
8351 var myNewRecord = new TopicRecord({
8352 title: 'Do my job please',
8355 lastPost: new Date(),
8356 lastPoster: 'Animal',
8357 excerpt: 'No way dude!'
8359 myStore.add(myNewRecord);
8364 Roo.data.Record.create = function(o){
8366 f.superclass.constructor.apply(this, arguments);
8368 Roo.extend(f, Roo.data.Record);
8369 var p = f.prototype;
8370 p.fields = new Roo.util.MixedCollection(false, function(field){
8373 for(var i = 0, len = o.length; i < len; i++){
8374 p.fields.add(new Roo.data.Field(o[i]));
8376 f.getField = function(name){
8377 return p.fields.get(name);
8382 Roo.data.Record.AUTO_ID = 1000;
8383 Roo.data.Record.EDIT = 'edit';
8384 Roo.data.Record.REJECT = 'reject';
8385 Roo.data.Record.COMMIT = 'commit';
8387 Roo.data.Record.prototype = {
8389 * Readonly flag - true if this record has been modified.
8398 join : function(store){
8403 * Set the named field to the specified value.
8404 * @param {String} name The name of the field to set.
8405 * @param {Object} value The value to set the field to.
8407 set : function(name, value){
8408 if(this.data[name] == value){
8415 if(typeof this.modified[name] == 'undefined'){
8416 this.modified[name] = this.data[name];
8418 this.data[name] = value;
8419 if(!this.editing && this.store){
8420 this.store.afterEdit(this);
8425 * Get the value of the named field.
8426 * @param {String} name The name of the field to get the value of.
8427 * @return {Object} The value of the field.
8429 get : function(name){
8430 return this.data[name];
8434 beginEdit : function(){
8435 this.editing = true;
8440 cancelEdit : function(){
8441 this.editing = false;
8442 delete this.modified;
8446 endEdit : function(){
8447 this.editing = false;
8448 if(this.dirty && this.store){
8449 this.store.afterEdit(this);
8454 * Usually called by the {@link Roo.data.Store} which owns the Record.
8455 * Rejects all changes made to the Record since either creation, or the last commit operation.
8456 * Modified fields are reverted to their original values.
8458 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8459 * of reject operations.
8461 reject : function(){
8462 var m = this.modified;
8464 if(typeof m[n] != "function"){
8465 this.data[n] = m[n];
8469 delete this.modified;
8470 this.editing = false;
8472 this.store.afterReject(this);
8477 * Usually called by the {@link Roo.data.Store} which owns the Record.
8478 * Commits all changes made to the Record since either creation, or the last commit operation.
8480 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8481 * of commit operations.
8483 commit : function(){
8485 delete this.modified;
8486 this.editing = false;
8488 this.store.afterCommit(this);
8493 hasError : function(){
8494 return this.error != null;
8498 clearError : function(){
8503 * Creates a copy of this record.
8504 * @param {String} id (optional) A new record id if you don't want to use this record's id
8507 copy : function(newId) {
8508 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8512 * Ext JS Library 1.1.1
8513 * Copyright(c) 2006-2007, Ext JS, LLC.
8515 * Originally Released Under LGPL - original licence link has changed is not relivant.
8518 * <script type="text/javascript">
8524 * @class Roo.data.Store
8525 * @extends Roo.util.Observable
8526 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8527 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8529 * 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
8530 * has no knowledge of the format of the data returned by the Proxy.<br>
8532 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8533 * instances from the data object. These records are cached and made available through accessor functions.
8535 * Creates a new Store.
8536 * @param {Object} config A config object containing the objects needed for the Store to access data,
8537 * and read the data into Records.
8539 Roo.data.Store = function(config){
8540 this.data = new Roo.util.MixedCollection(false);
8541 this.data.getKey = function(o){
8544 this.baseParams = {};
8551 "multisort" : "_multisort"
8554 if(config && config.data){
8555 this.inlineData = config.data;
8559 Roo.apply(this, config);
8561 if(this.reader){ // reader passed
8562 this.reader = Roo.factory(this.reader, Roo.data);
8563 this.reader.xmodule = this.xmodule || false;
8564 if(!this.recordType){
8565 this.recordType = this.reader.recordType;
8567 if(this.reader.onMetaChange){
8568 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8572 if(this.recordType){
8573 this.fields = this.recordType.prototype.fields;
8579 * @event datachanged
8580 * Fires when the data cache has changed, and a widget which is using this Store
8581 * as a Record cache should refresh its view.
8582 * @param {Store} this
8587 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8588 * @param {Store} this
8589 * @param {Object} meta The JSON metadata
8594 * Fires when Records have been added to the Store
8595 * @param {Store} this
8596 * @param {Roo.data.Record[]} records The array of Records added
8597 * @param {Number} index The index at which the record(s) were added
8602 * Fires when a Record has been removed from the Store
8603 * @param {Store} this
8604 * @param {Roo.data.Record} record The Record that was removed
8605 * @param {Number} index The index at which the record was removed
8610 * Fires when a Record has been updated
8611 * @param {Store} this
8612 * @param {Roo.data.Record} record The Record that was updated
8613 * @param {String} operation The update operation being performed. Value may be one of:
8615 Roo.data.Record.EDIT
8616 Roo.data.Record.REJECT
8617 Roo.data.Record.COMMIT
8623 * Fires when the data cache has been cleared.
8624 * @param {Store} this
8629 * Fires before a request is made for a new data object. If the beforeload handler returns false
8630 * the load action will be canceled.
8631 * @param {Store} this
8632 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8636 * @event beforeloadadd
8637 * Fires after a new set of Records has been loaded.
8638 * @param {Store} this
8639 * @param {Roo.data.Record[]} records The Records that were loaded
8640 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8642 beforeloadadd : true,
8645 * Fires after a new set of Records has been loaded, before they are added to the store.
8646 * @param {Store} this
8647 * @param {Roo.data.Record[]} records The Records that were loaded
8648 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8649 * @params {Object} return from reader
8653 * @event loadexception
8654 * Fires if an exception occurs in the Proxy during loading.
8655 * Called with the signature of the Proxy's "loadexception" event.
8656 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8659 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8660 * @param {Object} load options
8661 * @param {Object} jsonData from your request (normally this contains the Exception)
8663 loadexception : true
8667 this.proxy = Roo.factory(this.proxy, Roo.data);
8668 this.proxy.xmodule = this.xmodule || false;
8669 this.relayEvents(this.proxy, ["loadexception"]);
8671 this.sortToggle = {};
8672 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8674 Roo.data.Store.superclass.constructor.call(this);
8676 if(this.inlineData){
8677 this.loadData(this.inlineData);
8678 delete this.inlineData;
8682 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8684 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8685 * without a remote query - used by combo/forms at present.
8689 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8692 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8695 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8696 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8699 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8700 * on any HTTP request
8703 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8706 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8710 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8711 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8716 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8717 * loaded or when a record is removed. (defaults to false).
8719 pruneModifiedRecords : false,
8725 * Add Records to the Store and fires the add event.
8726 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8728 add : function(records){
8729 records = [].concat(records);
8730 for(var i = 0, len = records.length; i < len; i++){
8731 records[i].join(this);
8733 var index = this.data.length;
8734 this.data.addAll(records);
8735 this.fireEvent("add", this, records, index);
8739 * Remove a Record from the Store and fires the remove event.
8740 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8742 remove : function(record){
8743 var index = this.data.indexOf(record);
8744 this.data.removeAt(index);
8745 if(this.pruneModifiedRecords){
8746 this.modified.remove(record);
8748 this.fireEvent("remove", this, record, index);
8752 * Remove all Records from the Store and fires the clear event.
8754 removeAll : function(){
8756 if(this.pruneModifiedRecords){
8759 this.fireEvent("clear", this);
8763 * Inserts Records to the Store at the given index and fires the add event.
8764 * @param {Number} index The start index at which to insert the passed Records.
8765 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8767 insert : function(index, records){
8768 records = [].concat(records);
8769 for(var i = 0, len = records.length; i < len; i++){
8770 this.data.insert(index, records[i]);
8771 records[i].join(this);
8773 this.fireEvent("add", this, records, index);
8777 * Get the index within the cache of the passed Record.
8778 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8779 * @return {Number} The index of the passed Record. Returns -1 if not found.
8781 indexOf : function(record){
8782 return this.data.indexOf(record);
8786 * Get the index within the cache of the Record with the passed id.
8787 * @param {String} id The id of the Record to find.
8788 * @return {Number} The index of the Record. Returns -1 if not found.
8790 indexOfId : function(id){
8791 return this.data.indexOfKey(id);
8795 * Get the Record with the specified id.
8796 * @param {String} id The id of the Record to find.
8797 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8799 getById : function(id){
8800 return this.data.key(id);
8804 * Get the Record at the specified index.
8805 * @param {Number} index The index of the Record to find.
8806 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8808 getAt : function(index){
8809 return this.data.itemAt(index);
8813 * Returns a range of Records between specified indices.
8814 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8815 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8816 * @return {Roo.data.Record[]} An array of Records
8818 getRange : function(start, end){
8819 return this.data.getRange(start, end);
8823 storeOptions : function(o){
8824 o = Roo.apply({}, o);
8827 this.lastOptions = o;
8831 * Loads the Record cache from the configured Proxy using the configured Reader.
8833 * If using remote paging, then the first load call must specify the <em>start</em>
8834 * and <em>limit</em> properties in the options.params property to establish the initial
8835 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8837 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8838 * and this call will return before the new data has been loaded. Perform any post-processing
8839 * in a callback function, or in a "load" event handler.</strong>
8841 * @param {Object} options An object containing properties which control loading options:<ul>
8842 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8843 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8844 * passed the following arguments:<ul>
8845 * <li>r : Roo.data.Record[]</li>
8846 * <li>options: Options object from the load call</li>
8847 * <li>success: Boolean success indicator</li></ul></li>
8848 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8849 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8852 load : function(options){
8853 options = options || {};
8854 if(this.fireEvent("beforeload", this, options) !== false){
8855 this.storeOptions(options);
8856 var p = Roo.apply(options.params || {}, this.baseParams);
8857 // if meta was not loaded from remote source.. try requesting it.
8858 if (!this.reader.metaFromRemote) {
8861 if(this.sortInfo && this.remoteSort){
8862 var pn = this.paramNames;
8863 p[pn["sort"]] = this.sortInfo.field;
8864 p[pn["dir"]] = this.sortInfo.direction;
8866 if (this.multiSort) {
8867 var pn = this.paramNames;
8868 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8871 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8876 * Reloads the Record cache from the configured Proxy using the configured Reader and
8877 * the options from the last load operation performed.
8878 * @param {Object} options (optional) An object containing properties which may override the options
8879 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8880 * the most recently used options are reused).
8882 reload : function(options){
8883 this.load(Roo.applyIf(options||{}, this.lastOptions));
8887 // Called as a callback by the Reader during a load operation.
8888 loadRecords : function(o, options, success){
8889 if(!o || success === false){
8890 if(success !== false){
8891 this.fireEvent("load", this, [], options, o);
8893 if(options.callback){
8894 options.callback.call(options.scope || this, [], options, false);
8898 // if data returned failure - throw an exception.
8899 if (o.success === false) {
8900 // show a message if no listener is registered.
8901 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8902 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8904 // loadmask wil be hooked into this..
8905 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8908 var r = o.records, t = o.totalRecords || r.length;
8910 this.fireEvent("beforeloadadd", this, r, options, o);
8912 if(!options || options.add !== true){
8913 if(this.pruneModifiedRecords){
8916 for(var i = 0, len = r.length; i < len; i++){
8920 this.data = this.snapshot;
8921 delete this.snapshot;
8924 this.data.addAll(r);
8925 this.totalLength = t;
8927 this.fireEvent("datachanged", this);
8929 this.totalLength = Math.max(t, this.data.length+r.length);
8932 this.fireEvent("load", this, r, options, o);
8933 if(options.callback){
8934 options.callback.call(options.scope || this, r, options, true);
8940 * Loads data from a passed data block. A Reader which understands the format of the data
8941 * must have been configured in the constructor.
8942 * @param {Object} data The data block from which to read the Records. The format of the data expected
8943 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8944 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8946 loadData : function(o, append){
8947 var r = this.reader.readRecords(o);
8948 this.loadRecords(r, {add: append}, true);
8952 * Gets the number of cached records.
8954 * <em>If using paging, this may not be the total size of the dataset. If the data object
8955 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8956 * the data set size</em>
8958 getCount : function(){
8959 return this.data.length || 0;
8963 * Gets the total number of records in the dataset as returned by the server.
8965 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8966 * the dataset size</em>
8968 getTotalCount : function(){
8969 return this.totalLength || 0;
8973 * Returns the sort state of the Store as an object with two properties:
8975 field {String} The name of the field by which the Records are sorted
8976 direction {String} The sort order, "ASC" or "DESC"
8979 getSortState : function(){
8980 return this.sortInfo;
8984 applySort : function(){
8985 if(this.sortInfo && !this.remoteSort){
8986 var s = this.sortInfo, f = s.field;
8987 var st = this.fields.get(f).sortType;
8988 var fn = function(r1, r2){
8989 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8990 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8992 this.data.sort(s.direction, fn);
8993 if(this.snapshot && this.snapshot != this.data){
8994 this.snapshot.sort(s.direction, fn);
9000 * Sets the default sort column and order to be used by the next load operation.
9001 * @param {String} fieldName The name of the field to sort by.
9002 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9004 setDefaultSort : function(field, dir){
9005 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9010 * If remote sorting is used, the sort is performed on the server, and the cache is
9011 * reloaded. If local sorting is used, the cache is sorted internally.
9012 * @param {String} fieldName The name of the field to sort by.
9013 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9015 sort : function(fieldName, dir){
9016 var f = this.fields.get(fieldName);
9018 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9020 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9021 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9026 this.sortToggle[f.name] = dir;
9027 this.sortInfo = {field: f.name, direction: dir};
9028 if(!this.remoteSort){
9030 this.fireEvent("datachanged", this);
9032 this.load(this.lastOptions);
9037 * Calls the specified function for each of the Records in the cache.
9038 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9039 * Returning <em>false</em> aborts and exits the iteration.
9040 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9042 each : function(fn, scope){
9043 this.data.each(fn, scope);
9047 * Gets all records modified since the last commit. Modified records are persisted across load operations
9048 * (e.g., during paging).
9049 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9051 getModifiedRecords : function(){
9052 return this.modified;
9056 createFilterFn : function(property, value, anyMatch){
9057 if(!value.exec){ // not a regex
9058 value = String(value);
9059 if(value.length == 0){
9062 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9065 return value.test(r.data[property]);
9070 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9071 * @param {String} property A field on your records
9072 * @param {Number} start The record index to start at (defaults to 0)
9073 * @param {Number} end The last record index to include (defaults to length - 1)
9074 * @return {Number} The sum
9076 sum : function(property, start, end){
9077 var rs = this.data.items, v = 0;
9079 end = (end || end === 0) ? end : rs.length-1;
9081 for(var i = start; i <= end; i++){
9082 v += (rs[i].data[property] || 0);
9088 * Filter the records by a specified property.
9089 * @param {String} field A field on your records
9090 * @param {String/RegExp} value Either a string that the field
9091 * should start with or a RegExp to test against the field
9092 * @param {Boolean} anyMatch True to match any part not just the beginning
9094 filter : function(property, value, anyMatch){
9095 var fn = this.createFilterFn(property, value, anyMatch);
9096 return fn ? this.filterBy(fn) : this.clearFilter();
9100 * Filter by a function. The specified function will be called with each
9101 * record in this data source. If the function returns true the record is included,
9102 * otherwise it is filtered.
9103 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9104 * @param {Object} scope (optional) The scope of the function (defaults to this)
9106 filterBy : function(fn, scope){
9107 this.snapshot = this.snapshot || this.data;
9108 this.data = this.queryBy(fn, scope||this);
9109 this.fireEvent("datachanged", this);
9113 * Query the records by a specified property.
9114 * @param {String} field A field on your records
9115 * @param {String/RegExp} value Either a string that the field
9116 * should start with or a RegExp to test against the field
9117 * @param {Boolean} anyMatch True to match any part not just the beginning
9118 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9120 query : function(property, value, anyMatch){
9121 var fn = this.createFilterFn(property, value, anyMatch);
9122 return fn ? this.queryBy(fn) : this.data.clone();
9126 * Query by a function. The specified function will be called with each
9127 * record in this data source. If the function returns true the record is included
9129 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9130 * @param {Object} scope (optional) The scope of the function (defaults to this)
9131 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9133 queryBy : function(fn, scope){
9134 var data = this.snapshot || this.data;
9135 return data.filterBy(fn, scope||this);
9139 * Collects unique values for a particular dataIndex from this store.
9140 * @param {String} dataIndex The property to collect
9141 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9142 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9143 * @return {Array} An array of the unique values
9145 collect : function(dataIndex, allowNull, bypassFilter){
9146 var d = (bypassFilter === true && this.snapshot) ?
9147 this.snapshot.items : this.data.items;
9148 var v, sv, r = [], l = {};
9149 for(var i = 0, len = d.length; i < len; i++){
9150 v = d[i].data[dataIndex];
9152 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9161 * Revert to a view of the Record cache with no filtering applied.
9162 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9164 clearFilter : function(suppressEvent){
9165 if(this.snapshot && this.snapshot != this.data){
9166 this.data = this.snapshot;
9167 delete this.snapshot;
9168 if(suppressEvent !== true){
9169 this.fireEvent("datachanged", this);
9175 afterEdit : function(record){
9176 if(this.modified.indexOf(record) == -1){
9177 this.modified.push(record);
9179 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9183 afterReject : function(record){
9184 this.modified.remove(record);
9185 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9189 afterCommit : function(record){
9190 this.modified.remove(record);
9191 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9195 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9196 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9198 commitChanges : function(){
9199 var m = this.modified.slice(0);
9201 for(var i = 0, len = m.length; i < len; i++){
9207 * Cancel outstanding changes on all changed records.
9209 rejectChanges : function(){
9210 var m = this.modified.slice(0);
9212 for(var i = 0, len = m.length; i < len; i++){
9217 onMetaChange : function(meta, rtype, o){
9218 this.recordType = rtype;
9219 this.fields = rtype.prototype.fields;
9220 delete this.snapshot;
9221 this.sortInfo = meta.sortInfo || this.sortInfo;
9223 this.fireEvent('metachange', this, this.reader.meta);
9226 moveIndex : function(data, type)
9228 var index = this.indexOf(data);
9230 var newIndex = index + type;
9234 this.insert(newIndex, data);
9239 * Ext JS Library 1.1.1
9240 * Copyright(c) 2006-2007, Ext JS, LLC.
9242 * Originally Released Under LGPL - original licence link has changed is not relivant.
9245 * <script type="text/javascript">
9249 * @class Roo.data.SimpleStore
9250 * @extends Roo.data.Store
9251 * Small helper class to make creating Stores from Array data easier.
9252 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9253 * @cfg {Array} fields An array of field definition objects, or field name strings.
9254 * @cfg {Array} data The multi-dimensional array of data
9256 * @param {Object} config
9258 Roo.data.SimpleStore = function(config){
9259 Roo.data.SimpleStore.superclass.constructor.call(this, {
9261 reader: new Roo.data.ArrayReader({
9264 Roo.data.Record.create(config.fields)
9266 proxy : new Roo.data.MemoryProxy(config.data)
9270 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9272 * Ext JS Library 1.1.1
9273 * Copyright(c) 2006-2007, Ext JS, LLC.
9275 * Originally Released Under LGPL - original licence link has changed is not relivant.
9278 * <script type="text/javascript">
9283 * @extends Roo.data.Store
9284 * @class Roo.data.JsonStore
9285 * Small helper class to make creating Stores for JSON data easier. <br/>
9287 var store = new Roo.data.JsonStore({
9288 url: 'get-images.php',
9290 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9293 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9294 * JsonReader and HttpProxy (unless inline data is provided).</b>
9295 * @cfg {Array} fields An array of field definition objects, or field name strings.
9297 * @param {Object} config
9299 Roo.data.JsonStore = function(c){
9300 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9301 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9302 reader: new Roo.data.JsonReader(c, c.fields)
9305 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9307 * Ext JS Library 1.1.1
9308 * Copyright(c) 2006-2007, Ext JS, LLC.
9310 * Originally Released Under LGPL - original licence link has changed is not relivant.
9313 * <script type="text/javascript">
9317 Roo.data.Field = function(config){
9318 if(typeof config == "string"){
9319 config = {name: config};
9321 Roo.apply(this, config);
9327 var st = Roo.data.SortTypes;
9328 // named sortTypes are supported, here we look them up
9329 if(typeof this.sortType == "string"){
9330 this.sortType = st[this.sortType];
9333 // set default sortType for strings and dates
9337 this.sortType = st.asUCString;
9340 this.sortType = st.asDate;
9343 this.sortType = st.none;
9348 var stripRe = /[\$,%]/g;
9350 // prebuilt conversion function for this field, instead of
9351 // switching every time we're reading a value
9353 var cv, dateFormat = this.dateFormat;
9358 cv = function(v){ return v; };
9361 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9365 return v !== undefined && v !== null && v !== '' ?
9366 parseInt(String(v).replace(stripRe, ""), 10) : '';
9371 return v !== undefined && v !== null && v !== '' ?
9372 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9377 cv = function(v){ return v === true || v === "true" || v == 1; };
9384 if(v instanceof Date){
9388 if(dateFormat == "timestamp"){
9389 return new Date(v*1000);
9391 return Date.parseDate(v, dateFormat);
9393 var parsed = Date.parse(v);
9394 return parsed ? new Date(parsed) : null;
9403 Roo.data.Field.prototype = {
9411 * Ext JS Library 1.1.1
9412 * Copyright(c) 2006-2007, Ext JS, LLC.
9414 * Originally Released Under LGPL - original licence link has changed is not relivant.
9417 * <script type="text/javascript">
9420 // Base class for reading structured data from a data source. This class is intended to be
9421 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9424 * @class Roo.data.DataReader
9425 * Base class for reading structured data from a data source. This class is intended to be
9426 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9429 Roo.data.DataReader = function(meta, recordType){
9433 this.recordType = recordType instanceof Array ?
9434 Roo.data.Record.create(recordType) : recordType;
9437 Roo.data.DataReader.prototype = {
9439 * Create an empty record
9440 * @param {Object} data (optional) - overlay some values
9441 * @return {Roo.data.Record} record created.
9443 newRow : function(d) {
9445 this.recordType.prototype.fields.each(function(c) {
9447 case 'int' : da[c.name] = 0; break;
9448 case 'date' : da[c.name] = new Date(); break;
9449 case 'float' : da[c.name] = 0.0; break;
9450 case 'boolean' : da[c.name] = false; break;
9451 default : da[c.name] = ""; break;
9455 return new this.recordType(Roo.apply(da, d));
9460 * Ext JS Library 1.1.1
9461 * Copyright(c) 2006-2007, Ext JS, LLC.
9463 * Originally Released Under LGPL - original licence link has changed is not relivant.
9466 * <script type="text/javascript">
9470 * @class Roo.data.DataProxy
9471 * @extends Roo.data.Observable
9472 * This class is an abstract base class for implementations which provide retrieval of
9473 * unformatted data objects.<br>
9475 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9476 * (of the appropriate type which knows how to parse the data object) to provide a block of
9477 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9479 * Custom implementations must implement the load method as described in
9480 * {@link Roo.data.HttpProxy#load}.
9482 Roo.data.DataProxy = function(){
9486 * Fires before a network request is made to retrieve a data object.
9487 * @param {Object} This DataProxy object.
9488 * @param {Object} params The params parameter to the load function.
9493 * Fires before the load method's callback is called.
9494 * @param {Object} This DataProxy object.
9495 * @param {Object} o The data object.
9496 * @param {Object} arg The callback argument object passed to the load function.
9500 * @event loadexception
9501 * Fires if an Exception occurs during data retrieval.
9502 * @param {Object} This DataProxy object.
9503 * @param {Object} o The data object.
9504 * @param {Object} arg The callback argument object passed to the load function.
9505 * @param {Object} e The Exception.
9507 loadexception : true
9509 Roo.data.DataProxy.superclass.constructor.call(this);
9512 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9515 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9519 * Ext JS Library 1.1.1
9520 * Copyright(c) 2006-2007, Ext JS, LLC.
9522 * Originally Released Under LGPL - original licence link has changed is not relivant.
9525 * <script type="text/javascript">
9528 * @class Roo.data.MemoryProxy
9529 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9530 * to the Reader when its load method is called.
9532 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9534 Roo.data.MemoryProxy = function(data){
9538 Roo.data.MemoryProxy.superclass.constructor.call(this);
9542 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9544 * Load data from the requested source (in this case an in-memory
9545 * data object passed to the constructor), read the data object into
9546 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9547 * process that block using the passed callback.
9548 * @param {Object} params This parameter is not used by the MemoryProxy class.
9549 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9550 * object into a block of Roo.data.Records.
9551 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9552 * The function must be passed <ul>
9553 * <li>The Record block object</li>
9554 * <li>The "arg" argument from the load function</li>
9555 * <li>A boolean success indicator</li>
9557 * @param {Object} scope The scope in which to call the callback
9558 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9560 load : function(params, reader, callback, scope, arg){
9561 params = params || {};
9564 result = reader.readRecords(this.data);
9566 this.fireEvent("loadexception", this, arg, null, e);
9567 callback.call(scope, null, arg, false);
9570 callback.call(scope, result, arg, true);
9574 update : function(params, records){
9579 * Ext JS Library 1.1.1
9580 * Copyright(c) 2006-2007, Ext JS, LLC.
9582 * Originally Released Under LGPL - original licence link has changed is not relivant.
9585 * <script type="text/javascript">
9588 * @class Roo.data.HttpProxy
9589 * @extends Roo.data.DataProxy
9590 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9591 * configured to reference a certain URL.<br><br>
9593 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9594 * from which the running page was served.<br><br>
9596 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9598 * Be aware that to enable the browser to parse an XML document, the server must set
9599 * the Content-Type header in the HTTP response to "text/xml".
9601 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9602 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9603 * will be used to make the request.
9605 Roo.data.HttpProxy = function(conn){
9606 Roo.data.HttpProxy.superclass.constructor.call(this);
9607 // is conn a conn config or a real conn?
9609 this.useAjax = !conn || !conn.events;
9613 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9614 // thse are take from connection...
9617 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9620 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9621 * extra parameters to each request made by this object. (defaults to undefined)
9624 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9625 * to each request made by this object. (defaults to undefined)
9628 * @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)
9631 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9634 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9640 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9644 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9645 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9646 * a finer-grained basis than the DataProxy events.
9648 getConnection : function(){
9649 return this.useAjax ? Roo.Ajax : this.conn;
9653 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9654 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9655 * process that block using the passed callback.
9656 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9657 * for the request to the remote server.
9658 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9659 * object into a block of Roo.data.Records.
9660 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9661 * The function must be passed <ul>
9662 * <li>The Record block object</li>
9663 * <li>The "arg" argument from the load function</li>
9664 * <li>A boolean success indicator</li>
9666 * @param {Object} scope The scope in which to call the callback
9667 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9669 load : function(params, reader, callback, scope, arg){
9670 if(this.fireEvent("beforeload", this, params) !== false){
9672 params : params || {},
9674 callback : callback,
9679 callback : this.loadResponse,
9683 Roo.applyIf(o, this.conn);
9684 if(this.activeRequest){
9685 Roo.Ajax.abort(this.activeRequest);
9687 this.activeRequest = Roo.Ajax.request(o);
9689 this.conn.request(o);
9692 callback.call(scope||this, null, arg, false);
9697 loadResponse : function(o, success, response){
9698 delete this.activeRequest;
9700 this.fireEvent("loadexception", this, o, response);
9701 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9706 result = o.reader.read(response);
9708 this.fireEvent("loadexception", this, o, response, e);
9709 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9713 this.fireEvent("load", this, o, o.request.arg);
9714 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9718 update : function(dataSet){
9723 updateResponse : function(dataSet){
9728 * Ext JS Library 1.1.1
9729 * Copyright(c) 2006-2007, Ext JS, LLC.
9731 * Originally Released Under LGPL - original licence link has changed is not relivant.
9734 * <script type="text/javascript">
9738 * @class Roo.data.ScriptTagProxy
9739 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9740 * other than the originating domain of the running page.<br><br>
9742 * <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
9743 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9745 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9746 * source code that is used as the source inside a <script> tag.<br><br>
9748 * In order for the browser to process the returned data, the server must wrap the data object
9749 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9750 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9751 * depending on whether the callback name was passed:
9754 boolean scriptTag = false;
9755 String cb = request.getParameter("callback");
9758 response.setContentType("text/javascript");
9760 response.setContentType("application/x-json");
9762 Writer out = response.getWriter();
9764 out.write(cb + "(");
9766 out.print(dataBlock.toJsonString());
9773 * @param {Object} config A configuration object.
9775 Roo.data.ScriptTagProxy = function(config){
9776 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9777 Roo.apply(this, config);
9778 this.head = document.getElementsByTagName("head")[0];
9781 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9783 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9785 * @cfg {String} url The URL from which to request the data object.
9788 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9792 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9793 * the server the name of the callback function set up by the load call to process the returned data object.
9794 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9795 * javascript output which calls this named function passing the data object as its only parameter.
9797 callbackParam : "callback",
9799 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9800 * name to the request.
9805 * Load data from the configured URL, read the data object into
9806 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9807 * process that block using the passed callback.
9808 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9809 * for the request to the remote server.
9810 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9811 * object into a block of Roo.data.Records.
9812 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9813 * The function must be passed <ul>
9814 * <li>The Record block object</li>
9815 * <li>The "arg" argument from the load function</li>
9816 * <li>A boolean success indicator</li>
9818 * @param {Object} scope The scope in which to call the callback
9819 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9821 load : function(params, reader, callback, scope, arg){
9822 if(this.fireEvent("beforeload", this, params) !== false){
9824 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9827 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9829 url += "&_dc=" + (new Date().getTime());
9831 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9834 cb : "stcCallback"+transId,
9835 scriptId : "stcScript"+transId,
9839 callback : callback,
9845 window[trans.cb] = function(o){
9846 conn.handleResponse(o, trans);
9849 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9851 if(this.autoAbort !== false){
9855 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9857 var script = document.createElement("script");
9858 script.setAttribute("src", url);
9859 script.setAttribute("type", "text/javascript");
9860 script.setAttribute("id", trans.scriptId);
9861 this.head.appendChild(script);
9865 callback.call(scope||this, null, arg, false);
9870 isLoading : function(){
9871 return this.trans ? true : false;
9875 * Abort the current server request.
9878 if(this.isLoading()){
9879 this.destroyTrans(this.trans);
9884 destroyTrans : function(trans, isLoaded){
9885 this.head.removeChild(document.getElementById(trans.scriptId));
9886 clearTimeout(trans.timeoutId);
9888 window[trans.cb] = undefined;
9890 delete window[trans.cb];
9893 // if hasn't been loaded, wait for load to remove it to prevent script error
9894 window[trans.cb] = function(){
9895 window[trans.cb] = undefined;
9897 delete window[trans.cb];
9904 handleResponse : function(o, trans){
9906 this.destroyTrans(trans, true);
9909 result = trans.reader.readRecords(o);
9911 this.fireEvent("loadexception", this, o, trans.arg, e);
9912 trans.callback.call(trans.scope||window, null, trans.arg, false);
9915 this.fireEvent("load", this, o, trans.arg);
9916 trans.callback.call(trans.scope||window, result, trans.arg, true);
9920 handleFailure : function(trans){
9922 this.destroyTrans(trans, false);
9923 this.fireEvent("loadexception", this, null, trans.arg);
9924 trans.callback.call(trans.scope||window, null, trans.arg, false);
9928 * Ext JS Library 1.1.1
9929 * Copyright(c) 2006-2007, Ext JS, LLC.
9931 * Originally Released Under LGPL - original licence link has changed is not relivant.
9934 * <script type="text/javascript">
9938 * @class Roo.data.JsonReader
9939 * @extends Roo.data.DataReader
9940 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9941 * based on mappings in a provided Roo.data.Record constructor.
9943 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9944 * in the reply previously.
9949 var RecordDef = Roo.data.Record.create([
9950 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9951 {name: 'occupation'} // This field will use "occupation" as the mapping.
9953 var myReader = new Roo.data.JsonReader({
9954 totalProperty: "results", // The property which contains the total dataset size (optional)
9955 root: "rows", // The property which contains an Array of row objects
9956 id: "id" // The property within each row object that provides an ID for the record (optional)
9960 * This would consume a JSON file like this:
9962 { 'results': 2, 'rows': [
9963 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9964 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9967 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9968 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9969 * paged from the remote server.
9970 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9971 * @cfg {String} root name of the property which contains the Array of row objects.
9972 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9974 * Create a new JsonReader
9975 * @param {Object} meta Metadata configuration options
9976 * @param {Object} recordType Either an Array of field definition objects,
9977 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9979 Roo.data.JsonReader = function(meta, recordType){
9982 // set some defaults:
9984 totalProperty: 'total',
9985 successProperty : 'success',
9990 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9992 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9995 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9996 * Used by Store query builder to append _requestMeta to params.
9999 metaFromRemote : false,
10001 * This method is only used by a DataProxy which has retrieved data from a remote server.
10002 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10003 * @return {Object} data A data block which is used by an Roo.data.Store object as
10004 * a cache of Roo.data.Records.
10006 read : function(response){
10007 var json = response.responseText;
10009 var o = /* eval:var:o */ eval("("+json+")");
10011 throw {message: "JsonReader.read: Json object not found"};
10017 this.metaFromRemote = true;
10018 this.meta = o.metaData;
10019 this.recordType = Roo.data.Record.create(o.metaData.fields);
10020 this.onMetaChange(this.meta, this.recordType, o);
10022 return this.readRecords(o);
10025 // private function a store will implement
10026 onMetaChange : function(meta, recordType, o){
10033 simpleAccess: function(obj, subsc) {
10040 getJsonAccessor: function(){
10042 return function(expr) {
10044 return(re.test(expr))
10045 ? new Function("obj", "return obj." + expr)
10050 return Roo.emptyFn;
10055 * Create a data block containing Roo.data.Records from an XML document.
10056 * @param {Object} o An object which contains an Array of row objects in the property specified
10057 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10058 * which contains the total size of the dataset.
10059 * @return {Object} data A data block which is used by an Roo.data.Store object as
10060 * a cache of Roo.data.Records.
10062 readRecords : function(o){
10064 * After any data loads, the raw JSON data is available for further custom processing.
10068 var s = this.meta, Record = this.recordType,
10069 f = Record.prototype.fields, fi = f.items, fl = f.length;
10071 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10073 if(s.totalProperty) {
10074 this.getTotal = this.getJsonAccessor(s.totalProperty);
10076 if(s.successProperty) {
10077 this.getSuccess = this.getJsonAccessor(s.successProperty);
10079 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10081 var g = this.getJsonAccessor(s.id);
10082 this.getId = function(rec) {
10084 return (r === undefined || r === "") ? null : r;
10087 this.getId = function(){return null;};
10090 for(var jj = 0; jj < fl; jj++){
10092 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10093 this.ef[jj] = this.getJsonAccessor(map);
10097 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10098 if(s.totalProperty){
10099 var vt = parseInt(this.getTotal(o), 10);
10104 if(s.successProperty){
10105 var vs = this.getSuccess(o);
10106 if(vs === false || vs === 'false'){
10111 for(var i = 0; i < c; i++){
10114 var id = this.getId(n);
10115 for(var j = 0; j < fl; j++){
10117 var v = this.ef[j](n);
10119 Roo.log('missing convert for ' + f.name);
10123 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10125 var record = new Record(values, id);
10127 records[i] = record;
10133 totalRecords : totalRecords
10138 * Ext JS Library 1.1.1
10139 * Copyright(c) 2006-2007, Ext JS, LLC.
10141 * Originally Released Under LGPL - original licence link has changed is not relivant.
10144 * <script type="text/javascript">
10148 * @class Roo.data.ArrayReader
10149 * @extends Roo.data.DataReader
10150 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10151 * Each element of that Array represents a row of data fields. The
10152 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10153 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10157 var RecordDef = Roo.data.Record.create([
10158 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10159 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10161 var myReader = new Roo.data.ArrayReader({
10162 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10166 * This would consume an Array like this:
10168 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10170 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10172 * Create a new JsonReader
10173 * @param {Object} meta Metadata configuration options.
10174 * @param {Object} recordType Either an Array of field definition objects
10175 * as specified to {@link Roo.data.Record#create},
10176 * or an {@link Roo.data.Record} object
10177 * created using {@link Roo.data.Record#create}.
10179 Roo.data.ArrayReader = function(meta, recordType){
10180 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10183 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10185 * Create a data block containing Roo.data.Records from an XML document.
10186 * @param {Object} o An Array of row objects which represents the dataset.
10187 * @return {Object} data A data block which is used by an Roo.data.Store object as
10188 * a cache of Roo.data.Records.
10190 readRecords : function(o){
10191 var sid = this.meta ? this.meta.id : null;
10192 var recordType = this.recordType, fields = recordType.prototype.fields;
10195 for(var i = 0; i < root.length; i++){
10198 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10199 for(var j = 0, jlen = fields.length; j < jlen; j++){
10200 var f = fields.items[j];
10201 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10202 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10204 values[f.name] = v;
10206 var record = new recordType(values, id);
10208 records[records.length] = record;
10212 totalRecords : records.length
10221 * @class Roo.bootstrap.ComboBox
10222 * @extends Roo.bootstrap.TriggerField
10223 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10224 * @cfg {Boolean} append (true|false) default false
10225 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10226 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10227 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10228 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10229 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10231 * Create a new ComboBox.
10232 * @param {Object} config Configuration options
10234 Roo.bootstrap.ComboBox = function(config){
10235 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10239 * Fires when the dropdown list is expanded
10240 * @param {Roo.bootstrap.ComboBox} combo This combo box
10245 * Fires when the dropdown list is collapsed
10246 * @param {Roo.bootstrap.ComboBox} combo This combo box
10250 * @event beforeselect
10251 * Fires before a list item is selected. Return false to cancel the selection.
10252 * @param {Roo.bootstrap.ComboBox} combo This combo box
10253 * @param {Roo.data.Record} record The data record returned from the underlying store
10254 * @param {Number} index The index of the selected item in the dropdown list
10256 'beforeselect' : true,
10259 * Fires when a list item is selected
10260 * @param {Roo.bootstrap.ComboBox} combo This combo box
10261 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10262 * @param {Number} index The index of the selected item in the dropdown list
10266 * @event beforequery
10267 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10268 * The event object passed has these properties:
10269 * @param {Roo.bootstrap.ComboBox} combo This combo box
10270 * @param {String} query The query
10271 * @param {Boolean} forceAll true to force "all" query
10272 * @param {Boolean} cancel true to cancel the query
10273 * @param {Object} e The query event object
10275 'beforequery': true,
10278 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10279 * @param {Roo.bootstrap.ComboBox} combo This combo box
10284 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10285 * @param {Roo.bootstrap.ComboBox} combo This combo box
10286 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10291 * Fires when the remove value from the combobox array
10292 * @param {Roo.bootstrap.ComboBox} combo This combo box
10299 this.tickItems = [];
10301 this.selectedIndex = -1;
10302 if(this.mode == 'local'){
10303 if(config.queryDelay === undefined){
10304 this.queryDelay = 10;
10306 if(config.minChars === undefined){
10312 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10315 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10316 * rendering into an Roo.Editor, defaults to false)
10319 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10320 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10323 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10326 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10327 * the dropdown list (defaults to undefined, with no header element)
10331 * @cfg {String/Roo.Template} tpl The template to use to render the output
10335 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10337 listWidth: undefined,
10339 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10340 * mode = 'remote' or 'text' if mode = 'local')
10342 displayField: undefined,
10344 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10345 * mode = 'remote' or 'value' if mode = 'local').
10346 * Note: use of a valueField requires the user make a selection
10347 * in order for a value to be mapped.
10349 valueField: undefined,
10353 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10354 * field's data value (defaults to the underlying DOM element's name)
10356 hiddenName: undefined,
10358 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10362 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10364 selectedClass: 'active',
10367 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10371 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10372 * anchor positions (defaults to 'tl-bl')
10374 listAlign: 'tl-bl?',
10376 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10380 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10381 * query specified by the allQuery config option (defaults to 'query')
10383 triggerAction: 'query',
10385 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10386 * (defaults to 4, does not apply if editable = false)
10390 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10391 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10395 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10396 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10400 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10401 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10405 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10406 * when editable = true (defaults to false)
10408 selectOnFocus:false,
10410 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10412 queryParam: 'query',
10414 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10415 * when mode = 'remote' (defaults to 'Loading...')
10417 loadingText: 'Loading...',
10419 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10423 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10427 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10428 * traditional select (defaults to true)
10432 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10436 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10440 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10441 * listWidth has a higher value)
10445 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10446 * allow the user to set arbitrary text into the field (defaults to false)
10448 forceSelection:false,
10450 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10451 * if typeAhead = true (defaults to 250)
10453 typeAheadDelay : 250,
10455 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10456 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10458 valueNotFoundText : undefined,
10460 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10462 blockFocus : false,
10465 * @cfg {Boolean} disableClear Disable showing of clear button.
10467 disableClear : false,
10469 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10471 alwaysQuery : false,
10474 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10488 btnPosition : 'right',
10489 triggerList : true,
10490 showToggleBtn : true,
10491 // element that contains real text value.. (when hidden is used..)
10493 getAutoCreate : function()
10500 if(!this.tickable){
10501 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10506 * ComboBox with tickable selections
10509 var align = this.labelAlign || this.parentLabelAlign();
10512 cls : 'form-group roo-combobox-tickable' //input-group
10518 cls : 'tickable-buttons',
10523 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10530 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10537 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10544 Roo.each(buttons.cn, function(c){
10546 c.cls += ' btn-' + _this.size;
10549 if (_this.disabled) {
10560 cls: 'form-hidden-field'
10564 cls: 'select2-choices',
10568 cls: 'select2-search-field',
10580 cls: 'select2-container input-group select2-container-multi',
10585 // cls: 'typeahead typeahead-long dropdown-menu',
10586 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10591 if (align ==='left' && this.fieldLabel.length) {
10593 Roo.log("left and has label");
10599 cls : 'control-label col-sm-' + this.labelWidth,
10600 html : this.fieldLabel
10604 cls : "col-sm-" + (12 - this.labelWidth),
10611 } else if ( this.fieldLabel.length) {
10617 //cls : 'input-group-addon',
10618 html : this.fieldLabel
10628 Roo.log(" no label && no align");
10635 ['xs','sm','md','lg'].map(function(size){
10636 if (settings[size]) {
10637 cfg.cls += ' col-' + size + '-' + settings[size];
10646 initEvents: function()
10650 throw "can not find store for combo";
10652 this.store = Roo.factory(this.store, Roo.data);
10655 this.initTickableEvents();
10659 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10661 if(this.hiddenName){
10663 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10665 this.hiddenField.dom.value =
10666 this.hiddenValue !== undefined ? this.hiddenValue :
10667 this.value !== undefined ? this.value : '';
10669 // prevent input submission
10670 this.el.dom.removeAttribute('name');
10671 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10676 // this.el.dom.setAttribute('autocomplete', 'off');
10679 var cls = 'x-combo-list';
10681 //this.list = new Roo.Layer({
10682 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10688 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10689 _this.list.setWidth(lw);
10692 this.list.on('mouseover', this.onViewOver, this);
10693 this.list.on('mousemove', this.onViewMove, this);
10695 this.list.on('scroll', this.onViewScroll, this);
10698 this.list.swallowEvent('mousewheel');
10699 this.assetHeight = 0;
10702 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10703 this.assetHeight += this.header.getHeight();
10706 this.innerList = this.list.createChild({cls:cls+'-inner'});
10707 this.innerList.on('mouseover', this.onViewOver, this);
10708 this.innerList.on('mousemove', this.onViewMove, this);
10709 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10711 if(this.allowBlank && !this.pageSize && !this.disableClear){
10712 this.footer = this.list.createChild({cls:cls+'-ft'});
10713 this.pageTb = new Roo.Toolbar(this.footer);
10717 this.footer = this.list.createChild({cls:cls+'-ft'});
10718 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10719 {pageSize: this.pageSize});
10723 if (this.pageTb && this.allowBlank && !this.disableClear) {
10725 this.pageTb.add(new Roo.Toolbar.Fill(), {
10726 cls: 'x-btn-icon x-btn-clear',
10728 handler: function()
10731 _this.clearValue();
10732 _this.onSelect(false, -1);
10737 this.assetHeight += this.footer.getHeight();
10742 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10745 this.view = new Roo.View(this.list, this.tpl, {
10746 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10748 //this.view.wrapEl.setDisplayed(false);
10749 this.view.on('click', this.onViewClick, this);
10753 this.store.on('beforeload', this.onBeforeLoad, this);
10754 this.store.on('load', this.onLoad, this);
10755 this.store.on('loadexception', this.onLoadException, this);
10757 if(this.resizable){
10758 this.resizer = new Roo.Resizable(this.list, {
10759 pinned:true, handles:'se'
10761 this.resizer.on('resize', function(r, w, h){
10762 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10763 this.listWidth = w;
10764 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10765 this.restrictHeight();
10767 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10770 if(!this.editable){
10771 this.editable = true;
10772 this.setEditable(false);
10777 if (typeof(this.events.add.listeners) != 'undefined') {
10779 this.addicon = this.wrap.createChild(
10780 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10782 this.addicon.on('click', function(e) {
10783 this.fireEvent('add', this);
10786 if (typeof(this.events.edit.listeners) != 'undefined') {
10788 this.editicon = this.wrap.createChild(
10789 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10790 if (this.addicon) {
10791 this.editicon.setStyle('margin-left', '40px');
10793 this.editicon.on('click', function(e) {
10795 // we fire even if inothing is selected..
10796 this.fireEvent('edit', this, this.lastData );
10802 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10803 "up" : function(e){
10804 this.inKeyMode = true;
10808 "down" : function(e){
10809 if(!this.isExpanded()){
10810 this.onTriggerClick();
10812 this.inKeyMode = true;
10817 "enter" : function(e){
10818 // this.onViewClick();
10822 if(this.fireEvent("specialkey", this, e)){
10823 this.onViewClick(false);
10829 "esc" : function(e){
10833 "tab" : function(e){
10836 if(this.fireEvent("specialkey", this, e)){
10837 this.onViewClick(false);
10845 doRelay : function(foo, bar, hname){
10846 if(hname == 'down' || this.scope.isExpanded()){
10847 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10856 this.queryDelay = Math.max(this.queryDelay || 10,
10857 this.mode == 'local' ? 10 : 250);
10860 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10862 if(this.typeAhead){
10863 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10865 if(this.editable !== false){
10866 this.inputEl().on("keyup", this.onKeyUp, this);
10868 if(this.forceSelection){
10869 this.inputEl().on('blur', this.doForce, this);
10873 this.choices = this.el.select('ul.select2-choices', true).first();
10874 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10878 initTickableEvents: function()
10882 if(this.hiddenName){
10884 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10886 this.hiddenField.dom.value =
10887 this.hiddenValue !== undefined ? this.hiddenValue :
10888 this.value !== undefined ? this.value : '';
10890 // prevent input submission
10891 this.el.dom.removeAttribute('name');
10892 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10897 // this.list = this.el.select('ul.dropdown-menu',true).first();
10899 this.choices = this.el.select('ul.select2-choices', true).first();
10900 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10901 if(this.triggerList){
10902 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10905 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10906 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10908 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10909 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10911 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10912 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10914 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10915 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10916 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10919 this.cancelBtn.hide();
10924 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10925 _this.list.setWidth(lw);
10928 this.list.on('mouseover', this.onViewOver, this);
10929 this.list.on('mousemove', this.onViewMove, this);
10931 this.list.on('scroll', this.onViewScroll, this);
10934 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>';
10937 this.view = new Roo.View(this.list, this.tpl, {
10938 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10941 //this.view.wrapEl.setDisplayed(false);
10942 this.view.on('click', this.onViewClick, this);
10946 this.store.on('beforeload', this.onBeforeLoad, this);
10947 this.store.on('load', this.onLoad, this);
10948 this.store.on('loadexception', this.onLoadException, this);
10950 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10951 // "up" : function(e){
10952 // this.inKeyMode = true;
10953 // this.selectPrev();
10956 // "down" : function(e){
10957 // if(!this.isExpanded()){
10958 // this.onTriggerClick();
10960 // this.inKeyMode = true;
10961 // this.selectNext();
10965 // "enter" : function(e){
10966 //// this.onViewClick();
10968 // this.collapse();
10970 // if(this.fireEvent("specialkey", this, e)){
10971 // this.onViewClick(false);
10977 // "esc" : function(e){
10978 // this.collapse();
10981 // "tab" : function(e){
10982 // this.collapse();
10984 // if(this.fireEvent("specialkey", this, e)){
10985 // this.onViewClick(false);
10993 // doRelay : function(foo, bar, hname){
10994 // if(hname == 'down' || this.scope.isExpanded()){
10995 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11000 // forceKeyDown: true
11004 this.queryDelay = Math.max(this.queryDelay || 10,
11005 this.mode == 'local' ? 10 : 250);
11008 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11010 if(this.typeAhead){
11011 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11015 onDestroy : function(){
11017 this.view.setStore(null);
11018 this.view.el.removeAllListeners();
11019 this.view.el.remove();
11020 this.view.purgeListeners();
11023 this.list.dom.innerHTML = '';
11027 this.store.un('beforeload', this.onBeforeLoad, this);
11028 this.store.un('load', this.onLoad, this);
11029 this.store.un('loadexception', this.onLoadException, this);
11031 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11035 fireKey : function(e){
11036 if(e.isNavKeyPress() && !this.list.isVisible()){
11037 this.fireEvent("specialkey", this, e);
11042 onResize: function(w, h){
11043 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11045 // if(typeof w != 'number'){
11046 // // we do not handle it!?!?
11049 // var tw = this.trigger.getWidth();
11050 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11051 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11053 // this.inputEl().setWidth( this.adjustWidth('input', x));
11055 // //this.trigger.setStyle('left', x+'px');
11057 // if(this.list && this.listWidth === undefined){
11058 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11059 // this.list.setWidth(lw);
11060 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11068 * Allow or prevent the user from directly editing the field text. If false is passed,
11069 * the user will only be able to select from the items defined in the dropdown list. This method
11070 * is the runtime equivalent of setting the 'editable' config option at config time.
11071 * @param {Boolean} value True to allow the user to directly edit the field text
11073 setEditable : function(value){
11074 if(value == this.editable){
11077 this.editable = value;
11079 this.inputEl().dom.setAttribute('readOnly', true);
11080 this.inputEl().on('mousedown', this.onTriggerClick, this);
11081 this.inputEl().addClass('x-combo-noedit');
11083 this.inputEl().dom.setAttribute('readOnly', false);
11084 this.inputEl().un('mousedown', this.onTriggerClick, this);
11085 this.inputEl().removeClass('x-combo-noedit');
11091 onBeforeLoad : function(combo,opts){
11092 if(!this.hasFocus){
11096 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11098 // this.restrictHeight();
11099 this.selectedIndex = -1;
11103 onLoad : function(){
11105 this.hasQuery = false;
11107 if(!this.hasFocus){
11111 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11112 this.loading.hide();
11115 if(this.store.getCount() > 0){
11117 // this.restrictHeight();
11118 if(this.lastQuery == this.allQuery){
11119 if(this.editable && !this.tickable){
11120 this.inputEl().dom.select();
11124 !this.selectByValue(this.value, true) &&
11125 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11126 this.store.lastOptions.add != true)
11128 this.select(0, true);
11131 if(this.autoFocus){
11134 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11135 this.taTask.delay(this.typeAheadDelay);
11139 this.onEmptyResults();
11145 onLoadException : function()
11147 this.hasQuery = false;
11149 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11150 this.loading.hide();
11154 Roo.log(this.store.reader.jsonData);
11155 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11157 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11163 onTypeAhead : function(){
11164 if(this.store.getCount() > 0){
11165 var r = this.store.getAt(0);
11166 var newValue = r.data[this.displayField];
11167 var len = newValue.length;
11168 var selStart = this.getRawValue().length;
11170 if(selStart != len){
11171 this.setRawValue(newValue);
11172 this.selectText(selStart, newValue.length);
11178 onSelect : function(record, index){
11180 if(this.fireEvent('beforeselect', this, record, index) !== false){
11182 this.setFromData(index > -1 ? record.data : false);
11185 this.fireEvent('select', this, record, index);
11190 * Returns the currently selected field value or empty string if no value is set.
11191 * @return {String} value The selected value
11193 getValue : function(){
11196 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11199 if(this.valueField){
11200 return typeof this.value != 'undefined' ? this.value : '';
11202 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11207 * Clears any text/value currently set in the field
11209 clearValue : function(){
11210 if(this.hiddenField){
11211 this.hiddenField.dom.value = '';
11214 this.setRawValue('');
11215 this.lastSelectionText = '';
11220 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11221 * will be displayed in the field. If the value does not match the data value of an existing item,
11222 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11223 * Otherwise the field will be blank (although the value will still be set).
11224 * @param {String} value The value to match
11226 setValue : function(v){
11233 if(this.valueField){
11234 var r = this.findRecord(this.valueField, v);
11236 text = r.data[this.displayField];
11237 }else if(this.valueNotFoundText !== undefined){
11238 text = this.valueNotFoundText;
11241 this.lastSelectionText = text;
11242 if(this.hiddenField){
11243 this.hiddenField.dom.value = v;
11245 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11249 * @property {Object} the last set data for the element
11254 * Sets the value of the field based on a object which is related to the record format for the store.
11255 * @param {Object} value the value to set as. or false on reset?
11257 setFromData : function(o){
11260 if(typeof o.display_name !== 'string'){
11261 for(var i=0;i<o.display_name.length;i++){
11262 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11270 var dv = ''; // display value
11271 var vv = ''; // value value..
11273 if (this.displayField) {
11274 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11276 // this is an error condition!!!
11277 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11280 if(this.valueField){
11281 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11284 if(this.hiddenField){
11285 this.hiddenField.dom.value = vv;
11287 this.lastSelectionText = dv;
11288 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11292 // no hidden field.. - we store the value in 'value', but still display
11293 // display field!!!!
11294 this.lastSelectionText = dv;
11295 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11301 reset : function(){
11302 // overridden so that last data is reset..
11303 this.setValue(this.originalValue);
11304 this.clearInvalid();
11305 this.lastData = false;
11307 this.view.clearSelections();
11311 findRecord : function(prop, value){
11313 if(this.store.getCount() > 0){
11314 this.store.each(function(r){
11315 if(r.data[prop] == value){
11325 getName: function()
11327 // returns hidden if it's set..
11328 if (!this.rendered) {return ''};
11329 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11333 onViewMove : function(e, t){
11334 this.inKeyMode = false;
11338 onViewOver : function(e, t){
11339 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11342 var item = this.view.findItemFromChild(t);
11345 var index = this.view.indexOf(item);
11346 this.select(index, false);
11351 onViewClick : function(view, doFocus, el, e)
11353 var index = this.view.getSelectedIndexes()[0];
11355 var r = this.store.getAt(index);
11359 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11366 Roo.each(this.tickItems, function(v,k){
11368 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11369 _this.tickItems.splice(k, 1);
11379 this.tickItems.push(r.data);
11384 this.onSelect(r, index);
11386 if(doFocus !== false && !this.blockFocus){
11387 this.inputEl().focus();
11392 restrictHeight : function(){
11393 //this.innerList.dom.style.height = '';
11394 //var inner = this.innerList.dom;
11395 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11396 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11397 //this.list.beginUpdate();
11398 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11399 this.list.alignTo(this.inputEl(), this.listAlign);
11400 this.list.alignTo(this.inputEl(), this.listAlign);
11401 //this.list.endUpdate();
11405 onEmptyResults : function(){
11410 * Returns true if the dropdown list is expanded, else false.
11412 isExpanded : function(){
11413 return this.list.isVisible();
11417 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11418 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11419 * @param {String} value The data value of the item to select
11420 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11421 * selected item if it is not currently in view (defaults to true)
11422 * @return {Boolean} True if the value matched an item in the list, else false
11424 selectByValue : function(v, scrollIntoView){
11425 if(v !== undefined && v !== null){
11426 var r = this.findRecord(this.valueField || this.displayField, v);
11428 this.select(this.store.indexOf(r), scrollIntoView);
11436 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11437 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11438 * @param {Number} index The zero-based index of the list item to select
11439 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11440 * selected item if it is not currently in view (defaults to true)
11442 select : function(index, scrollIntoView){
11443 this.selectedIndex = index;
11444 this.view.select(index);
11445 if(scrollIntoView !== false){
11446 var el = this.view.getNode(index);
11447 if(el && !this.multiple && !this.tickable){
11448 this.list.scrollChildIntoView(el, false);
11454 selectNext : function(){
11455 var ct = this.store.getCount();
11457 if(this.selectedIndex == -1){
11459 }else if(this.selectedIndex < ct-1){
11460 this.select(this.selectedIndex+1);
11466 selectPrev : function(){
11467 var ct = this.store.getCount();
11469 if(this.selectedIndex == -1){
11471 }else if(this.selectedIndex != 0){
11472 this.select(this.selectedIndex-1);
11478 onKeyUp : function(e){
11479 if(this.editable !== false && !e.isSpecialKey()){
11480 this.lastKey = e.getKey();
11481 this.dqTask.delay(this.queryDelay);
11486 validateBlur : function(){
11487 return !this.list || !this.list.isVisible();
11491 initQuery : function(){
11492 this.doQuery(this.getRawValue());
11496 doForce : function(){
11497 if(this.inputEl().dom.value.length > 0){
11498 this.inputEl().dom.value =
11499 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11505 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11506 * query allowing the query action to be canceled if needed.
11507 * @param {String} query The SQL query to execute
11508 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11509 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11510 * saved in the current store (defaults to false)
11512 doQuery : function(q, forceAll){
11514 if(q === undefined || q === null){
11519 forceAll: forceAll,
11523 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11528 forceAll = qe.forceAll;
11529 if(forceAll === true || (q.length >= this.minChars)){
11531 this.hasQuery = true;
11533 if(this.lastQuery != q || this.alwaysQuery){
11534 this.lastQuery = q;
11535 if(this.mode == 'local'){
11536 this.selectedIndex = -1;
11538 this.store.clearFilter();
11540 this.store.filter(this.displayField, q);
11544 this.store.baseParams[this.queryParam] = q;
11546 var options = {params : this.getParams(q)};
11549 options.add = true;
11550 options.params.start = this.page * this.pageSize;
11553 this.store.load(options);
11555 * this code will make the page width larger, at the beginning, the list not align correctly,
11556 * we should expand the list on onLoad
11557 * so command out it
11562 this.selectedIndex = -1;
11567 this.loadNext = false;
11571 getParams : function(q){
11573 //p[this.queryParam] = q;
11577 p.limit = this.pageSize;
11583 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11585 collapse : function(){
11586 if(!this.isExpanded()){
11594 this.cancelBtn.hide();
11595 this.trigger.show();
11598 Roo.get(document).un('mousedown', this.collapseIf, this);
11599 Roo.get(document).un('mousewheel', this.collapseIf, this);
11600 if (!this.editable) {
11601 Roo.get(document).un('keydown', this.listKeyPress, this);
11603 this.fireEvent('collapse', this);
11607 collapseIf : function(e){
11608 var in_combo = e.within(this.el);
11609 var in_list = e.within(this.list);
11610 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11612 if (in_combo || in_list || is_list) {
11613 //e.stopPropagation();
11618 this.onTickableFooterButtonClick(e, false, false);
11626 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11628 expand : function(){
11630 if(this.isExpanded() || !this.hasFocus){
11634 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11635 this.list.setWidth(lw);
11640 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11641 this.list.setWidth(lw);
11645 this.restrictHeight();
11649 this.tickItems = Roo.apply([], this.item);
11652 this.cancelBtn.show();
11653 this.trigger.hide();
11657 Roo.get(document).on('mousedown', this.collapseIf, this);
11658 Roo.get(document).on('mousewheel', this.collapseIf, this);
11659 if (!this.editable) {
11660 Roo.get(document).on('keydown', this.listKeyPress, this);
11663 this.fireEvent('expand', this);
11667 // Implements the default empty TriggerField.onTriggerClick function
11668 onTriggerClick : function(e)
11670 Roo.log('trigger click');
11672 if(this.disabled || !this.triggerList){
11677 this.loadNext = false;
11679 if(this.isExpanded()){
11681 if (!this.blockFocus) {
11682 this.inputEl().focus();
11686 this.hasFocus = true;
11687 if(this.triggerAction == 'all') {
11688 this.doQuery(this.allQuery, true);
11690 this.doQuery(this.getRawValue());
11692 if (!this.blockFocus) {
11693 this.inputEl().focus();
11698 onTickableTriggerClick : function(e)
11705 this.loadNext = false;
11706 this.hasFocus = true;
11708 if(this.triggerAction == 'all') {
11709 this.doQuery(this.allQuery, true);
11711 this.doQuery(this.getRawValue());
11715 onSearchFieldClick : function(e)
11717 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11722 this.loadNext = false;
11723 this.hasFocus = true;
11725 if(this.triggerAction == 'all') {
11726 this.doQuery(this.allQuery, true);
11728 this.doQuery(this.getRawValue());
11732 listKeyPress : function(e)
11734 //Roo.log('listkeypress');
11735 // scroll to first matching element based on key pres..
11736 if (e.isSpecialKey()) {
11739 var k = String.fromCharCode(e.getKey()).toUpperCase();
11742 var csel = this.view.getSelectedNodes();
11743 var cselitem = false;
11745 var ix = this.view.indexOf(csel[0]);
11746 cselitem = this.store.getAt(ix);
11747 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11753 this.store.each(function(v) {
11755 // start at existing selection.
11756 if (cselitem.id == v.id) {
11762 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11763 match = this.store.indexOf(v);
11769 if (match === false) {
11770 return true; // no more action?
11773 this.view.select(match);
11774 var sn = Roo.get(this.view.getSelectedNodes()[0])
11775 //sn.scrollIntoView(sn.dom.parentNode, false);
11778 onViewScroll : function(e, t){
11780 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){
11784 this.hasQuery = true;
11786 this.loading = this.list.select('.loading', true).first();
11788 if(this.loading === null){
11789 this.list.createChild({
11791 cls: 'loading select2-more-results select2-active',
11792 html: 'Loading more results...'
11795 this.loading = this.list.select('.loading', true).first();
11797 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11799 this.loading.hide();
11802 this.loading.show();
11807 this.loadNext = true;
11809 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11814 addItem : function(o)
11816 var dv = ''; // display value
11818 if (this.displayField) {
11819 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11821 // this is an error condition!!!
11822 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11829 var choice = this.choices.createChild({
11831 cls: 'select2-search-choice',
11840 cls: 'select2-search-choice-close',
11845 }, this.searchField);
11847 var close = choice.select('a.select2-search-choice-close', true).first()
11849 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11857 this.inputEl().dom.value = '';
11861 onRemoveItem : function(e, _self, o)
11863 e.preventDefault();
11864 var index = this.item.indexOf(o.data) * 1;
11867 Roo.log('not this item?!');
11871 this.item.splice(index, 1);
11876 this.fireEvent('remove', this, e);
11880 syncValue : function()
11882 if(!this.item.length){
11889 Roo.each(this.item, function(i){
11890 if(_this.valueField){
11891 value.push(i[_this.valueField]);
11898 this.value = value.join(',');
11900 if(this.hiddenField){
11901 this.hiddenField.dom.value = this.value;
11905 clearItem : function()
11907 if(!this.multiple){
11913 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11920 inputEl: function ()
11923 return this.searchField;
11925 return this.el.select('input.form-control',true).first();
11929 onTickableFooterButtonClick : function(e, btn, el)
11931 e.preventDefault();
11933 if(btn && btn.name == 'cancel'){
11934 this.tickItems = Roo.apply([], this.item);
11943 Roo.each(this.tickItems, function(o){
11954 * @cfg {Boolean} grow
11958 * @cfg {Number} growMin
11962 * @cfg {Number} growMax
11972 * Ext JS Library 1.1.1
11973 * Copyright(c) 2006-2007, Ext JS, LLC.
11975 * Originally Released Under LGPL - original licence link has changed is not relivant.
11978 * <script type="text/javascript">
11983 * @extends Roo.util.Observable
11984 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11985 * This class also supports single and multi selection modes. <br>
11986 * Create a data model bound view:
11988 var store = new Roo.data.Store(...);
11990 var view = new Roo.View({
11992 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11994 singleSelect: true,
11995 selectedClass: "ydataview-selected",
11999 // listen for node click?
12000 view.on("click", function(vw, index, node, e){
12001 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12005 dataModel.load("foobar.xml");
12007 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12009 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12010 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12012 * Note: old style constructor is still suported (container, template, config)
12015 * Create a new View
12016 * @param {Object} config The config object
12019 Roo.View = function(config, depreciated_tpl, depreciated_config){
12021 this.parent = false;
12023 if (typeof(depreciated_tpl) == 'undefined') {
12024 // new way.. - universal constructor.
12025 Roo.apply(this, config);
12026 this.el = Roo.get(this.el);
12029 this.el = Roo.get(config);
12030 this.tpl = depreciated_tpl;
12031 Roo.apply(this, depreciated_config);
12033 this.wrapEl = this.el.wrap().wrap();
12034 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12037 if(typeof(this.tpl) == "string"){
12038 this.tpl = new Roo.Template(this.tpl);
12040 // support xtype ctors..
12041 this.tpl = new Roo.factory(this.tpl, Roo);
12045 this.tpl.compile();
12050 * @event beforeclick
12051 * Fires before a click is processed. Returns false to cancel the default action.
12052 * @param {Roo.View} this
12053 * @param {Number} index The index of the target node
12054 * @param {HTMLElement} node The target node
12055 * @param {Roo.EventObject} e The raw event object
12057 "beforeclick" : true,
12060 * Fires when a template node is clicked.
12061 * @param {Roo.View} this
12062 * @param {Number} index The index of the target node
12063 * @param {HTMLElement} node The target node
12064 * @param {Roo.EventObject} e The raw event object
12069 * Fires when a template node is double clicked.
12070 * @param {Roo.View} this
12071 * @param {Number} index The index of the target node
12072 * @param {HTMLElement} node The target node
12073 * @param {Roo.EventObject} e The raw event object
12077 * @event contextmenu
12078 * Fires when a template node is right clicked.
12079 * @param {Roo.View} this
12080 * @param {Number} index The index of the target node
12081 * @param {HTMLElement} node The target node
12082 * @param {Roo.EventObject} e The raw event object
12084 "contextmenu" : true,
12086 * @event selectionchange
12087 * Fires when the selected nodes change.
12088 * @param {Roo.View} this
12089 * @param {Array} selections Array of the selected nodes
12091 "selectionchange" : true,
12094 * @event beforeselect
12095 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12096 * @param {Roo.View} this
12097 * @param {HTMLElement} node The node to be selected
12098 * @param {Array} selections Array of currently selected nodes
12100 "beforeselect" : true,
12102 * @event preparedata
12103 * Fires on every row to render, to allow you to change the data.
12104 * @param {Roo.View} this
12105 * @param {Object} data to be rendered (change this)
12107 "preparedata" : true
12115 "click": this.onClick,
12116 "dblclick": this.onDblClick,
12117 "contextmenu": this.onContextMenu,
12121 this.selections = [];
12123 this.cmp = new Roo.CompositeElementLite([]);
12125 this.store = Roo.factory(this.store, Roo.data);
12126 this.setStore(this.store, true);
12129 if ( this.footer && this.footer.xtype) {
12131 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12133 this.footer.dataSource = this.store
12134 this.footer.container = fctr;
12135 this.footer = Roo.factory(this.footer, Roo);
12136 fctr.insertFirst(this.el);
12138 // this is a bit insane - as the paging toolbar seems to detach the el..
12139 // dom.parentNode.parentNode.parentNode
12140 // they get detached?
12144 Roo.View.superclass.constructor.call(this);
12149 Roo.extend(Roo.View, Roo.util.Observable, {
12152 * @cfg {Roo.data.Store} store Data store to load data from.
12157 * @cfg {String|Roo.Element} el The container element.
12162 * @cfg {String|Roo.Template} tpl The template used by this View
12166 * @cfg {String} dataName the named area of the template to use as the data area
12167 * Works with domtemplates roo-name="name"
12171 * @cfg {String} selectedClass The css class to add to selected nodes
12173 selectedClass : "x-view-selected",
12175 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12180 * @cfg {String} text to display on mask (default Loading)
12184 * @cfg {Boolean} multiSelect Allow multiple selection
12186 multiSelect : false,
12188 * @cfg {Boolean} singleSelect Allow single selection
12190 singleSelect: false,
12193 * @cfg {Boolean} toggleSelect - selecting
12195 toggleSelect : false,
12198 * @cfg {Boolean} tickable - selecting
12203 * Returns the element this view is bound to.
12204 * @return {Roo.Element}
12206 getEl : function(){
12207 return this.wrapEl;
12213 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12215 refresh : function(){
12216 Roo.log('refresh');
12219 // if we are using something like 'domtemplate', then
12220 // the what gets used is:
12221 // t.applySubtemplate(NAME, data, wrapping data..)
12222 // the outer template then get' applied with
12223 // the store 'extra data'
12224 // and the body get's added to the
12225 // roo-name="data" node?
12226 // <span class='roo-tpl-{name}'></span> ?????
12230 this.clearSelections();
12231 this.el.update("");
12233 var records = this.store.getRange();
12234 if(records.length < 1) {
12236 // is this valid?? = should it render a template??
12238 this.el.update(this.emptyText);
12242 if (this.dataName) {
12243 this.el.update(t.apply(this.store.meta)); //????
12244 el = this.el.child('.roo-tpl-' + this.dataName);
12247 for(var i = 0, len = records.length; i < len; i++){
12248 var data = this.prepareData(records[i].data, i, records[i]);
12249 this.fireEvent("preparedata", this, data, i, records[i]);
12251 var d = Roo.apply({}, data);
12254 Roo.apply(d, {'roo-id' : Roo.id()});
12258 Roo.each(this.parent.item, function(item){
12259 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12262 Roo.apply(d, {'roo-data-checked' : 'checked'});
12266 html[html.length] = Roo.util.Format.trim(
12268 t.applySubtemplate(this.dataName, d, this.store.meta) :
12275 el.update(html.join(""));
12276 this.nodes = el.dom.childNodes;
12277 this.updateIndexes(0);
12282 * Function to override to reformat the data that is sent to
12283 * the template for each node.
12284 * DEPRICATED - use the preparedata event handler.
12285 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12286 * a JSON object for an UpdateManager bound view).
12288 prepareData : function(data, index, record)
12290 this.fireEvent("preparedata", this, data, index, record);
12294 onUpdate : function(ds, record){
12295 Roo.log('on update');
12296 this.clearSelections();
12297 var index = this.store.indexOf(record);
12298 var n = this.nodes[index];
12299 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12300 n.parentNode.removeChild(n);
12301 this.updateIndexes(index, index);
12307 onAdd : function(ds, records, index)
12309 Roo.log(['on Add', ds, records, index] );
12310 this.clearSelections();
12311 if(this.nodes.length == 0){
12315 var n = this.nodes[index];
12316 for(var i = 0, len = records.length; i < len; i++){
12317 var d = this.prepareData(records[i].data, i, records[i]);
12319 this.tpl.insertBefore(n, d);
12322 this.tpl.append(this.el, d);
12325 this.updateIndexes(index);
12328 onRemove : function(ds, record, index){
12329 Roo.log('onRemove');
12330 this.clearSelections();
12331 var el = this.dataName ?
12332 this.el.child('.roo-tpl-' + this.dataName) :
12335 el.dom.removeChild(this.nodes[index]);
12336 this.updateIndexes(index);
12340 * Refresh an individual node.
12341 * @param {Number} index
12343 refreshNode : function(index){
12344 this.onUpdate(this.store, this.store.getAt(index));
12347 updateIndexes : function(startIndex, endIndex){
12348 var ns = this.nodes;
12349 startIndex = startIndex || 0;
12350 endIndex = endIndex || ns.length - 1;
12351 for(var i = startIndex; i <= endIndex; i++){
12352 ns[i].nodeIndex = i;
12357 * Changes the data store this view uses and refresh the view.
12358 * @param {Store} store
12360 setStore : function(store, initial){
12361 if(!initial && this.store){
12362 this.store.un("datachanged", this.refresh);
12363 this.store.un("add", this.onAdd);
12364 this.store.un("remove", this.onRemove);
12365 this.store.un("update", this.onUpdate);
12366 this.store.un("clear", this.refresh);
12367 this.store.un("beforeload", this.onBeforeLoad);
12368 this.store.un("load", this.onLoad);
12369 this.store.un("loadexception", this.onLoad);
12373 store.on("datachanged", this.refresh, this);
12374 store.on("add", this.onAdd, this);
12375 store.on("remove", this.onRemove, this);
12376 store.on("update", this.onUpdate, this);
12377 store.on("clear", this.refresh, this);
12378 store.on("beforeload", this.onBeforeLoad, this);
12379 store.on("load", this.onLoad, this);
12380 store.on("loadexception", this.onLoad, this);
12388 * onbeforeLoad - masks the loading area.
12391 onBeforeLoad : function(store,opts)
12393 Roo.log('onBeforeLoad');
12395 this.el.update("");
12397 this.el.mask(this.mask ? this.mask : "Loading" );
12399 onLoad : function ()
12406 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12407 * @param {HTMLElement} node
12408 * @return {HTMLElement} The template node
12410 findItemFromChild : function(node){
12411 var el = this.dataName ?
12412 this.el.child('.roo-tpl-' + this.dataName,true) :
12415 if(!node || node.parentNode == el){
12418 var p = node.parentNode;
12419 while(p && p != el){
12420 if(p.parentNode == el){
12429 onClick : function(e){
12430 var item = this.findItemFromChild(e.getTarget());
12432 var index = this.indexOf(item);
12433 if(this.onItemClick(item, index, e) !== false){
12434 this.fireEvent("click", this, index, item, e);
12437 this.clearSelections();
12442 onContextMenu : function(e){
12443 var item = this.findItemFromChild(e.getTarget());
12445 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12450 onDblClick : function(e){
12451 var item = this.findItemFromChild(e.getTarget());
12453 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12457 onItemClick : function(item, index, e)
12459 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12462 if (this.toggleSelect) {
12463 var m = this.isSelected(item) ? 'unselect' : 'select';
12466 _t[m](item, true, false);
12469 if(this.multiSelect || this.singleSelect){
12470 if(this.multiSelect && e.shiftKey && this.lastSelection){
12471 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12473 this.select(item, this.multiSelect && e.ctrlKey);
12474 this.lastSelection = item;
12477 if(!this.tickable){
12478 e.preventDefault();
12486 * Get the number of selected nodes.
12489 getSelectionCount : function(){
12490 return this.selections.length;
12494 * Get the currently selected nodes.
12495 * @return {Array} An array of HTMLElements
12497 getSelectedNodes : function(){
12498 return this.selections;
12502 * Get the indexes of the selected nodes.
12505 getSelectedIndexes : function(){
12506 var indexes = [], s = this.selections;
12507 for(var i = 0, len = s.length; i < len; i++){
12508 indexes.push(s[i].nodeIndex);
12514 * Clear all selections
12515 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12517 clearSelections : function(suppressEvent){
12518 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12519 this.cmp.elements = this.selections;
12520 this.cmp.removeClass(this.selectedClass);
12521 this.selections = [];
12522 if(!suppressEvent){
12523 this.fireEvent("selectionchange", this, this.selections);
12529 * Returns true if the passed node is selected
12530 * @param {HTMLElement/Number} node The node or node index
12531 * @return {Boolean}
12533 isSelected : function(node){
12534 var s = this.selections;
12538 node = this.getNode(node);
12539 return s.indexOf(node) !== -1;
12544 * @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
12545 * @param {Boolean} keepExisting (optional) true to keep existing selections
12546 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12548 select : function(nodeInfo, keepExisting, suppressEvent){
12549 if(nodeInfo instanceof Array){
12551 this.clearSelections(true);
12553 for(var i = 0, len = nodeInfo.length; i < len; i++){
12554 this.select(nodeInfo[i], true, true);
12558 var node = this.getNode(nodeInfo);
12559 if(!node || this.isSelected(node)){
12560 return; // already selected.
12563 this.clearSelections(true);
12565 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12566 Roo.fly(node).addClass(this.selectedClass);
12567 this.selections.push(node);
12568 if(!suppressEvent){
12569 this.fireEvent("selectionchange", this, this.selections);
12577 * @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
12578 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12579 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12581 unselect : function(nodeInfo, keepExisting, suppressEvent)
12583 if(nodeInfo instanceof Array){
12584 Roo.each(this.selections, function(s) {
12585 this.unselect(s, nodeInfo);
12589 var node = this.getNode(nodeInfo);
12590 if(!node || !this.isSelected(node)){
12591 Roo.log("not selected");
12592 return; // not selected.
12596 Roo.each(this.selections, function(s) {
12598 Roo.fly(node).removeClass(this.selectedClass);
12605 this.selections= ns;
12606 this.fireEvent("selectionchange", this, this.selections);
12610 * Gets a template node.
12611 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12612 * @return {HTMLElement} The node or null if it wasn't found
12614 getNode : function(nodeInfo){
12615 if(typeof nodeInfo == "string"){
12616 return document.getElementById(nodeInfo);
12617 }else if(typeof nodeInfo == "number"){
12618 return this.nodes[nodeInfo];
12624 * Gets a range template nodes.
12625 * @param {Number} startIndex
12626 * @param {Number} endIndex
12627 * @return {Array} An array of nodes
12629 getNodes : function(start, end){
12630 var ns = this.nodes;
12631 start = start || 0;
12632 end = typeof end == "undefined" ? ns.length - 1 : end;
12635 for(var i = start; i <= end; i++){
12639 for(var i = start; i >= end; i--){
12647 * Finds the index of the passed node
12648 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12649 * @return {Number} The index of the node or -1
12651 indexOf : function(node){
12652 node = this.getNode(node);
12653 if(typeof node.nodeIndex == "number"){
12654 return node.nodeIndex;
12656 var ns = this.nodes;
12657 for(var i = 0, len = ns.length; i < len; i++){
12668 * based on jquery fullcalendar
12672 Roo.bootstrap = Roo.bootstrap || {};
12674 * @class Roo.bootstrap.Calendar
12675 * @extends Roo.bootstrap.Component
12676 * Bootstrap Calendar class
12677 * @cfg {Boolean} loadMask (true|false) default false
12678 * @cfg {Object} header generate the user specific header of the calendar, default false
12681 * Create a new Container
12682 * @param {Object} config The config object
12687 Roo.bootstrap.Calendar = function(config){
12688 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12692 * Fires when a date is selected
12693 * @param {DatePicker} this
12694 * @param {Date} date The selected date
12698 * @event monthchange
12699 * Fires when the displayed month changes
12700 * @param {DatePicker} this
12701 * @param {Date} date The selected month
12703 'monthchange': true,
12705 * @event evententer
12706 * Fires when mouse over an event
12707 * @param {Calendar} this
12708 * @param {event} Event
12710 'evententer': true,
12712 * @event eventleave
12713 * Fires when the mouse leaves an
12714 * @param {Calendar} this
12717 'eventleave': true,
12719 * @event eventclick
12720 * Fires when the mouse click an
12721 * @param {Calendar} this
12730 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12733 * @cfg {Number} startDay
12734 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12742 getAutoCreate : function(){
12745 var fc_button = function(name, corner, style, content ) {
12746 return Roo.apply({},{
12748 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12750 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12753 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12764 style : 'width:100%',
12771 cls : 'fc-header-left',
12773 fc_button('prev', 'left', 'arrow', '‹' ),
12774 fc_button('next', 'right', 'arrow', '›' ),
12775 { tag: 'span', cls: 'fc-header-space' },
12776 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12784 cls : 'fc-header-center',
12788 cls: 'fc-header-title',
12791 html : 'month / year'
12799 cls : 'fc-header-right',
12801 /* fc_button('month', 'left', '', 'month' ),
12802 fc_button('week', '', '', 'week' ),
12803 fc_button('day', 'right', '', 'day' )
12815 header = this.header;
12818 var cal_heads = function() {
12820 // fixme - handle this.
12822 for (var i =0; i < Date.dayNames.length; i++) {
12823 var d = Date.dayNames[i];
12826 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12827 html : d.substring(0,3)
12831 ret[0].cls += ' fc-first';
12832 ret[6].cls += ' fc-last';
12835 var cal_cell = function(n) {
12838 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12843 cls: 'fc-day-number',
12847 cls: 'fc-day-content',
12851 style: 'position: relative;' // height: 17px;
12863 var cal_rows = function() {
12866 for (var r = 0; r < 6; r++) {
12873 for (var i =0; i < Date.dayNames.length; i++) {
12874 var d = Date.dayNames[i];
12875 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12878 row.cn[0].cls+=' fc-first';
12879 row.cn[0].cn[0].style = 'min-height:90px';
12880 row.cn[6].cls+=' fc-last';
12884 ret[0].cls += ' fc-first';
12885 ret[4].cls += ' fc-prev-last';
12886 ret[5].cls += ' fc-last';
12893 cls: 'fc-border-separate',
12894 style : 'width:100%',
12902 cls : 'fc-first fc-last',
12920 cls : 'fc-content',
12921 style : "position: relative;",
12924 cls : 'fc-view fc-view-month fc-grid',
12925 style : 'position: relative',
12926 unselectable : 'on',
12929 cls : 'fc-event-container',
12930 style : 'position:absolute;z-index:8;top:0;left:0;'
12948 initEvents : function()
12951 throw "can not find store for calendar";
12957 style: "text-align:center",
12961 style: "background-color:white;width:50%;margin:250 auto",
12965 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12976 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12978 var size = this.el.select('.fc-content', true).first().getSize();
12979 this.maskEl.setSize(size.width, size.height);
12980 this.maskEl.enableDisplayMode("block");
12981 if(!this.loadMask){
12982 this.maskEl.hide();
12985 this.store = Roo.factory(this.store, Roo.data);
12986 this.store.on('load', this.onLoad, this);
12987 this.store.on('beforeload', this.onBeforeLoad, this);
12991 this.cells = this.el.select('.fc-day',true);
12992 //Roo.log(this.cells);
12993 this.textNodes = this.el.query('.fc-day-number');
12994 this.cells.addClassOnOver('fc-state-hover');
12996 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12997 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12998 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12999 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13001 this.on('monthchange', this.onMonthChange, this);
13003 this.update(new Date().clearTime());
13006 resize : function() {
13007 var sz = this.el.getSize();
13009 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13010 this.el.select('.fc-day-content div',true).setHeight(34);
13015 showPrevMonth : function(e){
13016 this.update(this.activeDate.add("mo", -1));
13018 showToday : function(e){
13019 this.update(new Date().clearTime());
13022 showNextMonth : function(e){
13023 this.update(this.activeDate.add("mo", 1));
13027 showPrevYear : function(){
13028 this.update(this.activeDate.add("y", -1));
13032 showNextYear : function(){
13033 this.update(this.activeDate.add("y", 1));
13038 update : function(date)
13040 var vd = this.activeDate;
13041 this.activeDate = date;
13042 // if(vd && this.el){
13043 // var t = date.getTime();
13044 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13045 // Roo.log('using add remove');
13047 // this.fireEvent('monthchange', this, date);
13049 // this.cells.removeClass("fc-state-highlight");
13050 // this.cells.each(function(c){
13051 // if(c.dateValue == t){
13052 // c.addClass("fc-state-highlight");
13053 // setTimeout(function(){
13054 // try{c.dom.firstChild.focus();}catch(e){}
13064 var days = date.getDaysInMonth();
13066 var firstOfMonth = date.getFirstDateOfMonth();
13067 var startingPos = firstOfMonth.getDay()-this.startDay;
13069 if(startingPos < this.startDay){
13073 var pm = date.add(Date.MONTH, -1);
13074 var prevStart = pm.getDaysInMonth()-startingPos;
13076 this.cells = this.el.select('.fc-day',true);
13077 this.textNodes = this.el.query('.fc-day-number');
13078 this.cells.addClassOnOver('fc-state-hover');
13080 var cells = this.cells.elements;
13081 var textEls = this.textNodes;
13083 Roo.each(cells, function(cell){
13084 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13087 days += startingPos;
13089 // convert everything to numbers so it's fast
13090 var day = 86400000;
13091 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13094 //Roo.log(prevStart);
13096 var today = new Date().clearTime().getTime();
13097 var sel = date.clearTime().getTime();
13098 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13099 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13100 var ddMatch = this.disabledDatesRE;
13101 var ddText = this.disabledDatesText;
13102 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13103 var ddaysText = this.disabledDaysText;
13104 var format = this.format;
13106 var setCellClass = function(cal, cell){
13110 //Roo.log('set Cell Class');
13112 var t = d.getTime();
13116 cell.dateValue = t;
13118 cell.className += " fc-today";
13119 cell.className += " fc-state-highlight";
13120 cell.title = cal.todayText;
13123 // disable highlight in other month..
13124 //cell.className += " fc-state-highlight";
13129 cell.className = " fc-state-disabled";
13130 cell.title = cal.minText;
13134 cell.className = " fc-state-disabled";
13135 cell.title = cal.maxText;
13139 if(ddays.indexOf(d.getDay()) != -1){
13140 cell.title = ddaysText;
13141 cell.className = " fc-state-disabled";
13144 if(ddMatch && format){
13145 var fvalue = d.dateFormat(format);
13146 if(ddMatch.test(fvalue)){
13147 cell.title = ddText.replace("%0", fvalue);
13148 cell.className = " fc-state-disabled";
13152 if (!cell.initialClassName) {
13153 cell.initialClassName = cell.dom.className;
13156 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13161 for(; i < startingPos; i++) {
13162 textEls[i].innerHTML = (++prevStart);
13163 d.setDate(d.getDate()+1);
13165 cells[i].className = "fc-past fc-other-month";
13166 setCellClass(this, cells[i]);
13171 for(; i < days; i++){
13172 intDay = i - startingPos + 1;
13173 textEls[i].innerHTML = (intDay);
13174 d.setDate(d.getDate()+1);
13176 cells[i].className = ''; // "x-date-active";
13177 setCellClass(this, cells[i]);
13181 for(; i < 42; i++) {
13182 textEls[i].innerHTML = (++extraDays);
13183 d.setDate(d.getDate()+1);
13185 cells[i].className = "fc-future fc-other-month";
13186 setCellClass(this, cells[i]);
13189 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13191 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13193 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13194 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13196 if(totalRows != 6){
13197 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13198 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13201 this.fireEvent('monthchange', this, date);
13205 if(!this.internalRender){
13206 var main = this.el.dom.firstChild;
13207 var w = main.offsetWidth;
13208 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13209 Roo.fly(main).setWidth(w);
13210 this.internalRender = true;
13211 // opera does not respect the auto grow header center column
13212 // then, after it gets a width opera refuses to recalculate
13213 // without a second pass
13214 if(Roo.isOpera && !this.secondPass){
13215 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13216 this.secondPass = true;
13217 this.update.defer(10, this, [date]);
13224 findCell : function(dt) {
13225 dt = dt.clearTime().getTime();
13227 this.cells.each(function(c){
13228 //Roo.log("check " +c.dateValue + '?=' + dt);
13229 if(c.dateValue == dt){
13239 findCells : function(ev) {
13240 var s = ev.start.clone().clearTime().getTime();
13242 var e= ev.end.clone().clearTime().getTime();
13245 this.cells.each(function(c){
13246 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13248 if(c.dateValue > e){
13251 if(c.dateValue < s){
13260 // findBestRow: function(cells)
13264 // for (var i =0 ; i < cells.length;i++) {
13265 // ret = Math.max(cells[i].rows || 0,ret);
13272 addItem : function(ev)
13274 // look for vertical location slot in
13275 var cells = this.findCells(ev);
13277 // ev.row = this.findBestRow(cells);
13279 // work out the location.
13283 for(var i =0; i < cells.length; i++) {
13285 cells[i].row = cells[0].row;
13288 cells[i].row = cells[i].row + 1;
13298 if (crow.start.getY() == cells[i].getY()) {
13300 crow.end = cells[i];
13317 cells[0].events.push(ev);
13319 this.calevents.push(ev);
13322 clearEvents: function() {
13324 if(!this.calevents){
13328 Roo.each(this.cells.elements, function(c){
13334 Roo.each(this.calevents, function(e) {
13335 Roo.each(e.els, function(el) {
13336 el.un('mouseenter' ,this.onEventEnter, this);
13337 el.un('mouseleave' ,this.onEventLeave, this);
13342 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13348 renderEvents: function()
13352 this.cells.each(function(c) {
13361 if(c.row != c.events.length){
13362 r = 4 - (4 - (c.row - c.events.length));
13365 c.events = ev.slice(0, r);
13366 c.more = ev.slice(r);
13368 if(c.more.length && c.more.length == 1){
13369 c.events.push(c.more.pop());
13372 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13376 this.cells.each(function(c) {
13378 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13381 for (var e = 0; e < c.events.length; e++){
13382 var ev = c.events[e];
13383 var rows = ev.rows;
13385 for(var i = 0; i < rows.length; i++) {
13387 // how many rows should it span..
13390 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13391 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13393 unselectable : "on",
13396 cls: 'fc-event-inner',
13400 // cls: 'fc-event-time',
13401 // html : cells.length > 1 ? '' : ev.time
13405 cls: 'fc-event-title',
13406 html : String.format('{0}', ev.title)
13413 cls: 'ui-resizable-handle ui-resizable-e',
13414 html : '  '
13421 cfg.cls += ' fc-event-start';
13423 if ((i+1) == rows.length) {
13424 cfg.cls += ' fc-event-end';
13427 var ctr = _this.el.select('.fc-event-container',true).first();
13428 var cg = ctr.createChild(cfg);
13430 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13431 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13433 var r = (c.more.length) ? 1 : 0;
13434 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13435 cg.setWidth(ebox.right - sbox.x -2);
13437 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13438 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13439 cg.on('click', _this.onEventClick, _this, ev);
13450 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13451 style : 'position: absolute',
13452 unselectable : "on",
13455 cls: 'fc-event-inner',
13459 cls: 'fc-event-title',
13467 cls: 'ui-resizable-handle ui-resizable-e',
13468 html : '  '
13474 var ctr = _this.el.select('.fc-event-container',true).first();
13475 var cg = ctr.createChild(cfg);
13477 var sbox = c.select('.fc-day-content',true).first().getBox();
13478 var ebox = c.select('.fc-day-content',true).first().getBox();
13480 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13481 cg.setWidth(ebox.right - sbox.x -2);
13483 cg.on('click', _this.onMoreEventClick, _this, c.more);
13493 onEventEnter: function (e, el,event,d) {
13494 this.fireEvent('evententer', this, el, event);
13497 onEventLeave: function (e, el,event,d) {
13498 this.fireEvent('eventleave', this, el, event);
13501 onEventClick: function (e, el,event,d) {
13502 this.fireEvent('eventclick', this, el, event);
13505 onMonthChange: function () {
13509 onMoreEventClick: function(e, el, more)
13513 this.calpopover.placement = 'right';
13514 this.calpopover.setTitle('More');
13516 this.calpopover.setContent('');
13518 var ctr = this.calpopover.el.select('.popover-content', true).first();
13520 Roo.each(more, function(m){
13522 cls : 'fc-event-hori fc-event-draggable',
13525 var cg = ctr.createChild(cfg);
13527 cg.on('click', _this.onEventClick, _this, m);
13530 this.calpopover.show(el);
13535 onLoad: function ()
13537 this.calevents = [];
13540 if(this.store.getCount() > 0){
13541 this.store.data.each(function(d){
13544 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13545 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13546 time : d.data.start_time,
13547 title : d.data.title,
13548 description : d.data.description,
13549 venue : d.data.venue
13554 this.renderEvents();
13556 if(this.calevents.length && this.loadMask){
13557 this.maskEl.hide();
13561 onBeforeLoad: function()
13563 this.clearEvents();
13565 this.maskEl.show();
13579 * @class Roo.bootstrap.Popover
13580 * @extends Roo.bootstrap.Component
13581 * Bootstrap Popover class
13582 * @cfg {String} html contents of the popover (or false to use children..)
13583 * @cfg {String} title of popover (or false to hide)
13584 * @cfg {String} placement how it is placed
13585 * @cfg {String} trigger click || hover (or false to trigger manually)
13586 * @cfg {String} over what (parent or false to trigger manually.)
13589 * Create a new Popover
13590 * @param {Object} config The config object
13593 Roo.bootstrap.Popover = function(config){
13594 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13597 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13599 title: 'Fill in a title',
13602 placement : 'right',
13603 trigger : 'hover', // hover
13607 can_build_overlaid : false,
13609 getChildContainer : function()
13611 return this.el.select('.popover-content',true).first();
13614 getAutoCreate : function(){
13615 Roo.log('make popover?');
13617 cls : 'popover roo-dynamic',
13618 style: 'display:block',
13624 cls : 'popover-inner',
13628 cls: 'popover-title',
13632 cls : 'popover-content',
13643 setTitle: function(str)
13645 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13647 setContent: function(str)
13649 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13651 // as it get's added to the bottom of the page.
13652 onRender : function(ct, position)
13654 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13656 var cfg = Roo.apply({}, this.getAutoCreate());
13660 cfg.cls += ' ' + this.cls;
13663 cfg.style = this.style;
13665 Roo.log("adding to ")
13666 this.el = Roo.get(document.body).createChild(cfg, position);
13672 initEvents : function()
13674 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13675 this.el.enableDisplayMode('block');
13677 if (this.over === false) {
13680 if (this.triggers === false) {
13683 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13684 var triggers = this.trigger ? this.trigger.split(' ') : [];
13685 Roo.each(triggers, function(trigger) {
13687 if (trigger == 'click') {
13688 on_el.on('click', this.toggle, this);
13689 } else if (trigger != 'manual') {
13690 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13691 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13693 on_el.on(eventIn ,this.enter, this);
13694 on_el.on(eventOut, this.leave, this);
13705 toggle : function () {
13706 this.hoverState == 'in' ? this.leave() : this.enter();
13709 enter : function () {
13712 clearTimeout(this.timeout);
13714 this.hoverState = 'in'
13716 if (!this.delay || !this.delay.show) {
13721 this.timeout = setTimeout(function () {
13722 if (_t.hoverState == 'in') {
13725 }, this.delay.show)
13727 leave : function() {
13728 clearTimeout(this.timeout);
13730 this.hoverState = 'out'
13732 if (!this.delay || !this.delay.hide) {
13737 this.timeout = setTimeout(function () {
13738 if (_t.hoverState == 'out') {
13741 }, this.delay.hide)
13744 show : function (on_el)
13747 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13750 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13751 if (this.html !== false) {
13752 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13754 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13755 if (!this.title.length) {
13756 this.el.select('.popover-title',true).hide();
13759 var placement = typeof this.placement == 'function' ?
13760 this.placement.call(this, this.el, on_el) :
13763 var autoToken = /\s?auto?\s?/i;
13764 var autoPlace = autoToken.test(placement);
13766 placement = placement.replace(autoToken, '') || 'top';
13770 //this.el.setXY([0,0]);
13772 this.el.dom.style.display='block';
13773 this.el.addClass(placement);
13775 //this.el.appendTo(on_el);
13777 var p = this.getPosition();
13778 var box = this.el.getBox();
13783 var align = Roo.bootstrap.Popover.alignment[placement]
13784 this.el.alignTo(on_el, align[0],align[1]);
13785 //var arrow = this.el.select('.arrow',true).first();
13786 //arrow.set(align[2],
13788 this.el.addClass('in');
13789 this.hoverState = null;
13791 if (this.el.hasClass('fade')) {
13798 this.el.setXY([0,0]);
13799 this.el.removeClass('in');
13806 Roo.bootstrap.Popover.alignment = {
13807 'left' : ['r-l', [-10,0], 'right'],
13808 'right' : ['l-r', [10,0], 'left'],
13809 'bottom' : ['t-b', [0,10], 'top'],
13810 'top' : [ 'b-t', [0,-10], 'bottom']
13821 * @class Roo.bootstrap.Progress
13822 * @extends Roo.bootstrap.Component
13823 * Bootstrap Progress class
13824 * @cfg {Boolean} striped striped of the progress bar
13825 * @cfg {Boolean} active animated of the progress bar
13829 * Create a new Progress
13830 * @param {Object} config The config object
13833 Roo.bootstrap.Progress = function(config){
13834 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13837 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13842 getAutoCreate : function(){
13850 cfg.cls += ' progress-striped';
13854 cfg.cls += ' active';
13873 * @class Roo.bootstrap.ProgressBar
13874 * @extends Roo.bootstrap.Component
13875 * Bootstrap ProgressBar class
13876 * @cfg {Number} aria_valuenow aria-value now
13877 * @cfg {Number} aria_valuemin aria-value min
13878 * @cfg {Number} aria_valuemax aria-value max
13879 * @cfg {String} label label for the progress bar
13880 * @cfg {String} panel (success | info | warning | danger )
13881 * @cfg {String} role role of the progress bar
13882 * @cfg {String} sr_only text
13886 * Create a new ProgressBar
13887 * @param {Object} config The config object
13890 Roo.bootstrap.ProgressBar = function(config){
13891 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13894 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13898 aria_valuemax : 100,
13904 getAutoCreate : function()
13909 cls: 'progress-bar',
13910 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13922 cfg.role = this.role;
13925 if(this.aria_valuenow){
13926 cfg['aria-valuenow'] = this.aria_valuenow;
13929 if(this.aria_valuemin){
13930 cfg['aria-valuemin'] = this.aria_valuemin;
13933 if(this.aria_valuemax){
13934 cfg['aria-valuemax'] = this.aria_valuemax;
13937 if(this.label && !this.sr_only){
13938 cfg.html = this.label;
13942 cfg.cls += ' progress-bar-' + this.panel;
13948 update : function(aria_valuenow)
13950 this.aria_valuenow = aria_valuenow;
13952 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13967 * @class Roo.bootstrap.TabGroup
13968 * @extends Roo.bootstrap.Column
13969 * Bootstrap Column class
13970 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13971 * @cfg {Boolean} carousel true to make the group behave like a carousel
13974 * Create a new TabGroup
13975 * @param {Object} config The config object
13978 Roo.bootstrap.TabGroup = function(config){
13979 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13981 this.navId = Roo.id();
13984 Roo.bootstrap.TabGroup.register(this);
13988 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13991 transition : false,
13993 getAutoCreate : function()
13995 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13997 cfg.cls += ' tab-content';
13999 if (this.carousel) {
14000 cfg.cls += ' carousel slide';
14002 cls : 'carousel-inner'
14009 getChildContainer : function()
14011 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14015 * register a Navigation item
14016 * @param {Roo.bootstrap.NavItem} the navitem to add
14018 register : function(item)
14020 this.tabs.push( item);
14021 item.navId = this.navId; // not really needed..
14025 getActivePanel : function()
14028 Roo.each(this.tabs, function(t) {
14038 getPanelByName : function(n)
14041 Roo.each(this.tabs, function(t) {
14042 if (t.tabId == n) {
14050 indexOfPanel : function(p)
14053 Roo.each(this.tabs, function(t,i) {
14054 if (t.tabId == p.tabId) {
14063 * show a specific panel
14064 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14065 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14067 showPanel : function (pan)
14070 if (typeof(pan) == 'number') {
14071 pan = this.tabs[pan];
14073 if (typeof(pan) == 'string') {
14074 pan = this.getPanelByName(pan);
14076 if (pan.tabId == this.getActivePanel().tabId) {
14079 var cur = this.getActivePanel();
14081 if (false === cur.fireEvent('beforedeactivate')) {
14085 if (this.carousel) {
14086 this.transition = true;
14087 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14088 var lr = dir == 'next' ? 'left' : 'right';
14089 pan.el.addClass(dir); // or prev
14090 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14091 cur.el.addClass(lr); // or right
14092 pan.el.addClass(lr);
14095 cur.el.on('transitionend', function() {
14096 Roo.log("trans end?");
14098 pan.el.removeClass([lr,dir]);
14099 pan.setActive(true);
14101 cur.el.removeClass([lr]);
14102 cur.setActive(false);
14104 _this.transition = false;
14106 }, this, { single: true } );
14110 cur.setActive(false);
14111 pan.setActive(true);
14115 showPanelNext : function()
14117 var i = this.indexOfPanel(this.getActivePanel());
14118 if (i > this.tabs.length) {
14121 this.showPanel(this.tabs[i+1]);
14123 showPanelPrev : function()
14125 var i = this.indexOfPanel(this.getActivePanel());
14129 this.showPanel(this.tabs[i-1]);
14140 Roo.apply(Roo.bootstrap.TabGroup, {
14144 * register a Navigation Group
14145 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14147 register : function(navgrp)
14149 this.groups[navgrp.navId] = navgrp;
14153 * fetch a Navigation Group based on the navigation ID
14154 * if one does not exist , it will get created.
14155 * @param {string} the navgroup to add
14156 * @returns {Roo.bootstrap.NavGroup} the navgroup
14158 get: function(navId) {
14159 if (typeof(this.groups[navId]) == 'undefined') {
14160 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14162 return this.groups[navId] ;
14177 * @class Roo.bootstrap.TabPanel
14178 * @extends Roo.bootstrap.Component
14179 * Bootstrap TabPanel class
14180 * @cfg {Boolean} active panel active
14181 * @cfg {String} html panel content
14182 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14183 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14187 * Create a new TabPanel
14188 * @param {Object} config The config object
14191 Roo.bootstrap.TabPanel = function(config){
14192 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14196 * Fires when the active status changes
14197 * @param {Roo.bootstrap.TabPanel} this
14198 * @param {Boolean} state the new state
14203 * @event beforedeactivate
14204 * Fires before a tab is de-activated - can be used to do validation on a form.
14205 * @param {Roo.bootstrap.TabPanel} this
14206 * @return {Boolean} false if there is an error
14209 'beforedeactivate': true
14212 this.tabId = this.tabId || Roo.id();
14216 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14223 getAutoCreate : function(){
14226 // item is needed for carousel - not sure if it has any effect otherwise
14227 cls: 'tab-pane item',
14228 html: this.html || ''
14232 cfg.cls += ' active';
14236 cfg.tabId = this.tabId;
14243 initEvents: function()
14245 Roo.log('-------- init events on tab panel ---------');
14247 var p = this.parent();
14248 this.navId = this.navId || p.navId;
14250 if (typeof(this.navId) != 'undefined') {
14251 // not really needed.. but just in case.. parent should be a NavGroup.
14252 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14253 Roo.log(['register', tg, this]);
14259 onRender : function(ct, position)
14261 // Roo.log("Call onRender: " + this.xtype);
14263 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14271 setActive: function(state)
14273 Roo.log("panel - set active " + this.tabId + "=" + state);
14275 this.active = state;
14277 this.el.removeClass('active');
14279 } else if (!this.el.hasClass('active')) {
14280 this.el.addClass('active');
14282 this.fireEvent('changed', this, state);
14299 * @class Roo.bootstrap.DateField
14300 * @extends Roo.bootstrap.Input
14301 * Bootstrap DateField class
14302 * @cfg {Number} weekStart default 0
14303 * @cfg {Number} weekStart default 0
14304 * @cfg {Number} viewMode default empty, (months|years)
14305 * @cfg {Number} minViewMode default empty, (months|years)
14306 * @cfg {Number} startDate default -Infinity
14307 * @cfg {Number} endDate default Infinity
14308 * @cfg {Boolean} todayHighlight default false
14309 * @cfg {Boolean} todayBtn default false
14310 * @cfg {Boolean} calendarWeeks default false
14311 * @cfg {Object} daysOfWeekDisabled default empty
14313 * @cfg {Boolean} keyboardNavigation default true
14314 * @cfg {String} language default en
14317 * Create a new DateField
14318 * @param {Object} config The config object
14321 Roo.bootstrap.DateField = function(config){
14322 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14326 * Fires when this field show.
14327 * @param {Roo.bootstrap.DateField} this
14328 * @param {Mixed} date The date value
14333 * Fires when this field hide.
14334 * @param {Roo.bootstrap.DateField} this
14335 * @param {Mixed} date The date value
14340 * Fires when select a date.
14341 * @param {Roo.bootstrap.DateField} this
14342 * @param {Mixed} date The date value
14348 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14351 * @cfg {String} format
14352 * The default date format string which can be overriden for localization support. The format must be
14353 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14357 * @cfg {String} altFormats
14358 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14359 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14361 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14369 todayHighlight : false,
14375 keyboardNavigation: true,
14377 calendarWeeks: false,
14379 startDate: -Infinity,
14383 daysOfWeekDisabled: [],
14387 UTCDate: function()
14389 return new Date(Date.UTC.apply(Date, arguments));
14392 UTCToday: function()
14394 var today = new Date();
14395 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14398 getDate: function() {
14399 var d = this.getUTCDate();
14400 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14403 getUTCDate: function() {
14407 setDate: function(d) {
14408 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14411 setUTCDate: function(d) {
14413 this.setValue(this.formatDate(this.date));
14416 onRender: function(ct, position)
14419 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14421 this.language = this.language || 'en';
14422 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14423 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14425 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14426 this.format = this.format || 'm/d/y';
14427 this.isInline = false;
14428 this.isInput = true;
14429 this.component = this.el.select('.add-on', true).first() || false;
14430 this.component = (this.component && this.component.length === 0) ? false : this.component;
14431 this.hasInput = this.component && this.inputEL().length;
14433 if (typeof(this.minViewMode === 'string')) {
14434 switch (this.minViewMode) {
14436 this.minViewMode = 1;
14439 this.minViewMode = 2;
14442 this.minViewMode = 0;
14447 if (typeof(this.viewMode === 'string')) {
14448 switch (this.viewMode) {
14461 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14463 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14465 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14467 this.picker().on('mousedown', this.onMousedown, this);
14468 this.picker().on('click', this.onClick, this);
14470 this.picker().addClass('datepicker-dropdown');
14472 this.startViewMode = this.viewMode;
14475 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14476 if(!this.calendarWeeks){
14481 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14482 v.attr('colspan', function(i, val){
14483 return parseInt(val) + 1;
14488 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14490 this.setStartDate(this.startDate);
14491 this.setEndDate(this.endDate);
14493 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14500 if(this.isInline) {
14505 picker : function()
14507 return this.pickerEl;
14508 // return this.el.select('.datepicker', true).first();
14511 fillDow: function()
14513 var dowCnt = this.weekStart;
14522 if(this.calendarWeeks){
14530 while (dowCnt < this.weekStart + 7) {
14534 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14538 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14541 fillMonths: function()
14544 var months = this.picker().select('>.datepicker-months td', true).first();
14546 months.dom.innerHTML = '';
14552 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14555 months.createChild(month);
14562 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;
14564 if (this.date < this.startDate) {
14565 this.viewDate = new Date(this.startDate);
14566 } else if (this.date > this.endDate) {
14567 this.viewDate = new Date(this.endDate);
14569 this.viewDate = new Date(this.date);
14577 var d = new Date(this.viewDate),
14578 year = d.getUTCFullYear(),
14579 month = d.getUTCMonth(),
14580 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14581 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14582 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14583 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14584 currentDate = this.date && this.date.valueOf(),
14585 today = this.UTCToday();
14587 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14589 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14591 // this.picker.select('>tfoot th.today').
14592 // .text(dates[this.language].today)
14593 // .toggle(this.todayBtn !== false);
14595 this.updateNavArrows();
14598 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14600 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14602 prevMonth.setUTCDate(day);
14604 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14606 var nextMonth = new Date(prevMonth);
14608 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14610 nextMonth = nextMonth.valueOf();
14612 var fillMonths = false;
14614 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14616 while(prevMonth.valueOf() < nextMonth) {
14619 if (prevMonth.getUTCDay() === this.weekStart) {
14621 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14629 if(this.calendarWeeks){
14630 // ISO 8601: First week contains first thursday.
14631 // ISO also states week starts on Monday, but we can be more abstract here.
14633 // Start of current week: based on weekstart/current date
14634 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14635 // Thursday of this week
14636 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14637 // First Thursday of year, year from thursday
14638 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14639 // Calendar week: ms between thursdays, div ms per day, div 7 days
14640 calWeek = (th - yth) / 864e5 / 7 + 1;
14642 fillMonths.cn.push({
14650 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14652 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14655 if (this.todayHighlight &&
14656 prevMonth.getUTCFullYear() == today.getFullYear() &&
14657 prevMonth.getUTCMonth() == today.getMonth() &&
14658 prevMonth.getUTCDate() == today.getDate()) {
14659 clsName += ' today';
14662 if (currentDate && prevMonth.valueOf() === currentDate) {
14663 clsName += ' active';
14666 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14667 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14668 clsName += ' disabled';
14671 fillMonths.cn.push({
14673 cls: 'day ' + clsName,
14674 html: prevMonth.getDate()
14677 prevMonth.setDate(prevMonth.getDate()+1);
14680 var currentYear = this.date && this.date.getUTCFullYear();
14681 var currentMonth = this.date && this.date.getUTCMonth();
14683 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14685 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14686 v.removeClass('active');
14688 if(currentYear === year && k === currentMonth){
14689 v.addClass('active');
14692 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14693 v.addClass('disabled');
14699 year = parseInt(year/10, 10) * 10;
14701 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14703 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14706 for (var i = -1; i < 11; i++) {
14707 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14709 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14717 showMode: function(dir)
14720 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14722 Roo.each(this.picker().select('>div',true).elements, function(v){
14723 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14726 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14731 if(this.isInline) return;
14733 this.picker().removeClass(['bottom', 'top']);
14735 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14737 * place to the top of element!
14741 this.picker().addClass('top');
14742 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14747 this.picker().addClass('bottom');
14749 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14752 parseDate : function(value)
14754 if(!value || value instanceof Date){
14757 var v = Date.parseDate(value, this.format);
14758 if (!v && this.useIso) {
14759 v = Date.parseDate(value, 'Y-m-d');
14761 if(!v && this.altFormats){
14762 if(!this.altFormatsArray){
14763 this.altFormatsArray = this.altFormats.split("|");
14765 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14766 v = Date.parseDate(value, this.altFormatsArray[i]);
14772 formatDate : function(date, fmt)
14774 return (!date || !(date instanceof Date)) ?
14775 date : date.dateFormat(fmt || this.format);
14778 onFocus : function()
14780 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14784 onBlur : function()
14786 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14788 var d = this.inputEl().getValue();
14797 this.picker().show();
14801 this.fireEvent('show', this, this.date);
14806 if(this.isInline) return;
14807 this.picker().hide();
14808 this.viewMode = this.startViewMode;
14811 this.fireEvent('hide', this, this.date);
14815 onMousedown: function(e)
14817 e.stopPropagation();
14818 e.preventDefault();
14823 Roo.bootstrap.DateField.superclass.keyup.call(this);
14827 setValue: function(v)
14829 var d = new Date(v).clearTime();
14831 if(isNaN(d.getTime())){
14832 this.date = this.viewDate = '';
14833 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14837 v = this.formatDate(d);
14839 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14841 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14845 this.fireEvent('select', this, this.date);
14849 getValue: function()
14851 return this.formatDate(this.date);
14854 fireKey: function(e)
14856 if (!this.picker().isVisible()){
14857 if (e.keyCode == 27) // allow escape to hide and re-show picker
14862 var dateChanged = false,
14864 newDate, newViewDate;
14869 e.preventDefault();
14873 if (!this.keyboardNavigation) break;
14874 dir = e.keyCode == 37 ? -1 : 1;
14877 newDate = this.moveYear(this.date, dir);
14878 newViewDate = this.moveYear(this.viewDate, dir);
14879 } else if (e.shiftKey){
14880 newDate = this.moveMonth(this.date, dir);
14881 newViewDate = this.moveMonth(this.viewDate, dir);
14883 newDate = new Date(this.date);
14884 newDate.setUTCDate(this.date.getUTCDate() + dir);
14885 newViewDate = new Date(this.viewDate);
14886 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14888 if (this.dateWithinRange(newDate)){
14889 this.date = newDate;
14890 this.viewDate = newViewDate;
14891 this.setValue(this.formatDate(this.date));
14893 e.preventDefault();
14894 dateChanged = true;
14899 if (!this.keyboardNavigation) break;
14900 dir = e.keyCode == 38 ? -1 : 1;
14902 newDate = this.moveYear(this.date, dir);
14903 newViewDate = this.moveYear(this.viewDate, dir);
14904 } else if (e.shiftKey){
14905 newDate = this.moveMonth(this.date, dir);
14906 newViewDate = this.moveMonth(this.viewDate, dir);
14908 newDate = new Date(this.date);
14909 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14910 newViewDate = new Date(this.viewDate);
14911 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14913 if (this.dateWithinRange(newDate)){
14914 this.date = newDate;
14915 this.viewDate = newViewDate;
14916 this.setValue(this.formatDate(this.date));
14918 e.preventDefault();
14919 dateChanged = true;
14923 this.setValue(this.formatDate(this.date));
14925 e.preventDefault();
14928 this.setValue(this.formatDate(this.date));
14942 onClick: function(e)
14944 e.stopPropagation();
14945 e.preventDefault();
14947 var target = e.getTarget();
14949 if(target.nodeName.toLowerCase() === 'i'){
14950 target = Roo.get(target).dom.parentNode;
14953 var nodeName = target.nodeName;
14954 var className = target.className;
14955 var html = target.innerHTML;
14957 switch(nodeName.toLowerCase()) {
14959 switch(className) {
14965 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14966 switch(this.viewMode){
14968 this.viewDate = this.moveMonth(this.viewDate, dir);
14972 this.viewDate = this.moveYear(this.viewDate, dir);
14978 var date = new Date();
14979 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14981 this.setValue(this.formatDate(this.date));
14988 if (className.indexOf('disabled') === -1) {
14989 this.viewDate.setUTCDate(1);
14990 if (className.indexOf('month') !== -1) {
14991 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14993 var year = parseInt(html, 10) || 0;
14994 this.viewDate.setUTCFullYear(year);
15003 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
15004 var day = parseInt(html, 10) || 1;
15005 var year = this.viewDate.getUTCFullYear(),
15006 month = this.viewDate.getUTCMonth();
15008 if (className.indexOf('old') !== -1) {
15015 } else if (className.indexOf('new') !== -1) {
15023 this.date = this.UTCDate(year, month, day,0,0,0,0);
15024 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15026 this.setValue(this.formatDate(this.date));
15033 setStartDate: function(startDate)
15035 this.startDate = startDate || -Infinity;
15036 if (this.startDate !== -Infinity) {
15037 this.startDate = this.parseDate(this.startDate);
15040 this.updateNavArrows();
15043 setEndDate: function(endDate)
15045 this.endDate = endDate || Infinity;
15046 if (this.endDate !== Infinity) {
15047 this.endDate = this.parseDate(this.endDate);
15050 this.updateNavArrows();
15053 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15055 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15056 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15057 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15059 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15060 return parseInt(d, 10);
15063 this.updateNavArrows();
15066 updateNavArrows: function()
15068 var d = new Date(this.viewDate),
15069 year = d.getUTCFullYear(),
15070 month = d.getUTCMonth();
15072 Roo.each(this.picker().select('.prev', true).elements, function(v){
15074 switch (this.viewMode) {
15077 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15083 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15090 Roo.each(this.picker().select('.next', true).elements, function(v){
15092 switch (this.viewMode) {
15095 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15101 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15109 moveMonth: function(date, dir)
15111 if (!dir) return date;
15112 var new_date = new Date(date.valueOf()),
15113 day = new_date.getUTCDate(),
15114 month = new_date.getUTCMonth(),
15115 mag = Math.abs(dir),
15117 dir = dir > 0 ? 1 : -1;
15120 // If going back one month, make sure month is not current month
15121 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15123 return new_date.getUTCMonth() == month;
15125 // If going forward one month, make sure month is as expected
15126 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15128 return new_date.getUTCMonth() != new_month;
15130 new_month = month + dir;
15131 new_date.setUTCMonth(new_month);
15132 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15133 if (new_month < 0 || new_month > 11)
15134 new_month = (new_month + 12) % 12;
15136 // For magnitudes >1, move one month at a time...
15137 for (var i=0; i<mag; i++)
15138 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15139 new_date = this.moveMonth(new_date, dir);
15140 // ...then reset the day, keeping it in the new month
15141 new_month = new_date.getUTCMonth();
15142 new_date.setUTCDate(day);
15144 return new_month != new_date.getUTCMonth();
15147 // Common date-resetting loop -- if date is beyond end of month, make it
15150 new_date.setUTCDate(--day);
15151 new_date.setUTCMonth(new_month);
15156 moveYear: function(date, dir)
15158 return this.moveMonth(date, dir*12);
15161 dateWithinRange: function(date)
15163 return date >= this.startDate && date <= this.endDate;
15169 this.picker().remove();
15174 Roo.apply(Roo.bootstrap.DateField, {
15185 html: '<i class="fa fa-arrow-left"/>'
15195 html: '<i class="fa fa-arrow-right"/>'
15237 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15238 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15239 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15240 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15241 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15254 navFnc: 'FullYear',
15259 navFnc: 'FullYear',
15264 Roo.apply(Roo.bootstrap.DateField, {
15268 cls: 'datepicker dropdown-menu',
15272 cls: 'datepicker-days',
15276 cls: 'table-condensed',
15278 Roo.bootstrap.DateField.head,
15282 Roo.bootstrap.DateField.footer
15289 cls: 'datepicker-months',
15293 cls: 'table-condensed',
15295 Roo.bootstrap.DateField.head,
15296 Roo.bootstrap.DateField.content,
15297 Roo.bootstrap.DateField.footer
15304 cls: 'datepicker-years',
15308 cls: 'table-condensed',
15310 Roo.bootstrap.DateField.head,
15311 Roo.bootstrap.DateField.content,
15312 Roo.bootstrap.DateField.footer
15331 * @class Roo.bootstrap.TimeField
15332 * @extends Roo.bootstrap.Input
15333 * Bootstrap DateField class
15337 * Create a new TimeField
15338 * @param {Object} config The config object
15341 Roo.bootstrap.TimeField = function(config){
15342 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15346 * Fires when this field show.
15347 * @param {Roo.bootstrap.DateField} this
15348 * @param {Mixed} date The date value
15353 * Fires when this field hide.
15354 * @param {Roo.bootstrap.DateField} this
15355 * @param {Mixed} date The date value
15360 * Fires when select a date.
15361 * @param {Roo.bootstrap.DateField} this
15362 * @param {Mixed} date The date value
15368 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15371 * @cfg {String} format
15372 * The default time format string which can be overriden for localization support. The format must be
15373 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15377 onRender: function(ct, position)
15380 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15382 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15384 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15386 this.pop = this.picker().select('>.datepicker-time',true).first();
15387 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15389 this.picker().on('mousedown', this.onMousedown, this);
15390 this.picker().on('click', this.onClick, this);
15392 this.picker().addClass('datepicker-dropdown');
15397 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15398 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15399 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15400 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15401 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15402 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15406 fireKey: function(e){
15407 if (!this.picker().isVisible()){
15408 if (e.keyCode == 27) // allow escape to hide and re-show picker
15413 e.preventDefault();
15421 this.onTogglePeriod();
15424 this.onIncrementMinutes();
15427 this.onDecrementMinutes();
15436 onClick: function(e) {
15437 e.stopPropagation();
15438 e.preventDefault();
15441 picker : function()
15443 return this.el.select('.datepicker', true).first();
15446 fillTime: function()
15448 var time = this.pop.select('tbody', true).first();
15450 time.dom.innerHTML = '';
15465 cls: 'hours-up glyphicon glyphicon-chevron-up'
15485 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15506 cls: 'timepicker-hour',
15521 cls: 'timepicker-minute',
15536 cls: 'btn btn-primary period',
15558 cls: 'hours-down glyphicon glyphicon-chevron-down'
15578 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15596 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15603 var hours = this.time.getHours();
15604 var minutes = this.time.getMinutes();
15617 hours = hours - 12;
15621 hours = '0' + hours;
15625 minutes = '0' + minutes;
15628 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15629 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15630 this.pop.select('button', true).first().dom.innerHTML = period;
15636 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15638 var cls = ['bottom'];
15640 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15647 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15652 this.picker().addClass(cls.join('-'));
15656 Roo.each(cls, function(c){
15658 _this.picker().setTop(_this.inputEl().getHeight());
15662 _this.picker().setTop(0 - _this.picker().getHeight());
15667 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15671 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15678 onFocus : function()
15680 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15684 onBlur : function()
15686 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15692 this.picker().show();
15697 this.fireEvent('show', this, this.date);
15702 this.picker().hide();
15705 this.fireEvent('hide', this, this.date);
15708 setTime : function()
15711 this.setValue(this.time.format(this.format));
15713 this.fireEvent('select', this, this.date);
15718 onMousedown: function(e){
15719 e.stopPropagation();
15720 e.preventDefault();
15723 onIncrementHours: function()
15725 Roo.log('onIncrementHours');
15726 this.time = this.time.add(Date.HOUR, 1);
15731 onDecrementHours: function()
15733 Roo.log('onDecrementHours');
15734 this.time = this.time.add(Date.HOUR, -1);
15738 onIncrementMinutes: function()
15740 Roo.log('onIncrementMinutes');
15741 this.time = this.time.add(Date.MINUTE, 1);
15745 onDecrementMinutes: function()
15747 Roo.log('onDecrementMinutes');
15748 this.time = this.time.add(Date.MINUTE, -1);
15752 onTogglePeriod: function()
15754 Roo.log('onTogglePeriod');
15755 this.time = this.time.add(Date.HOUR, 12);
15762 Roo.apply(Roo.bootstrap.TimeField, {
15792 cls: 'btn btn-info ok',
15804 Roo.apply(Roo.bootstrap.TimeField, {
15808 cls: 'datepicker dropdown-menu',
15812 cls: 'datepicker-time',
15816 cls: 'table-condensed',
15818 Roo.bootstrap.TimeField.content,
15819 Roo.bootstrap.TimeField.footer
15838 * @class Roo.bootstrap.CheckBox
15839 * @extends Roo.bootstrap.Input
15840 * Bootstrap CheckBox class
15842 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15843 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15844 * @cfg {String} boxLabel The text that appears beside the checkbox
15845 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15846 * @cfg {Boolean} checked initnal the element
15850 * Create a new CheckBox
15851 * @param {Object} config The config object
15854 Roo.bootstrap.CheckBox = function(config){
15855 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15860 * Fires when the element is checked or unchecked.
15861 * @param {Roo.bootstrap.CheckBox} this This input
15862 * @param {Boolean} checked The new checked value
15868 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15870 inputType: 'checkbox',
15877 getAutoCreate : function()
15879 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15885 cfg.cls = 'form-group checkbox' //input-group
15893 type : this.inputType,
15894 value : (!this.checked) ? this.valueOff : this.inputValue,
15895 cls : 'roo-checkbox', //'form-box',
15896 placeholder : this.placeholder || ''
15900 if (this.weight) { // Validity check?
15901 cfg.cls += " checkbox-" + this.weight;
15904 if (this.disabled) {
15905 input.disabled=true;
15909 input.checked = this.checked;
15913 input.name = this.name;
15917 input.cls += ' input-' + this.size;
15921 ['xs','sm','md','lg'].map(function(size){
15922 if (settings[size]) {
15923 cfg.cls += ' col-' + size + '-' + settings[size];
15929 var inputblock = input;
15934 if (this.before || this.after) {
15937 cls : 'input-group',
15941 inputblock.cn.push({
15943 cls : 'input-group-addon',
15947 inputblock.cn.push(input);
15949 inputblock.cn.push({
15951 cls : 'input-group-addon',
15958 if (align ==='left' && this.fieldLabel.length) {
15959 Roo.log("left and has label");
15965 cls : 'control-label col-md-' + this.labelWidth,
15966 html : this.fieldLabel
15970 cls : "col-md-" + (12 - this.labelWidth),
15977 } else if ( this.fieldLabel.length) {
15982 tag: this.boxLabel ? 'span' : 'label',
15984 cls: 'control-label box-input-label',
15985 //cls : 'input-group-addon',
15986 html : this.fieldLabel
15996 Roo.log(" no label && no align");
15997 cfg.cn = [ inputblock ] ;
16006 html: this.boxLabel
16018 * return the real input element.
16020 inputEl: function ()
16022 return this.el.select('input.roo-checkbox',true).first();
16027 return this.el.select('label.control-label',true).first();
16030 initEvents : function()
16032 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16034 this.inputEl().on('click', this.onClick, this);
16038 onClick : function()
16040 this.setChecked(!this.checked);
16043 setChecked : function(state,suppressEvent)
16045 this.checked = state;
16047 this.inputEl().dom.checked = state;
16049 if(suppressEvent !== true){
16050 this.fireEvent('check', this, state);
16053 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16057 setValue : function(v,suppressEvent)
16059 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16073 * @class Roo.bootstrap.Radio
16074 * @extends Roo.bootstrap.CheckBox
16075 * Bootstrap Radio class
16078 * Create a new Radio
16079 * @param {Object} config The config object
16082 Roo.bootstrap.Radio = function(config){
16083 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16087 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16089 inputType: 'radio',
16093 getAutoCreate : function()
16095 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16101 cfg.cls = 'form-group radio' //input-group
16106 type : this.inputType,
16107 value : (!this.checked) ? this.valueOff : this.inputValue,
16109 placeholder : this.placeholder || ''
16112 if (this.weight) { // Validity check?
16113 cfg.cls += " radio-" + this.weight;
16115 if (this.disabled) {
16116 input.disabled=true;
16120 input.checked = this.checked;
16124 input.name = this.name;
16128 input.cls += ' input-' + this.size;
16132 ['xs','sm','md','lg'].map(function(size){
16133 if (settings[size]) {
16134 cfg.cls += ' col-' + size + '-' + settings[size];
16138 var inputblock = input;
16140 if (this.before || this.after) {
16143 cls : 'input-group',
16147 inputblock.cn.push({
16149 cls : 'input-group-addon',
16153 inputblock.cn.push(input);
16155 inputblock.cn.push({
16157 cls : 'input-group-addon',
16164 if (align ==='left' && this.fieldLabel.length) {
16165 Roo.log("left and has label");
16171 cls : 'control-label col-md-' + this.labelWidth,
16172 html : this.fieldLabel
16176 cls : "col-md-" + (12 - this.labelWidth),
16183 } else if ( this.fieldLabel.length) {
16190 cls: 'control-label box-input-label',
16191 //cls : 'input-group-addon',
16192 html : this.fieldLabel
16202 Roo.log(" no label && no align");
16217 html: this.boxLabel
16224 inputEl: function ()
16226 return this.el.select('input.roo-radio',true).first();
16228 onClick : function()
16230 this.setChecked(true);
16233 setChecked : function(state,suppressEvent)
16236 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16237 v.dom.checked = false;
16241 this.checked = state;
16242 this.inputEl().dom.checked = state;
16244 if(suppressEvent !== true){
16245 this.fireEvent('check', this, state);
16248 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16252 getGroupValue : function()
16255 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16256 if(v.dom.checked == true){
16257 value = v.dom.value;
16265 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16266 * @return {Mixed} value The field value
16268 getValue : function(){
16269 return this.getGroupValue();
16275 //<script type="text/javascript">
16278 * Based Ext JS Library 1.1.1
16279 * Copyright(c) 2006-2007, Ext JS, LLC.
16285 * @class Roo.HtmlEditorCore
16286 * @extends Roo.Component
16287 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16289 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16292 Roo.HtmlEditorCore = function(config){
16295 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16298 * @event initialize
16299 * Fires when the editor is fully initialized (including the iframe)
16300 * @param {Roo.HtmlEditorCore} this
16305 * Fires when the editor is first receives the focus. Any insertion must wait
16306 * until after this event.
16307 * @param {Roo.HtmlEditorCore} this
16311 * @event beforesync
16312 * Fires before the textarea is updated with content from the editor iframe. Return false
16313 * to cancel the sync.
16314 * @param {Roo.HtmlEditorCore} this
16315 * @param {String} html
16319 * @event beforepush
16320 * Fires before the iframe editor is updated with content from the textarea. Return false
16321 * to cancel the push.
16322 * @param {Roo.HtmlEditorCore} this
16323 * @param {String} html
16328 * Fires when the textarea is updated with content from the editor iframe.
16329 * @param {Roo.HtmlEditorCore} this
16330 * @param {String} html
16335 * Fires when the iframe editor is updated with content from the textarea.
16336 * @param {Roo.HtmlEditorCore} this
16337 * @param {String} html
16342 * @event editorevent
16343 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16344 * @param {Roo.HtmlEditorCore} this
16352 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16356 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16362 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16367 * @cfg {Number} height (in pixels)
16371 * @cfg {Number} width (in pixels)
16376 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16379 stylesheets: false,
16384 // private properties
16385 validationEvent : false,
16387 initialized : false,
16389 sourceEditMode : false,
16390 onFocus : Roo.emptyFn,
16392 hideMode:'offsets',
16400 * Protected method that will not generally be called directly. It
16401 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16402 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16404 getDocMarkup : function(){
16407 Roo.log(this.stylesheets);
16409 // inherit styels from page...??
16410 if (this.stylesheets === false) {
16412 Roo.get(document.head).select('style').each(function(node) {
16413 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16416 Roo.get(document.head).select('link').each(function(node) {
16417 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16420 } else if (!this.stylesheets.length) {
16422 st = '<style type="text/css">' +
16423 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16426 Roo.each(this.stylesheets, function(s) {
16427 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16432 st += '<style type="text/css">' +
16433 'IMG { cursor: pointer } ' +
16437 return '<html><head>' + st +
16438 //<style type="text/css">' +
16439 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16441 ' </head><body class="roo-htmleditor-body"></body></html>';
16445 onRender : function(ct, position)
16448 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16449 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16452 this.el.dom.style.border = '0 none';
16453 this.el.dom.setAttribute('tabIndex', -1);
16454 this.el.addClass('x-hidden hide');
16458 if(Roo.isIE){ // fix IE 1px bogus margin
16459 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16463 this.frameId = Roo.id();
16467 var iframe = this.owner.wrap.createChild({
16469 cls: 'form-control', // bootstrap..
16471 name: this.frameId,
16472 frameBorder : 'no',
16473 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16478 this.iframe = iframe.dom;
16480 this.assignDocWin();
16482 this.doc.designMode = 'on';
16485 this.doc.write(this.getDocMarkup());
16489 var task = { // must defer to wait for browser to be ready
16491 //console.log("run task?" + this.doc.readyState);
16492 this.assignDocWin();
16493 if(this.doc.body || this.doc.readyState == 'complete'){
16495 this.doc.designMode="on";
16499 Roo.TaskMgr.stop(task);
16500 this.initEditor.defer(10, this);
16507 Roo.TaskMgr.start(task);
16514 onResize : function(w, h)
16516 Roo.log('resize: ' +w + ',' + h );
16517 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16521 if(typeof w == 'number'){
16523 this.iframe.style.width = w + 'px';
16525 if(typeof h == 'number'){
16527 this.iframe.style.height = h + 'px';
16529 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16536 * Toggles the editor between standard and source edit mode.
16537 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16539 toggleSourceEdit : function(sourceEditMode){
16541 this.sourceEditMode = sourceEditMode === true;
16543 if(this.sourceEditMode){
16545 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16548 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16549 //this.iframe.className = '';
16552 //this.setSize(this.owner.wrap.getSize());
16553 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16560 * Protected method that will not generally be called directly. If you need/want
16561 * custom HTML cleanup, this is the method you should override.
16562 * @param {String} html The HTML to be cleaned
16563 * return {String} The cleaned HTML
16565 cleanHtml : function(html){
16566 html = String(html);
16567 if(html.length > 5){
16568 if(Roo.isSafari){ // strip safari nonsense
16569 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16572 if(html == ' '){
16579 * HTML Editor -> Textarea
16580 * Protected method that will not generally be called directly. Syncs the contents
16581 * of the editor iframe with the textarea.
16583 syncValue : function(){
16584 if(this.initialized){
16585 var bd = (this.doc.body || this.doc.documentElement);
16586 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16587 var html = bd.innerHTML;
16589 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16590 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16592 html = '<div style="'+m[0]+'">' + html + '</div>';
16595 html = this.cleanHtml(html);
16596 // fix up the special chars.. normaly like back quotes in word...
16597 // however we do not want to do this with chinese..
16598 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16599 var cc = b.charCodeAt();
16601 (cc >= 0x4E00 && cc < 0xA000 ) ||
16602 (cc >= 0x3400 && cc < 0x4E00 ) ||
16603 (cc >= 0xf900 && cc < 0xfb00 )
16609 if(this.owner.fireEvent('beforesync', this, html) !== false){
16610 this.el.dom.value = html;
16611 this.owner.fireEvent('sync', this, html);
16617 * Protected method that will not generally be called directly. Pushes the value of the textarea
16618 * into the iframe editor.
16620 pushValue : function(){
16621 if(this.initialized){
16622 var v = this.el.dom.value.trim();
16624 // if(v.length < 1){
16628 if(this.owner.fireEvent('beforepush', this, v) !== false){
16629 var d = (this.doc.body || this.doc.documentElement);
16631 this.cleanUpPaste();
16632 this.el.dom.value = d.innerHTML;
16633 this.owner.fireEvent('push', this, v);
16639 deferFocus : function(){
16640 this.focus.defer(10, this);
16644 focus : function(){
16645 if(this.win && !this.sourceEditMode){
16652 assignDocWin: function()
16654 var iframe = this.iframe;
16657 this.doc = iframe.contentWindow.document;
16658 this.win = iframe.contentWindow;
16660 // if (!Roo.get(this.frameId)) {
16663 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16664 // this.win = Roo.get(this.frameId).dom.contentWindow;
16666 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16670 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16671 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16676 initEditor : function(){
16677 //console.log("INIT EDITOR");
16678 this.assignDocWin();
16682 this.doc.designMode="on";
16684 this.doc.write(this.getDocMarkup());
16687 var dbody = (this.doc.body || this.doc.documentElement);
16688 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16689 // this copies styles from the containing element into thsi one..
16690 // not sure why we need all of this..
16691 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16693 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16694 //ss['background-attachment'] = 'fixed'; // w3c
16695 dbody.bgProperties = 'fixed'; // ie
16696 //Roo.DomHelper.applyStyles(dbody, ss);
16697 Roo.EventManager.on(this.doc, {
16698 //'mousedown': this.onEditorEvent,
16699 'mouseup': this.onEditorEvent,
16700 'dblclick': this.onEditorEvent,
16701 'click': this.onEditorEvent,
16702 'keyup': this.onEditorEvent,
16707 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16709 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16710 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16712 this.initialized = true;
16714 this.owner.fireEvent('initialize', this);
16719 onDestroy : function(){
16725 //for (var i =0; i < this.toolbars.length;i++) {
16726 // // fixme - ask toolbars for heights?
16727 // this.toolbars[i].onDestroy();
16730 //this.wrap.dom.innerHTML = '';
16731 //this.wrap.remove();
16736 onFirstFocus : function(){
16738 this.assignDocWin();
16741 this.activated = true;
16744 if(Roo.isGecko){ // prevent silly gecko errors
16746 var s = this.win.getSelection();
16747 if(!s.focusNode || s.focusNode.nodeType != 3){
16748 var r = s.getRangeAt(0);
16749 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16754 this.execCmd('useCSS', true);
16755 this.execCmd('styleWithCSS', false);
16758 this.owner.fireEvent('activate', this);
16762 adjustFont: function(btn){
16763 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16764 //if(Roo.isSafari){ // safari
16767 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16768 if(Roo.isSafari){ // safari
16769 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16770 v = (v < 10) ? 10 : v;
16771 v = (v > 48) ? 48 : v;
16772 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16777 v = Math.max(1, v+adjust);
16779 this.execCmd('FontSize', v );
16782 onEditorEvent : function(e){
16783 this.owner.fireEvent('editorevent', this, e);
16784 // this.updateToolbar();
16785 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16788 insertTag : function(tg)
16790 // could be a bit smarter... -> wrap the current selected tRoo..
16791 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16793 range = this.createRange(this.getSelection());
16794 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16795 wrappingNode.appendChild(range.extractContents());
16796 range.insertNode(wrappingNode);
16803 this.execCmd("formatblock", tg);
16807 insertText : function(txt)
16811 var range = this.createRange();
16812 range.deleteContents();
16813 //alert(Sender.getAttribute('label'));
16815 range.insertNode(this.doc.createTextNode(txt));
16821 * Executes a Midas editor command on the editor document and performs necessary focus and
16822 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16823 * @param {String} cmd The Midas command
16824 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16826 relayCmd : function(cmd, value){
16828 this.execCmd(cmd, value);
16829 this.owner.fireEvent('editorevent', this);
16830 //this.updateToolbar();
16831 this.owner.deferFocus();
16835 * Executes a Midas editor command directly on the editor document.
16836 * For visual commands, you should use {@link #relayCmd} instead.
16837 * <b>This should only be called after the editor is initialized.</b>
16838 * @param {String} cmd The Midas command
16839 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16841 execCmd : function(cmd, value){
16842 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16849 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16851 * @param {String} text | dom node..
16853 insertAtCursor : function(text)
16858 if(!this.activated){
16864 var r = this.doc.selection.createRange();
16875 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16879 // from jquery ui (MIT licenced)
16881 var win = this.win;
16883 if (win.getSelection && win.getSelection().getRangeAt) {
16884 range = win.getSelection().getRangeAt(0);
16885 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16886 range.insertNode(node);
16887 } else if (win.document.selection && win.document.selection.createRange) {
16888 // no firefox support
16889 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16890 win.document.selection.createRange().pasteHTML(txt);
16892 // no firefox support
16893 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16894 this.execCmd('InsertHTML', txt);
16903 mozKeyPress : function(e){
16905 var c = e.getCharCode(), cmd;
16908 c = String.fromCharCode(c).toLowerCase();
16922 this.cleanUpPaste.defer(100, this);
16930 e.preventDefault();
16938 fixKeys : function(){ // load time branching for fastest keydown performance
16940 return function(e){
16941 var k = e.getKey(), r;
16944 r = this.doc.selection.createRange();
16947 r.pasteHTML('    ');
16954 r = this.doc.selection.createRange();
16956 var target = r.parentElement();
16957 if(!target || target.tagName.toLowerCase() != 'li'){
16959 r.pasteHTML('<br />');
16965 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16966 this.cleanUpPaste.defer(100, this);
16972 }else if(Roo.isOpera){
16973 return function(e){
16974 var k = e.getKey();
16978 this.execCmd('InsertHTML','    ');
16981 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16982 this.cleanUpPaste.defer(100, this);
16987 }else if(Roo.isSafari){
16988 return function(e){
16989 var k = e.getKey();
16993 this.execCmd('InsertText','\t');
16997 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16998 this.cleanUpPaste.defer(100, this);
17006 getAllAncestors: function()
17008 var p = this.getSelectedNode();
17011 a.push(p); // push blank onto stack..
17012 p = this.getParentElement();
17016 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17020 a.push(this.doc.body);
17024 lastSelNode : false,
17027 getSelection : function()
17029 this.assignDocWin();
17030 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17033 getSelectedNode: function()
17035 // this may only work on Gecko!!!
17037 // should we cache this!!!!
17042 var range = this.createRange(this.getSelection()).cloneRange();
17045 var parent = range.parentElement();
17047 var testRange = range.duplicate();
17048 testRange.moveToElementText(parent);
17049 if (testRange.inRange(range)) {
17052 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17055 parent = parent.parentElement;
17060 // is ancestor a text element.
17061 var ac = range.commonAncestorContainer;
17062 if (ac.nodeType == 3) {
17063 ac = ac.parentNode;
17066 var ar = ac.childNodes;
17069 var other_nodes = [];
17070 var has_other_nodes = false;
17071 for (var i=0;i<ar.length;i++) {
17072 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17075 // fullly contained node.
17077 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17082 // probably selected..
17083 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17084 other_nodes.push(ar[i]);
17088 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17093 has_other_nodes = true;
17095 if (!nodes.length && other_nodes.length) {
17096 nodes= other_nodes;
17098 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17104 createRange: function(sel)
17106 // this has strange effects when using with
17107 // top toolbar - not sure if it's a great idea.
17108 //this.editor.contentWindow.focus();
17109 if (typeof sel != "undefined") {
17111 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17113 return this.doc.createRange();
17116 return this.doc.createRange();
17119 getParentElement: function()
17122 this.assignDocWin();
17123 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17125 var range = this.createRange(sel);
17128 var p = range.commonAncestorContainer;
17129 while (p.nodeType == 3) { // text node
17140 * Range intersection.. the hard stuff...
17144 * [ -- selected range --- ]
17148 * if end is before start or hits it. fail.
17149 * if start is after end or hits it fail.
17151 * if either hits (but other is outside. - then it's not
17157 // @see http://www.thismuchiknow.co.uk/?p=64.
17158 rangeIntersectsNode : function(range, node)
17160 var nodeRange = node.ownerDocument.createRange();
17162 nodeRange.selectNode(node);
17164 nodeRange.selectNodeContents(node);
17167 var rangeStartRange = range.cloneRange();
17168 rangeStartRange.collapse(true);
17170 var rangeEndRange = range.cloneRange();
17171 rangeEndRange.collapse(false);
17173 var nodeStartRange = nodeRange.cloneRange();
17174 nodeStartRange.collapse(true);
17176 var nodeEndRange = nodeRange.cloneRange();
17177 nodeEndRange.collapse(false);
17179 return rangeStartRange.compareBoundaryPoints(
17180 Range.START_TO_START, nodeEndRange) == -1 &&
17181 rangeEndRange.compareBoundaryPoints(
17182 Range.START_TO_START, nodeStartRange) == 1;
17186 rangeCompareNode : function(range, node)
17188 var nodeRange = node.ownerDocument.createRange();
17190 nodeRange.selectNode(node);
17192 nodeRange.selectNodeContents(node);
17196 range.collapse(true);
17198 nodeRange.collapse(true);
17200 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17201 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17203 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17205 var nodeIsBefore = ss == 1;
17206 var nodeIsAfter = ee == -1;
17208 if (nodeIsBefore && nodeIsAfter)
17210 if (!nodeIsBefore && nodeIsAfter)
17211 return 1; //right trailed.
17213 if (nodeIsBefore && !nodeIsAfter)
17214 return 2; // left trailed.
17219 // private? - in a new class?
17220 cleanUpPaste : function()
17222 // cleans up the whole document..
17223 Roo.log('cleanuppaste');
17225 this.cleanUpChildren(this.doc.body);
17226 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17227 if (clean != this.doc.body.innerHTML) {
17228 this.doc.body.innerHTML = clean;
17233 cleanWordChars : function(input) {// change the chars to hex code
17234 var he = Roo.HtmlEditorCore;
17236 var output = input;
17237 Roo.each(he.swapCodes, function(sw) {
17238 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17240 output = output.replace(swapper, sw[1]);
17247 cleanUpChildren : function (n)
17249 if (!n.childNodes.length) {
17252 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17253 this.cleanUpChild(n.childNodes[i]);
17260 cleanUpChild : function (node)
17263 //console.log(node);
17264 if (node.nodeName == "#text") {
17265 // clean up silly Windows -- stuff?
17268 if (node.nodeName == "#comment") {
17269 node.parentNode.removeChild(node);
17270 // clean up silly Windows -- stuff?
17274 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17276 node.parentNode.removeChild(node);
17281 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17283 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17284 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17286 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17287 // remove_keep_children = true;
17290 if (remove_keep_children) {
17291 this.cleanUpChildren(node);
17292 // inserts everything just before this node...
17293 while (node.childNodes.length) {
17294 var cn = node.childNodes[0];
17295 node.removeChild(cn);
17296 node.parentNode.insertBefore(cn, node);
17298 node.parentNode.removeChild(node);
17302 if (!node.attributes || !node.attributes.length) {
17303 this.cleanUpChildren(node);
17307 function cleanAttr(n,v)
17310 if (v.match(/^\./) || v.match(/^\//)) {
17313 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17316 if (v.match(/^#/)) {
17319 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17320 node.removeAttribute(n);
17324 function cleanStyle(n,v)
17326 if (v.match(/expression/)) { //XSS?? should we even bother..
17327 node.removeAttribute(n);
17330 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17331 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17334 var parts = v.split(/;/);
17337 Roo.each(parts, function(p) {
17338 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17342 var l = p.split(':').shift().replace(/\s+/g,'');
17343 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17345 if ( cblack.indexOf(l) > -1) {
17346 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17347 //node.removeAttribute(n);
17351 // only allow 'c whitelisted system attributes'
17352 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17353 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17354 //node.removeAttribute(n);
17364 if (clean.length) {
17365 node.setAttribute(n, clean.join(';'));
17367 node.removeAttribute(n);
17373 for (var i = node.attributes.length-1; i > -1 ; i--) {
17374 var a = node.attributes[i];
17377 if (a.name.toLowerCase().substr(0,2)=='on') {
17378 node.removeAttribute(a.name);
17381 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17382 node.removeAttribute(a.name);
17385 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17386 cleanAttr(a.name,a.value); // fixme..
17389 if (a.name == 'style') {
17390 cleanStyle(a.name,a.value);
17393 /// clean up MS crap..
17394 // tecnically this should be a list of valid class'es..
17397 if (a.name == 'class') {
17398 if (a.value.match(/^Mso/)) {
17399 node.className = '';
17402 if (a.value.match(/body/)) {
17403 node.className = '';
17414 this.cleanUpChildren(node);
17419 * Clean up MS wordisms...
17421 cleanWord : function(node)
17424 var cleanWordChildren = function()
17426 if (!node.childNodes.length) {
17429 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17430 _t.cleanWord(node.childNodes[i]);
17436 this.cleanWord(this.doc.body);
17439 if (node.nodeName == "#text") {
17440 // clean up silly Windows -- stuff?
17443 if (node.nodeName == "#comment") {
17444 node.parentNode.removeChild(node);
17445 // clean up silly Windows -- stuff?
17449 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17450 node.parentNode.removeChild(node);
17454 // remove - but keep children..
17455 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17456 while (node.childNodes.length) {
17457 var cn = node.childNodes[0];
17458 node.removeChild(cn);
17459 node.parentNode.insertBefore(cn, node);
17461 node.parentNode.removeChild(node);
17462 cleanWordChildren();
17466 if (node.className.length) {
17468 var cn = node.className.split(/\W+/);
17470 Roo.each(cn, function(cls) {
17471 if (cls.match(/Mso[a-zA-Z]+/)) {
17476 node.className = cna.length ? cna.join(' ') : '';
17478 node.removeAttribute("class");
17482 if (node.hasAttribute("lang")) {
17483 node.removeAttribute("lang");
17486 if (node.hasAttribute("style")) {
17488 var styles = node.getAttribute("style").split(";");
17490 Roo.each(styles, function(s) {
17491 if (!s.match(/:/)) {
17494 var kv = s.split(":");
17495 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17498 // what ever is left... we allow.
17501 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17502 if (!nstyle.length) {
17503 node.removeAttribute('style');
17507 cleanWordChildren();
17511 domToHTML : function(currentElement, depth, nopadtext) {
17513 depth = depth || 0;
17514 nopadtext = nopadtext || false;
17516 if (!currentElement) {
17517 return this.domToHTML(this.doc.body);
17520 //Roo.log(currentElement);
17522 var allText = false;
17523 var nodeName = currentElement.nodeName;
17524 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17526 if (nodeName == '#text') {
17527 return currentElement.nodeValue;
17532 if (nodeName != 'BODY') {
17535 // Prints the node tagName, such as <A>, <IMG>, etc
17538 for(i = 0; i < currentElement.attributes.length;i++) {
17540 var aname = currentElement.attributes.item(i).name;
17541 if (!currentElement.attributes.item(i).value.length) {
17544 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17547 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17556 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17559 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17564 // Traverse the tree
17566 var currentElementChild = currentElement.childNodes.item(i);
17567 var allText = true;
17568 var innerHTML = '';
17570 while (currentElementChild) {
17571 // Formatting code (indent the tree so it looks nice on the screen)
17572 var nopad = nopadtext;
17573 if (lastnode == 'SPAN') {
17577 if (currentElementChild.nodeName == '#text') {
17578 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17579 if (!nopad && toadd.length > 80) {
17580 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17582 innerHTML += toadd;
17585 currentElementChild = currentElement.childNodes.item(i);
17591 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17593 // Recursively traverse the tree structure of the child node
17594 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17595 lastnode = currentElementChild.nodeName;
17597 currentElementChild=currentElement.childNodes.item(i);
17603 // The remaining code is mostly for formatting the tree
17604 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17609 ret+= "</"+tagName+">";
17615 // hide stuff that is not compatible
17629 * @event specialkey
17633 * @cfg {String} fieldClass @hide
17636 * @cfg {String} focusClass @hide
17639 * @cfg {String} autoCreate @hide
17642 * @cfg {String} inputType @hide
17645 * @cfg {String} invalidClass @hide
17648 * @cfg {String} invalidText @hide
17651 * @cfg {String} msgFx @hide
17654 * @cfg {String} validateOnBlur @hide
17658 Roo.HtmlEditorCore.white = [
17659 'area', 'br', 'img', 'input', 'hr', 'wbr',
17661 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17662 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17663 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17664 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17665 'table', 'ul', 'xmp',
17667 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17670 'dir', 'menu', 'ol', 'ul', 'dl',
17676 Roo.HtmlEditorCore.black = [
17677 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17679 'base', 'basefont', 'bgsound', 'blink', 'body',
17680 'frame', 'frameset', 'head', 'html', 'ilayer',
17681 'iframe', 'layer', 'link', 'meta', 'object',
17682 'script', 'style' ,'title', 'xml' // clean later..
17684 Roo.HtmlEditorCore.clean = [
17685 'script', 'style', 'title', 'xml'
17687 Roo.HtmlEditorCore.remove = [
17692 Roo.HtmlEditorCore.ablack = [
17696 Roo.HtmlEditorCore.aclean = [
17697 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17701 Roo.HtmlEditorCore.pwhite= [
17702 'http', 'https', 'mailto'
17705 // white listed style attributes.
17706 Roo.HtmlEditorCore.cwhite= [
17707 // 'text-align', /// default is to allow most things..
17713 // black listed style attributes.
17714 Roo.HtmlEditorCore.cblack= [
17715 // 'font-size' -- this can be set by the project
17719 Roo.HtmlEditorCore.swapCodes =[
17738 * @class Roo.bootstrap.HtmlEditor
17739 * @extends Roo.bootstrap.TextArea
17740 * Bootstrap HtmlEditor class
17743 * Create a new HtmlEditor
17744 * @param {Object} config The config object
17747 Roo.bootstrap.HtmlEditor = function(config){
17748 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17749 if (!this.toolbars) {
17750 this.toolbars = [];
17752 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17755 * @event initialize
17756 * Fires when the editor is fully initialized (including the iframe)
17757 * @param {HtmlEditor} this
17762 * Fires when the editor is first receives the focus. Any insertion must wait
17763 * until after this event.
17764 * @param {HtmlEditor} this
17768 * @event beforesync
17769 * Fires before the textarea is updated with content from the editor iframe. Return false
17770 * to cancel the sync.
17771 * @param {HtmlEditor} this
17772 * @param {String} html
17776 * @event beforepush
17777 * Fires before the iframe editor is updated with content from the textarea. Return false
17778 * to cancel the push.
17779 * @param {HtmlEditor} this
17780 * @param {String} html
17785 * Fires when the textarea is updated with content from the editor iframe.
17786 * @param {HtmlEditor} this
17787 * @param {String} html
17792 * Fires when the iframe editor is updated with content from the textarea.
17793 * @param {HtmlEditor} this
17794 * @param {String} html
17798 * @event editmodechange
17799 * Fires when the editor switches edit modes
17800 * @param {HtmlEditor} this
17801 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17803 editmodechange: true,
17805 * @event editorevent
17806 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17807 * @param {HtmlEditor} this
17811 * @event firstfocus
17812 * Fires when on first focus - needed by toolbars..
17813 * @param {HtmlEditor} this
17818 * Auto save the htmlEditor value as a file into Events
17819 * @param {HtmlEditor} this
17823 * @event savedpreview
17824 * preview the saved version of htmlEditor
17825 * @param {HtmlEditor} this
17832 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17836 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17841 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17846 * @cfg {Number} height (in pixels)
17850 * @cfg {Number} width (in pixels)
17855 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17858 stylesheets: false,
17863 // private properties
17864 validationEvent : false,
17866 initialized : false,
17869 onFocus : Roo.emptyFn,
17871 hideMode:'offsets',
17874 tbContainer : false,
17876 toolbarContainer :function() {
17877 return this.wrap.select('.x-html-editor-tb',true).first();
17881 * Protected method that will not generally be called directly. It
17882 * is called when the editor creates its toolbar. Override this method if you need to
17883 * add custom toolbar buttons.
17884 * @param {HtmlEditor} editor
17886 createToolbar : function(){
17888 Roo.log("create toolbars");
17890 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17891 this.toolbars[0].render(this.toolbarContainer());
17895 // if (!editor.toolbars || !editor.toolbars.length) {
17896 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17899 // for (var i =0 ; i < editor.toolbars.length;i++) {
17900 // editor.toolbars[i] = Roo.factory(
17901 // typeof(editor.toolbars[i]) == 'string' ?
17902 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17903 // Roo.bootstrap.HtmlEditor);
17904 // editor.toolbars[i].init(editor);
17910 onRender : function(ct, position)
17912 // Roo.log("Call onRender: " + this.xtype);
17914 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17916 this.wrap = this.inputEl().wrap({
17917 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17920 this.editorcore.onRender(ct, position);
17922 if (this.resizable) {
17923 this.resizeEl = new Roo.Resizable(this.wrap, {
17927 minHeight : this.height,
17928 height: this.height,
17929 handles : this.resizable,
17932 resize : function(r, w, h) {
17933 _t.onResize(w,h); // -something
17939 this.createToolbar(this);
17942 if(!this.width && this.resizable){
17943 this.setSize(this.wrap.getSize());
17945 if (this.resizeEl) {
17946 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17947 // should trigger onReize..
17953 onResize : function(w, h)
17955 Roo.log('resize: ' +w + ',' + h );
17956 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17960 if(this.inputEl() ){
17961 if(typeof w == 'number'){
17962 var aw = w - this.wrap.getFrameWidth('lr');
17963 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17966 if(typeof h == 'number'){
17967 var tbh = -11; // fixme it needs to tool bar size!
17968 for (var i =0; i < this.toolbars.length;i++) {
17969 // fixme - ask toolbars for heights?
17970 tbh += this.toolbars[i].el.getHeight();
17971 //if (this.toolbars[i].footer) {
17972 // tbh += this.toolbars[i].footer.el.getHeight();
17980 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17981 ah -= 5; // knock a few pixes off for look..
17982 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17986 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17987 this.editorcore.onResize(ew,eh);
17992 * Toggles the editor between standard and source edit mode.
17993 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17995 toggleSourceEdit : function(sourceEditMode)
17997 this.editorcore.toggleSourceEdit(sourceEditMode);
17999 if(this.editorcore.sourceEditMode){
18000 Roo.log('editor - showing textarea');
18003 // Roo.log(this.syncValue());
18005 this.inputEl().removeClass(['hide', 'x-hidden']);
18006 this.inputEl().dom.removeAttribute('tabIndex');
18007 this.inputEl().focus();
18009 Roo.log('editor - hiding textarea');
18011 // Roo.log(this.pushValue());
18014 this.inputEl().addClass(['hide', 'x-hidden']);
18015 this.inputEl().dom.setAttribute('tabIndex', -1);
18016 //this.deferFocus();
18019 if(this.resizable){
18020 this.setSize(this.wrap.getSize());
18023 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18026 // private (for BoxComponent)
18027 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18029 // private (for BoxComponent)
18030 getResizeEl : function(){
18034 // private (for BoxComponent)
18035 getPositionEl : function(){
18040 initEvents : function(){
18041 this.originalValue = this.getValue();
18045 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18048 // markInvalid : Roo.emptyFn,
18050 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18053 // clearInvalid : Roo.emptyFn,
18055 setValue : function(v){
18056 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18057 this.editorcore.pushValue();
18062 deferFocus : function(){
18063 this.focus.defer(10, this);
18067 focus : function(){
18068 this.editorcore.focus();
18074 onDestroy : function(){
18080 for (var i =0; i < this.toolbars.length;i++) {
18081 // fixme - ask toolbars for heights?
18082 this.toolbars[i].onDestroy();
18085 this.wrap.dom.innerHTML = '';
18086 this.wrap.remove();
18091 onFirstFocus : function(){
18092 //Roo.log("onFirstFocus");
18093 this.editorcore.onFirstFocus();
18094 for (var i =0; i < this.toolbars.length;i++) {
18095 this.toolbars[i].onFirstFocus();
18101 syncValue : function()
18103 this.editorcore.syncValue();
18106 pushValue : function()
18108 this.editorcore.pushValue();
18112 // hide stuff that is not compatible
18126 * @event specialkey
18130 * @cfg {String} fieldClass @hide
18133 * @cfg {String} focusClass @hide
18136 * @cfg {String} autoCreate @hide
18139 * @cfg {String} inputType @hide
18142 * @cfg {String} invalidClass @hide
18145 * @cfg {String} invalidText @hide
18148 * @cfg {String} msgFx @hide
18151 * @cfg {String} validateOnBlur @hide
18160 Roo.namespace('Roo.bootstrap.htmleditor');
18162 * @class Roo.bootstrap.HtmlEditorToolbar1
18167 new Roo.bootstrap.HtmlEditor({
18170 new Roo.bootstrap.HtmlEditorToolbar1({
18171 disable : { fonts: 1 , format: 1, ..., ... , ...],
18177 * @cfg {Object} disable List of elements to disable..
18178 * @cfg {Array} btns List of additional buttons.
18182 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18185 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18188 Roo.apply(this, config);
18190 // default disabled, based on 'good practice'..
18191 this.disable = this.disable || {};
18192 Roo.applyIf(this.disable, {
18195 specialElements : true
18197 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18199 this.editor = config.editor;
18200 this.editorcore = config.editor.editorcore;
18202 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18204 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18205 // dont call parent... till later.
18207 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18212 editorcore : false,
18217 "h1","h2","h3","h4","h5","h6",
18219 "abbr", "acronym", "address", "cite", "samp", "var",
18223 onRender : function(ct, position)
18225 // Roo.log("Call onRender: " + this.xtype);
18227 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18229 this.el.dom.style.marginBottom = '0';
18231 var editorcore = this.editorcore;
18232 var editor= this.editor;
18235 var btn = function(id,cmd , toggle, handler){
18237 var event = toggle ? 'toggle' : 'click';
18242 xns: Roo.bootstrap,
18245 enableToggle:toggle !== false,
18247 pressed : toggle ? false : null,
18250 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18251 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18260 xns: Roo.bootstrap,
18261 glyphicon : 'font',
18265 xns: Roo.bootstrap,
18269 Roo.each(this.formats, function(f) {
18270 style.menu.items.push({
18272 xns: Roo.bootstrap,
18273 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18278 editorcore.insertTag(this.tagname);
18285 children.push(style);
18288 btn('bold',false,true);
18289 btn('italic',false,true);
18290 btn('align-left', 'justifyleft',true);
18291 btn('align-center', 'justifycenter',true);
18292 btn('align-right' , 'justifyright',true);
18293 btn('link', false, false, function(btn) {
18294 //Roo.log("create link?");
18295 var url = prompt(this.createLinkText, this.defaultLinkValue);
18296 if(url && url != 'http:/'+'/'){
18297 this.editorcore.relayCmd('createlink', url);
18300 btn('list','insertunorderedlist',true);
18301 btn('pencil', false,true, function(btn){
18304 this.toggleSourceEdit(btn.pressed);
18310 xns: Roo.bootstrap,
18315 xns: Roo.bootstrap,
18320 cog.menu.items.push({
18322 xns: Roo.bootstrap,
18323 html : Clean styles,
18328 editorcore.insertTag(this.tagname);
18337 this.xtype = 'NavSimplebar';
18339 for(var i=0;i< children.length;i++) {
18341 this.buttons.add(this.addxtypeChild(children[i]));
18345 editor.on('editorevent', this.updateToolbar, this);
18347 onBtnClick : function(id)
18349 this.editorcore.relayCmd(id);
18350 this.editorcore.focus();
18354 * Protected method that will not generally be called directly. It triggers
18355 * a toolbar update by reading the markup state of the current selection in the editor.
18357 updateToolbar: function(){
18359 if(!this.editorcore.activated){
18360 this.editor.onFirstFocus(); // is this neeed?
18364 var btns = this.buttons;
18365 var doc = this.editorcore.doc;
18366 btns.get('bold').setActive(doc.queryCommandState('bold'));
18367 btns.get('italic').setActive(doc.queryCommandState('italic'));
18368 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18370 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18371 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18372 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18374 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18375 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18378 var ans = this.editorcore.getAllAncestors();
18379 if (this.formatCombo) {
18382 var store = this.formatCombo.store;
18383 this.formatCombo.setValue("");
18384 for (var i =0; i < ans.length;i++) {
18385 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18387 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18395 // hides menus... - so this cant be on a menu...
18396 Roo.bootstrap.MenuMgr.hideAll();
18398 Roo.bootstrap.MenuMgr.hideAll();
18399 //this.editorsyncValue();
18401 onFirstFocus: function() {
18402 this.buttons.each(function(item){
18406 toggleSourceEdit : function(sourceEditMode){
18409 if(sourceEditMode){
18410 Roo.log("disabling buttons");
18411 this.buttons.each( function(item){
18412 if(item.cmd != 'pencil'){
18418 Roo.log("enabling buttons");
18419 if(this.editorcore.initialized){
18420 this.buttons.each( function(item){
18426 Roo.log("calling toggole on editor");
18427 // tell the editor that it's been pressed..
18428 this.editor.toggleSourceEdit(sourceEditMode);
18438 * @class Roo.bootstrap.Table.AbstractSelectionModel
18439 * @extends Roo.util.Observable
18440 * Abstract base class for grid SelectionModels. It provides the interface that should be
18441 * implemented by descendant classes. This class should not be directly instantiated.
18444 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18445 this.locked = false;
18446 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18450 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18451 /** @ignore Called by the grid automatically. Do not call directly. */
18452 init : function(grid){
18458 * Locks the selections.
18461 this.locked = true;
18465 * Unlocks the selections.
18467 unlock : function(){
18468 this.locked = false;
18472 * Returns true if the selections are locked.
18473 * @return {Boolean}
18475 isLocked : function(){
18476 return this.locked;
18480 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18481 * @class Roo.bootstrap.Table.RowSelectionModel
18482 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18483 * It supports multiple selections and keyboard selection/navigation.
18485 * @param {Object} config
18488 Roo.bootstrap.Table.RowSelectionModel = function(config){
18489 Roo.apply(this, config);
18490 this.selections = new Roo.util.MixedCollection(false, function(o){
18495 this.lastActive = false;
18499 * @event selectionchange
18500 * Fires when the selection changes
18501 * @param {SelectionModel} this
18503 "selectionchange" : true,
18505 * @event afterselectionchange
18506 * Fires after the selection changes (eg. by key press or clicking)
18507 * @param {SelectionModel} this
18509 "afterselectionchange" : true,
18511 * @event beforerowselect
18512 * Fires when a row is selected being selected, return false to cancel.
18513 * @param {SelectionModel} this
18514 * @param {Number} rowIndex The selected index
18515 * @param {Boolean} keepExisting False if other selections will be cleared
18517 "beforerowselect" : true,
18520 * Fires when a row is selected.
18521 * @param {SelectionModel} this
18522 * @param {Number} rowIndex The selected index
18523 * @param {Roo.data.Record} r The record
18525 "rowselect" : true,
18527 * @event rowdeselect
18528 * Fires when a row is deselected.
18529 * @param {SelectionModel} this
18530 * @param {Number} rowIndex The selected index
18532 "rowdeselect" : true
18534 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18535 this.locked = false;
18538 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18540 * @cfg {Boolean} singleSelect
18541 * True to allow selection of only one row at a time (defaults to false)
18543 singleSelect : false,
18546 initEvents : function(){
18548 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18549 this.grid.on("mousedown", this.handleMouseDown, this);
18550 }else{ // allow click to work like normal
18551 this.grid.on("rowclick", this.handleDragableRowClick, this);
18554 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18555 "up" : function(e){
18557 this.selectPrevious(e.shiftKey);
18558 }else if(this.last !== false && this.lastActive !== false){
18559 var last = this.last;
18560 this.selectRange(this.last, this.lastActive-1);
18561 this.grid.getView().focusRow(this.lastActive);
18562 if(last !== false){
18566 this.selectFirstRow();
18568 this.fireEvent("afterselectionchange", this);
18570 "down" : function(e){
18572 this.selectNext(e.shiftKey);
18573 }else if(this.last !== false && this.lastActive !== false){
18574 var last = this.last;
18575 this.selectRange(this.last, this.lastActive+1);
18576 this.grid.getView().focusRow(this.lastActive);
18577 if(last !== false){
18581 this.selectFirstRow();
18583 this.fireEvent("afterselectionchange", this);
18588 var view = this.grid.view;
18589 view.on("refresh", this.onRefresh, this);
18590 view.on("rowupdated", this.onRowUpdated, this);
18591 view.on("rowremoved", this.onRemove, this);
18595 onRefresh : function(){
18596 var ds = this.grid.dataSource, i, v = this.grid.view;
18597 var s = this.selections;
18598 s.each(function(r){
18599 if((i = ds.indexOfId(r.id)) != -1){
18608 onRemove : function(v, index, r){
18609 this.selections.remove(r);
18613 onRowUpdated : function(v, index, r){
18614 if(this.isSelected(r)){
18615 v.onRowSelect(index);
18621 * @param {Array} records The records to select
18622 * @param {Boolean} keepExisting (optional) True to keep existing selections
18624 selectRecords : function(records, keepExisting){
18626 this.clearSelections();
18628 var ds = this.grid.dataSource;
18629 for(var i = 0, len = records.length; i < len; i++){
18630 this.selectRow(ds.indexOf(records[i]), true);
18635 * Gets the number of selected rows.
18638 getCount : function(){
18639 return this.selections.length;
18643 * Selects the first row in the grid.
18645 selectFirstRow : function(){
18650 * Select the last row.
18651 * @param {Boolean} keepExisting (optional) True to keep existing selections
18653 selectLastRow : function(keepExisting){
18654 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18658 * Selects the row immediately following the last selected row.
18659 * @param {Boolean} keepExisting (optional) True to keep existing selections
18661 selectNext : function(keepExisting){
18662 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18663 this.selectRow(this.last+1, keepExisting);
18664 this.grid.getView().focusRow(this.last);
18669 * Selects the row that precedes the last selected row.
18670 * @param {Boolean} keepExisting (optional) True to keep existing selections
18672 selectPrevious : function(keepExisting){
18674 this.selectRow(this.last-1, keepExisting);
18675 this.grid.getView().focusRow(this.last);
18680 * Returns the selected records
18681 * @return {Array} Array of selected records
18683 getSelections : function(){
18684 return [].concat(this.selections.items);
18688 * Returns the first selected record.
18691 getSelected : function(){
18692 return this.selections.itemAt(0);
18697 * Clears all selections.
18699 clearSelections : function(fast){
18700 if(this.locked) return;
18702 var ds = this.grid.dataSource;
18703 var s = this.selections;
18704 s.each(function(r){
18705 this.deselectRow(ds.indexOfId(r.id));
18709 this.selections.clear();
18716 * Selects all rows.
18718 selectAll : function(){
18719 if(this.locked) return;
18720 this.selections.clear();
18721 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18722 this.selectRow(i, true);
18727 * Returns True if there is a selection.
18728 * @return {Boolean}
18730 hasSelection : function(){
18731 return this.selections.length > 0;
18735 * Returns True if the specified row is selected.
18736 * @param {Number/Record} record The record or index of the record to check
18737 * @return {Boolean}
18739 isSelected : function(index){
18740 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18741 return (r && this.selections.key(r.id) ? true : false);
18745 * Returns True if the specified record id is selected.
18746 * @param {String} id The id of record to check
18747 * @return {Boolean}
18749 isIdSelected : function(id){
18750 return (this.selections.key(id) ? true : false);
18754 handleMouseDown : function(e, t){
18755 var view = this.grid.getView(), rowIndex;
18756 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18759 if(e.shiftKey && this.last !== false){
18760 var last = this.last;
18761 this.selectRange(last, rowIndex, e.ctrlKey);
18762 this.last = last; // reset the last
18763 view.focusRow(rowIndex);
18765 var isSelected = this.isSelected(rowIndex);
18766 if(e.button !== 0 && isSelected){
18767 view.focusRow(rowIndex);
18768 }else if(e.ctrlKey && isSelected){
18769 this.deselectRow(rowIndex);
18770 }else if(!isSelected){
18771 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18772 view.focusRow(rowIndex);
18775 this.fireEvent("afterselectionchange", this);
18778 handleDragableRowClick : function(grid, rowIndex, e)
18780 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18781 this.selectRow(rowIndex, false);
18782 grid.view.focusRow(rowIndex);
18783 this.fireEvent("afterselectionchange", this);
18788 * Selects multiple rows.
18789 * @param {Array} rows Array of the indexes of the row to select
18790 * @param {Boolean} keepExisting (optional) True to keep existing selections
18792 selectRows : function(rows, keepExisting){
18794 this.clearSelections();
18796 for(var i = 0, len = rows.length; i < len; i++){
18797 this.selectRow(rows[i], true);
18802 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18803 * @param {Number} startRow The index of the first row in the range
18804 * @param {Number} endRow The index of the last row in the range
18805 * @param {Boolean} keepExisting (optional) True to retain existing selections
18807 selectRange : function(startRow, endRow, keepExisting){
18808 if(this.locked) return;
18810 this.clearSelections();
18812 if(startRow <= endRow){
18813 for(var i = startRow; i <= endRow; i++){
18814 this.selectRow(i, true);
18817 for(var i = startRow; i >= endRow; i--){
18818 this.selectRow(i, true);
18824 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18825 * @param {Number} startRow The index of the first row in the range
18826 * @param {Number} endRow The index of the last row in the range
18828 deselectRange : function(startRow, endRow, preventViewNotify){
18829 if(this.locked) return;
18830 for(var i = startRow; i <= endRow; i++){
18831 this.deselectRow(i, preventViewNotify);
18837 * @param {Number} row The index of the row to select
18838 * @param {Boolean} keepExisting (optional) True to keep existing selections
18840 selectRow : function(index, keepExisting, preventViewNotify){
18841 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18842 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18843 if(!keepExisting || this.singleSelect){
18844 this.clearSelections();
18846 var r = this.grid.dataSource.getAt(index);
18847 this.selections.add(r);
18848 this.last = this.lastActive = index;
18849 if(!preventViewNotify){
18850 this.grid.getView().onRowSelect(index);
18852 this.fireEvent("rowselect", this, index, r);
18853 this.fireEvent("selectionchange", this);
18859 * @param {Number} row The index of the row to deselect
18861 deselectRow : function(index, preventViewNotify){
18862 if(this.locked) return;
18863 if(this.last == index){
18866 if(this.lastActive == index){
18867 this.lastActive = false;
18869 var r = this.grid.dataSource.getAt(index);
18870 this.selections.remove(r);
18871 if(!preventViewNotify){
18872 this.grid.getView().onRowDeselect(index);
18874 this.fireEvent("rowdeselect", this, index);
18875 this.fireEvent("selectionchange", this);
18879 restoreLast : function(){
18881 this.last = this._last;
18886 acceptsNav : function(row, col, cm){
18887 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18891 onEditorKey : function(field, e){
18892 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18897 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18899 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18901 }else if(k == e.ENTER && !e.ctrlKey){
18905 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18907 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18909 }else if(k == e.ESC){
18913 g.startEditing(newCell[0], newCell[1]);
18918 * Ext JS Library 1.1.1
18919 * Copyright(c) 2006-2007, Ext JS, LLC.
18921 * Originally Released Under LGPL - original licence link has changed is not relivant.
18924 * <script type="text/javascript">
18928 * @class Roo.bootstrap.PagingToolbar
18930 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18932 * Create a new PagingToolbar
18933 * @param {Object} config The config object
18935 Roo.bootstrap.PagingToolbar = function(config)
18937 // old args format still supported... - xtype is prefered..
18938 // created from xtype...
18939 var ds = config.dataSource;
18940 this.toolbarItems = [];
18941 if (config.items) {
18942 this.toolbarItems = config.items;
18943 // config.items = [];
18946 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18953 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18957 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18959 * @cfg {Roo.data.Store} dataSource
18960 * The underlying data store providing the paged data
18963 * @cfg {String/HTMLElement/Element} container
18964 * container The id or element that will contain the toolbar
18967 * @cfg {Boolean} displayInfo
18968 * True to display the displayMsg (defaults to false)
18971 * @cfg {Number} pageSize
18972 * The number of records to display per page (defaults to 20)
18976 * @cfg {String} displayMsg
18977 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18979 displayMsg : 'Displaying {0} - {1} of {2}',
18981 * @cfg {String} emptyMsg
18982 * The message to display when no records are found (defaults to "No data to display")
18984 emptyMsg : 'No data to display',
18986 * Customizable piece of the default paging text (defaults to "Page")
18989 beforePageText : "Page",
18991 * Customizable piece of the default paging text (defaults to "of %0")
18994 afterPageText : "of {0}",
18996 * Customizable piece of the default paging text (defaults to "First Page")
18999 firstText : "First Page",
19001 * Customizable piece of the default paging text (defaults to "Previous Page")
19004 prevText : "Previous Page",
19006 * Customizable piece of the default paging text (defaults to "Next Page")
19009 nextText : "Next Page",
19011 * Customizable piece of the default paging text (defaults to "Last Page")
19014 lastText : "Last Page",
19016 * Customizable piece of the default paging text (defaults to "Refresh")
19019 refreshText : "Refresh",
19023 onRender : function(ct, position)
19025 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19026 this.navgroup.parentId = this.id;
19027 this.navgroup.onRender(this.el, null);
19028 // add the buttons to the navgroup
19030 if(this.displayInfo){
19031 Roo.log(this.el.select('ul.navbar-nav',true).first());
19032 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19033 this.displayEl = this.el.select('.x-paging-info', true).first();
19034 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19035 // this.displayEl = navel.el.select('span',true).first();
19041 Roo.each(_this.buttons, function(e){
19042 Roo.factory(e).onRender(_this.el, null);
19046 Roo.each(_this.toolbarItems, function(e) {
19047 _this.navgroup.addItem(e);
19050 this.first = this.navgroup.addItem({
19051 tooltip: this.firstText,
19053 icon : 'fa fa-backward',
19055 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19058 this.prev = this.navgroup.addItem({
19059 tooltip: this.prevText,
19061 icon : 'fa fa-step-backward',
19063 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19065 //this.addSeparator();
19068 var field = this.navgroup.addItem( {
19070 cls : 'x-paging-position',
19072 html : this.beforePageText +
19073 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19074 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19077 this.field = field.el.select('input', true).first();
19078 this.field.on("keydown", this.onPagingKeydown, this);
19079 this.field.on("focus", function(){this.dom.select();});
19082 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19083 //this.field.setHeight(18);
19084 //this.addSeparator();
19085 this.next = this.navgroup.addItem({
19086 tooltip: this.nextText,
19088 html : ' <i class="fa fa-step-forward">',
19090 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19092 this.last = this.navgroup.addItem({
19093 tooltip: this.lastText,
19094 icon : 'fa fa-forward',
19097 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19099 //this.addSeparator();
19100 this.loading = this.navgroup.addItem({
19101 tooltip: this.refreshText,
19102 icon: 'fa fa-refresh',
19104 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19110 updateInfo : function(){
19111 if(this.displayEl){
19112 var count = this.ds.getCount();
19113 var msg = count == 0 ?
19117 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19119 this.displayEl.update(msg);
19124 onLoad : function(ds, r, o){
19125 this.cursor = o.params ? o.params.start : 0;
19126 var d = this.getPageData(),
19130 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19131 this.field.dom.value = ap;
19132 this.first.setDisabled(ap == 1);
19133 this.prev.setDisabled(ap == 1);
19134 this.next.setDisabled(ap == ps);
19135 this.last.setDisabled(ap == ps);
19136 this.loading.enable();
19141 getPageData : function(){
19142 var total = this.ds.getTotalCount();
19145 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19146 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19151 onLoadError : function(){
19152 this.loading.enable();
19156 onPagingKeydown : function(e){
19157 var k = e.getKey();
19158 var d = this.getPageData();
19160 var v = this.field.dom.value, pageNum;
19161 if(!v || isNaN(pageNum = parseInt(v, 10))){
19162 this.field.dom.value = d.activePage;
19165 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19166 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19169 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))
19171 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19172 this.field.dom.value = pageNum;
19173 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19176 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19178 var v = this.field.dom.value, pageNum;
19179 var increment = (e.shiftKey) ? 10 : 1;
19180 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19182 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19183 this.field.dom.value = d.activePage;
19186 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19188 this.field.dom.value = parseInt(v, 10) + increment;
19189 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19190 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19197 beforeLoad : function(){
19199 this.loading.disable();
19204 onClick : function(which){
19211 ds.load({params:{start: 0, limit: this.pageSize}});
19214 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19217 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19220 var total = ds.getTotalCount();
19221 var extra = total % this.pageSize;
19222 var lastStart = extra ? (total - extra) : total-this.pageSize;
19223 ds.load({params:{start: lastStart, limit: this.pageSize}});
19226 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19232 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19233 * @param {Roo.data.Store} store The data store to unbind
19235 unbind : function(ds){
19236 ds.un("beforeload", this.beforeLoad, this);
19237 ds.un("load", this.onLoad, this);
19238 ds.un("loadexception", this.onLoadError, this);
19239 ds.un("remove", this.updateInfo, this);
19240 ds.un("add", this.updateInfo, this);
19241 this.ds = undefined;
19245 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19246 * @param {Roo.data.Store} store The data store to bind
19248 bind : function(ds){
19249 ds.on("beforeload", this.beforeLoad, this);
19250 ds.on("load", this.onLoad, this);
19251 ds.on("loadexception", this.onLoadError, this);
19252 ds.on("remove", this.updateInfo, this);
19253 ds.on("add", this.updateInfo, this);
19264 * @class Roo.bootstrap.MessageBar
19265 * @extends Roo.bootstrap.Component
19266 * Bootstrap MessageBar class
19267 * @cfg {String} html contents of the MessageBar
19268 * @cfg {String} weight (info | success | warning | danger) default info
19269 * @cfg {String} beforeClass insert the bar before the given class
19270 * @cfg {Boolean} closable (true | false) default false
19271 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19274 * Create a new Element
19275 * @param {Object} config The config object
19278 Roo.bootstrap.MessageBar = function(config){
19279 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19282 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19288 beforeClass: 'bootstrap-sticky-wrap',
19290 getAutoCreate : function(){
19294 cls: 'alert alert-dismissable alert-' + this.weight,
19299 html: this.html || ''
19305 cfg.cls += ' alert-messages-fixed';
19319 onRender : function(ct, position)
19321 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19324 var cfg = Roo.apply({}, this.getAutoCreate());
19328 cfg.cls += ' ' + this.cls;
19331 cfg.style = this.style;
19333 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19335 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19338 this.el.select('>button.close').on('click', this.hide, this);
19344 if (!this.rendered) {
19350 this.fireEvent('show', this);
19356 if (!this.rendered) {
19362 this.fireEvent('hide', this);
19365 update : function()
19367 // var e = this.el.dom.firstChild;
19369 // if(this.closable){
19370 // e = e.nextSibling;
19373 // e.data = this.html || '';
19375 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19391 * @class Roo.bootstrap.Graph
19392 * @extends Roo.bootstrap.Component
19393 * Bootstrap Graph class
19397 @cfg {String} graphtype bar | vbar | pie
19398 @cfg {number} g_x coodinator | centre x (pie)
19399 @cfg {number} g_y coodinator | centre y (pie)
19400 @cfg {number} g_r radius (pie)
19401 @cfg {number} g_height height of the chart (respected by all elements in the set)
19402 @cfg {number} g_width width of the chart (respected by all elements in the set)
19403 @cfg {Object} title The title of the chart
19406 -opts (object) options for the chart
19408 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19409 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19411 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.
19412 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19414 o stretch (boolean)
19416 -opts (object) options for the pie
19419 o startAngle (number)
19420 o endAngle (number)
19424 * Create a new Input
19425 * @param {Object} config The config object
19428 Roo.bootstrap.Graph = function(config){
19429 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19435 * The img click event for the img.
19436 * @param {Roo.EventObject} e
19442 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19453 //g_colors: this.colors,
19460 getAutoCreate : function(){
19471 onRender : function(ct,position){
19472 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19473 this.raphael = Raphael(this.el.dom);
19475 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19476 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19477 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19478 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19480 r.text(160, 10, "Single Series Chart").attr(txtattr);
19481 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19482 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19483 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19485 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19486 r.barchart(330, 10, 300, 220, data1);
19487 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19488 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19491 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19492 // r.barchart(30, 30, 560, 250, xdata, {
19493 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19494 // axis : "0 0 1 1",
19495 // axisxlabels : xdata
19496 // //yvalues : cols,
19499 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19501 // this.load(null,xdata,{
19502 // axis : "0 0 1 1",
19503 // axisxlabels : xdata
19508 load : function(graphtype,xdata,opts){
19509 this.raphael.clear();
19511 graphtype = this.graphtype;
19516 var r = this.raphael,
19517 fin = function () {
19518 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19520 fout = function () {
19521 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19523 pfin = function() {
19524 this.sector.stop();
19525 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19528 this.label[0].stop();
19529 this.label[0].attr({ r: 7.5 });
19530 this.label[1].attr({ "font-weight": 800 });
19533 pfout = function() {
19534 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19537 this.label[0].animate({ r: 5 }, 500, "bounce");
19538 this.label[1].attr({ "font-weight": 400 });
19544 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19547 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19550 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19551 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19553 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19560 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19565 setTitle: function(o)
19570 initEvents: function() {
19573 this.el.on('click', this.onClick, this);
19577 onClick : function(e)
19579 Roo.log('img onclick');
19580 this.fireEvent('click', this, e);
19592 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19595 * @class Roo.bootstrap.dash.NumberBox
19596 * @extends Roo.bootstrap.Component
19597 * Bootstrap NumberBox class
19598 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19599 * @cfg {String} headline Box headline
19600 * @cfg {String} content Box content
19601 * @cfg {String} icon Box icon
19602 * @cfg {String} footer Footer text
19603 * @cfg {String} fhref Footer href
19606 * Create a new NumberBox
19607 * @param {Object} config The config object
19611 Roo.bootstrap.dash.NumberBox = function(config){
19612 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19616 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19626 getAutoCreate : function(){
19630 cls : 'small-box bg-' + this.bgcolor,
19638 cls : 'roo-headline',
19639 html : this.headline
19643 cls : 'roo-content',
19644 html : this.content
19658 cls : 'ion ' + this.icon
19667 cls : 'small-box-footer',
19668 href : this.fhref || '#',
19672 cfg.cn.push(footer);
19679 onRender : function(ct,position){
19680 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19687 setHeadline: function (value)
19689 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19692 setFooter: function (value, href)
19694 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19697 this.el.select('a.small-box-footer',true).first().attr('href', href);
19702 setContent: function (value)
19704 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19707 initEvents: function()
19721 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19724 * @class Roo.bootstrap.dash.TabBox
19725 * @extends Roo.bootstrap.Component
19726 * Bootstrap TabBox class
19727 * @cfg {String} title Title of the TabBox
19728 * @cfg {String} icon Icon of the TabBox
19729 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19732 * Create a new TabBox
19733 * @param {Object} config The config object
19737 Roo.bootstrap.dash.TabBox = function(config){
19738 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19743 * When a pane is added
19744 * @param {Roo.bootstrap.dash.TabPane} pane
19751 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19757 getChildContainer : function()
19759 return this.el.select('.tab-content', true).first();
19762 getAutoCreate : function(){
19766 cls: 'pull-left header',
19774 cls: 'fa ' + this.icon
19781 cls: 'nav-tabs-custom',
19785 cls: 'nav nav-tabs pull-right',
19792 cls: 'tab-content no-padding',
19800 initEvents : function()
19802 //Roo.log('add add pane handler');
19803 this.on('addpane', this.onAddPane, this);
19806 * Updates the box title
19807 * @param {String} html to set the title to.
19809 setTitle : function(value)
19811 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19813 onAddPane : function(pane)
19815 //Roo.log('addpane');
19817 // tabs are rendere left to right..
19818 if(!this.showtabs){
19822 var ctr = this.el.select('.nav-tabs', true).first();
19825 var existing = ctr.select('.nav-tab',true);
19826 var qty = existing.getCount();;
19829 var tab = ctr.createChild({
19831 cls : 'nav-tab' + (qty ? '' : ' active'),
19839 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19842 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19844 pane.el.addClass('active');
19849 onTabClick : function(ev,un,ob,pane)
19851 //Roo.log('tab - prev default');
19852 ev.preventDefault();
19855 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19856 pane.tab.addClass('active');
19857 //Roo.log(pane.title);
19858 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19859 // technically we should have a deactivate event.. but maybe add later.
19860 // and it should not de-activate the selected tab...
19862 pane.el.addClass('active');
19863 pane.fireEvent('activate');
19878 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19880 * @class Roo.bootstrap.TabPane
19881 * @extends Roo.bootstrap.Component
19882 * Bootstrap TabPane class
19883 * @cfg {Boolean} active (false | true) Default false
19884 * @cfg {String} title title of panel
19888 * Create a new TabPane
19889 * @param {Object} config The config object
19892 Roo.bootstrap.dash.TabPane = function(config){
19893 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19899 * When a pane is activated
19900 * @param {Roo.bootstrap.dash.TabPane} pane
19907 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19912 // the tabBox that this is attached to.
19915 getAutoCreate : function()
19923 cfg.cls += ' active';
19928 initEvents : function()
19930 //Roo.log('trigger add pane handler');
19931 this.parent().fireEvent('addpane', this)
19935 * Updates the tab title
19936 * @param {String} html to set the title to.
19938 setTitle: function(str)
19944 this.tab.select('a', true).first().dom.innerHTML = str;
19961 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19964 * @class Roo.bootstrap.menu.Menu
19965 * @extends Roo.bootstrap.Component
19966 * Bootstrap Menu class - container for Menu
19967 * @cfg {String} html Text of the menu
19968 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19969 * @cfg {String} icon Font awesome icon
19970 * @cfg {String} pos Menu align to (top | bottom) default bottom
19974 * Create a new Menu
19975 * @param {Object} config The config object
19979 Roo.bootstrap.menu.Menu = function(config){
19980 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19984 * @event beforeshow
19985 * Fires before this menu is displayed
19986 * @param {Roo.bootstrap.menu.Menu} this
19990 * @event beforehide
19991 * Fires before this menu is hidden
19992 * @param {Roo.bootstrap.menu.Menu} this
19997 * Fires after this menu is displayed
19998 * @param {Roo.bootstrap.menu.Menu} this
20003 * Fires after this menu is hidden
20004 * @param {Roo.bootstrap.menu.Menu} this
20009 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20010 * @param {Roo.bootstrap.menu.Menu} this
20011 * @param {Roo.EventObject} e
20018 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20022 weight : 'default',
20027 getChildContainer : function() {
20028 if(this.isSubMenu){
20032 return this.el.select('ul.dropdown-menu', true).first();
20035 getAutoCreate : function()
20040 cls : 'roo-menu-text',
20048 cls : 'fa ' + this.icon
20059 cls : 'dropdown-button btn btn-' + this.weight,
20064 cls : 'dropdown-toggle btn btn-' + this.weight,
20074 cls : 'dropdown-menu'
20080 if(this.pos == 'top'){
20081 cfg.cls += ' dropup';
20084 if(this.isSubMenu){
20087 cls : 'dropdown-menu'
20094 onRender : function(ct, position)
20096 this.isSubMenu = ct.hasClass('dropdown-submenu');
20098 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20101 initEvents : function()
20103 if(this.isSubMenu){
20107 this.hidden = true;
20109 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20110 this.triggerEl.on('click', this.onTriggerPress, this);
20112 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20113 this.buttonEl.on('click', this.onClick, this);
20119 if(this.isSubMenu){
20123 return this.el.select('ul.dropdown-menu', true).first();
20126 onClick : function(e)
20128 this.fireEvent("click", this, e);
20131 onTriggerPress : function(e)
20133 if (this.isVisible()) {
20140 isVisible : function(){
20141 return !this.hidden;
20146 this.fireEvent("beforeshow", this);
20148 this.hidden = false;
20149 this.el.addClass('open');
20151 Roo.get(document).on("mouseup", this.onMouseUp, this);
20153 this.fireEvent("show", this);
20160 this.fireEvent("beforehide", this);
20162 this.hidden = true;
20163 this.el.removeClass('open');
20165 Roo.get(document).un("mouseup", this.onMouseUp);
20167 this.fireEvent("hide", this);
20170 onMouseUp : function()
20184 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20187 * @class Roo.bootstrap.menu.Item
20188 * @extends Roo.bootstrap.Component
20189 * Bootstrap MenuItem class
20190 * @cfg {Boolean} submenu (true | false) default false
20191 * @cfg {String} html text of the item
20192 * @cfg {String} href the link
20193 * @cfg {Boolean} disable (true | false) default false
20194 * @cfg {Boolean} preventDefault (true | false) default true
20195 * @cfg {String} icon Font awesome icon
20196 * @cfg {String} pos Submenu align to (left | right) default right
20200 * Create a new Item
20201 * @param {Object} config The config object
20205 Roo.bootstrap.menu.Item = function(config){
20206 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20210 * Fires when the mouse is hovering over this menu
20211 * @param {Roo.bootstrap.menu.Item} this
20212 * @param {Roo.EventObject} e
20217 * Fires when the mouse exits this menu
20218 * @param {Roo.bootstrap.menu.Item} this
20219 * @param {Roo.EventObject} e
20225 * The raw click event for the entire grid.
20226 * @param {Roo.EventObject} e
20232 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20237 preventDefault: true,
20242 getAutoCreate : function()
20247 cls : 'roo-menu-item-text',
20255 cls : 'fa ' + this.icon
20264 href : this.href || '#',
20271 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20275 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20277 if(this.pos == 'left'){
20278 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20285 initEvents : function()
20287 this.el.on('mouseover', this.onMouseOver, this);
20288 this.el.on('mouseout', this.onMouseOut, this);
20290 this.el.select('a', true).first().on('click', this.onClick, this);
20294 onClick : function(e)
20296 if(this.preventDefault){
20297 e.preventDefault();
20300 this.fireEvent("click", this, e);
20303 onMouseOver : function(e)
20305 if(this.submenu && this.pos == 'left'){
20306 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20309 this.fireEvent("mouseover", this, e);
20312 onMouseOut : function(e)
20314 this.fireEvent("mouseout", this, e);
20326 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20329 * @class Roo.bootstrap.menu.Separator
20330 * @extends Roo.bootstrap.Component
20331 * Bootstrap Separator class
20334 * Create a new Separator
20335 * @param {Object} config The config object
20339 Roo.bootstrap.menu.Separator = function(config){
20340 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20343 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20345 getAutoCreate : function(){