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;
214 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
215 // and are not displayed -this causes this to use up the wrong element when matching.
216 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
219 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
220 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
226 //echild.dom.removeAttribute('xtype');
228 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 Roo.log(self_cntr_el);
237 // if object has flexy:if - then it may or may not be rendered.
238 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
239 // skip a flexy if element.
240 Roo.log('skipping render');
243 Roo.log('skipping all children');
244 skip_children = true;
249 // actually if flexy:foreach is found, we really want to create
250 // multiple copies here...
252 //Roo.log(this[cntr]());
253 cn.render(this[cntr](true));
255 // then add the element..
263 if (typeof (tree.menu) != 'undefined') {
264 tree.menu.parentType = cn.xtype;
265 tree.menu.triggerEl = cn.el;
266 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
270 if (!tree.items || !tree.items.length) {
274 var items = tree.items;
277 //Roo.log(items.length);
279 if (!skip_children) {
280 for(var i =0;i < items.length;i++) {
281 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
303 * @class Roo.bootstrap.Body
304 * @extends Roo.bootstrap.Component
305 * Bootstrap Body class
309 * @param {Object} config The config object
312 Roo.bootstrap.Body = function(config){
313 Roo.bootstrap.Body.superclass.constructor.call(this, config);
314 this.el = Roo.get(document.body);
315 if (this.cls && this.cls.length) {
316 Roo.get(document.body).addClass(this.cls);
320 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
325 onRender : function(ct, position)
327 /* Roo.log("Roo.bootstrap.Body - onRender");
328 if (this.cls && this.cls.length) {
329 Roo.get(document.body).addClass(this.cls);
349 * @class Roo.bootstrap.ButtonGroup
350 * @extends Roo.bootstrap.Component
351 * Bootstrap ButtonGroup class
352 * @cfg {String} size lg | sm | xs (default empty normal)
353 * @cfg {String} align vertical | justified (default none)
354 * @cfg {String} direction up | down (default down)
355 * @cfg {Boolean} toolbar false | true
356 * @cfg {Boolean} btn true | false
361 * @param {Object} config The config object
364 Roo.bootstrap.ButtonGroup = function(config){
365 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
368 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
376 getAutoCreate : function(){
382 cfg.html = this.html || cfg.html;
393 if (['vertical','justified'].indexOf(this.align)!==-1) {
394 cfg.cls = 'btn-group-' + this.align;
396 if (this.align == 'justified') {
397 console.log(this.items);
401 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
402 cfg.cls += ' btn-group-' + this.size;
405 if (this.direction == 'up') {
406 cfg.cls += ' dropup' ;
422 * @class Roo.bootstrap.Button
423 * @extends Roo.bootstrap.Component
424 * Bootstrap Button class
425 * @cfg {String} html The button content
426 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
427 * @cfg {String} size empty | lg | sm | xs
428 * @cfg {String} tag empty | a | input | submit
429 * @cfg {String} href empty or href
430 * @cfg {Boolean} disabled false | true
431 * @cfg {Boolean} isClose false | true
432 * @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
433 * @cfg {String} badge text for badge
434 * @cfg {String} theme default (or empty) | glow
435 * @cfg {Boolean} inverse false | true
436 * @cfg {Boolean} toggle false | true
437 * @cfg {String} ontext text for on toggle state
438 * @cfg {String} offtext text for off toggle state
439 * @cfg {Boolean} defaulton true | false
440 * @cfg {Boolean} preventDefault (true | false) default true
441 * @cfg {Boolean} removeClass true | false remove the standard class..
442 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
445 * Create a new button
446 * @param {Object} config The config object
450 Roo.bootstrap.Button = function(config){
451 Roo.bootstrap.Button.superclass.constructor.call(this, config);
456 * When a butotn is pressed
457 * @param {Roo.EventObject} e
462 * After the button has been toggles
463 * @param {Roo.EventObject} e
464 * @param {boolean} pressed (also available as button.pressed)
470 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
488 preventDefault: true,
497 getAutoCreate : function(){
505 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
506 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
511 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
513 if (this.toggle == true) {
516 cls: 'slider-frame roo-button',
521 'data-off-text':'OFF',
522 cls: 'slider-button',
528 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
529 cfg.cls += ' '+this.weight;
538 cfg["aria-hidden"] = true;
540 cfg.html = "×";
546 if (this.theme==='default') {
547 cfg.cls = 'btn roo-button';
549 //if (this.parentType != 'Navbar') {
550 this.weight = this.weight.length ? this.weight : 'default';
552 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
554 cfg.cls += ' btn-' + this.weight;
556 } else if (this.theme==='glow') {
559 cfg.cls = 'btn-glow roo-button';
561 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
563 cfg.cls += ' ' + this.weight;
569 this.cls += ' inverse';
574 cfg.cls += ' active';
578 cfg.disabled = 'disabled';
582 Roo.log('changing to ul' );
584 this.glyphicon = 'caret';
587 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
589 //gsRoo.log(this.parentType);
590 if (this.parentType === 'Navbar' && !this.parent().bar) {
591 Roo.log('changing to li?');
600 href : this.href || '#'
603 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
604 cfg.cls += ' dropdown';
611 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
613 if (this.glyphicon) {
614 cfg.html = ' ' + cfg.html;
619 cls: 'glyphicon glyphicon-' + this.glyphicon
629 // cfg.cls='btn roo-button';
633 var value = cfg.html;
638 cls: 'glyphicon glyphicon-' + this.glyphicon,
657 cfg.cls += ' dropdown';
658 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
661 if (cfg.tag !== 'a' && this.href !== '') {
662 throw "Tag must be a to set href.";
663 } else if (this.href.length > 0) {
664 cfg.href = this.href;
667 if(this.removeClass){
672 cfg.target = this.target;
677 initEvents: function() {
678 // Roo.log('init events?');
679 // Roo.log(this.el.dom);
682 if (typeof (this.menu) != 'undefined') {
683 this.menu.parentType = this.xtype;
684 this.menu.triggerEl = this.el;
685 this.addxtype(Roo.apply({}, this.menu));
689 if (this.el.hasClass('roo-button')) {
690 this.el.on('click', this.onClick, this);
692 this.el.select('.roo-button').on('click', this.onClick, this);
695 if(this.removeClass){
696 this.el.on('click', this.onClick, this);
699 this.el.enableDisplayMode();
702 onClick : function(e)
708 Roo.log('button on click ');
709 if(this.preventDefault){
712 if (this.pressed === true || this.pressed === false) {
713 this.pressed = !this.pressed;
714 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
715 this.fireEvent('toggle', this, e, this.pressed);
719 this.fireEvent('click', this, e);
723 * Enables this button
727 this.disabled = false;
728 this.el.removeClass('disabled');
732 * Disable this button
736 this.disabled = true;
737 this.el.addClass('disabled');
740 * sets the active state on/off,
741 * @param {Boolean} state (optional) Force a particular state
743 setActive : function(v) {
745 this.el[v ? 'addClass' : 'removeClass']('active');
748 * toggles the current active state
750 toggleActive : function()
752 var active = this.el.hasClass('active');
753 this.setActive(!active);
757 setText : function(str)
759 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
763 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
786 * @class Roo.bootstrap.Column
787 * @extends Roo.bootstrap.Component
788 * Bootstrap Column class
789 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
790 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
791 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
792 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
793 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
794 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
795 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
796 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
799 * @cfg {Boolean} hidden (true|false) hide the element
800 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
801 * @cfg {String} fa (ban|check|...) font awesome icon
802 * @cfg {Number} fasize (1|2|....) font awsome size
804 * @cfg {String} icon (info-sign|check|...) glyphicon name
806 * @cfg {String} html content of column.
809 * Create a new Column
810 * @param {Object} config The config object
813 Roo.bootstrap.Column = function(config){
814 Roo.bootstrap.Column.superclass.constructor.call(this, config);
817 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
835 getAutoCreate : function(){
836 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
844 ['xs','sm','md','lg'].map(function(size){
845 //Roo.log( size + ':' + settings[size]);
847 if (settings[size+'off'] !== false) {
848 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
851 if (settings[size] === false) {
854 Roo.log(settings[size]);
855 if (!settings[size]) { // 0 = hidden
856 cfg.cls += ' hidden-' + size;
859 cfg.cls += ' col-' + size + '-' + settings[size];
864 cfg.cls += ' hidden';
867 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
868 cfg.cls +=' alert alert-' + this.alert;
872 if (this.html.length) {
873 cfg.html = this.html;
877 if (this.fasize > 1) {
878 fasize = ' fa-' + this.fasize + 'x';
880 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
885 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
904 * @class Roo.bootstrap.Container
905 * @extends Roo.bootstrap.Component
906 * Bootstrap Container class
907 * @cfg {Boolean} jumbotron is it a jumbotron element
908 * @cfg {String} html content of element
909 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
910 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
911 * @cfg {String} header content of header (for panel)
912 * @cfg {String} footer content of footer (for panel)
913 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
914 * @cfg {String} tag (header|aside|section) type of HTML tag.
915 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
916 * @cfg {String} fa (ban|check|...) font awesome icon
917 * @cfg {String} icon (info-sign|check|...) glyphicon name
918 * @cfg {Boolean} hidden (true|false) hide the element
922 * Create a new Container
923 * @param {Object} config The config object
926 Roo.bootstrap.Container = function(config){
927 Roo.bootstrap.Container.superclass.constructor.call(this, config);
930 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
944 getChildContainer : function() {
950 if (this.panel.length) {
951 return this.el.select('.panel-body',true).first();
958 getAutoCreate : function(){
961 tag : this.tag || 'div',
965 if (this.jumbotron) {
966 cfg.cls = 'jumbotron';
971 // - this is applied by the parent..
973 // cfg.cls = this.cls + '';
976 if (this.sticky.length) {
978 var bd = Roo.get(document.body);
979 if (!bd.hasClass('bootstrap-sticky')) {
980 bd.addClass('bootstrap-sticky');
981 Roo.select('html',true).setStyle('height', '100%');
984 cfg.cls += 'bootstrap-sticky-' + this.sticky;
988 if (this.well.length) {
992 cfg.cls +=' well well-' +this.well;
1001 cfg.cls += ' hidden';
1005 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1006 cfg.cls +=' alert alert-' + this.alert;
1011 if (this.panel.length) {
1012 cfg.cls += ' panel panel-' + this.panel;
1014 if (this.header.length) {
1017 cls : 'panel-heading',
1020 cls : 'panel-title',
1033 if (this.footer.length) {
1035 cls : 'panel-footer',
1044 body.html = this.html || cfg.html;
1045 // prefix with the icons..
1047 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1050 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1055 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1056 cfg.cls = 'container';
1062 titleEl : function()
1064 if(!this.el || !this.panel.length || !this.header.length){
1068 return this.el.select('.panel-title',true).first();
1071 setTitle : function(v)
1073 var titleEl = this.titleEl();
1079 titleEl.dom.innerHTML = v;
1082 getTitle : function()
1085 var titleEl = this.titleEl();
1091 return titleEl.dom.innerHTML;
1105 * @class Roo.bootstrap.Img
1106 * @extends Roo.bootstrap.Component
1107 * Bootstrap Img class
1108 * @cfg {Boolean} imgResponsive false | true
1109 * @cfg {String} border rounded | circle | thumbnail
1110 * @cfg {String} src image source
1111 * @cfg {String} alt image alternative text
1112 * @cfg {String} href a tag href
1113 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1116 * Create a new Input
1117 * @param {Object} config The config object
1120 Roo.bootstrap.Img = function(config){
1121 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1127 * The img click event for the img.
1128 * @param {Roo.EventObject} e
1134 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1136 imgResponsive: true,
1142 getAutoCreate : function(){
1146 cls: (this.imgResponsive) ? 'img-responsive' : '',
1150 cfg.html = this.html || cfg.html;
1152 cfg.src = this.src || cfg.src;
1154 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1155 cfg.cls += ' img-' + this.border;
1172 a.target = this.target;
1178 return (this.href) ? a : cfg;
1181 initEvents: function() {
1184 this.el.on('click', this.onClick, this);
1188 onClick : function(e)
1190 Roo.log('img onclick');
1191 this.fireEvent('click', this, e);
1205 * @class Roo.bootstrap.Link
1206 * @extends Roo.bootstrap.Component
1207 * Bootstrap Link Class
1208 * @cfg {String} alt image alternative text
1209 * @cfg {String} href a tag href
1210 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1211 * @cfg {String} html the content of the link.
1212 * @cfg {String} anchor name for the anchor link
1214 * @cfg {Boolean} preventDefault (true | false) default false
1218 * Create a new Input
1219 * @param {Object} config The config object
1222 Roo.bootstrap.Link = function(config){
1223 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1229 * The img click event for the img.
1230 * @param {Roo.EventObject} e
1236 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1240 preventDefault: false,
1244 getAutoCreate : function()
1250 // anchor's do not require html/href...
1251 if (this.anchor === false) {
1252 cfg.html = this.html || 'html-missing';
1253 cfg.href = this.href || '#';
1255 cfg.name = this.anchor;
1256 if (this.html !== false) {
1257 cfg.html = this.html;
1259 if (this.href !== false) {
1260 cfg.href = this.href;
1264 if(this.alt !== false){
1269 if(this.target !== false) {
1270 cfg.target = this.target;
1276 initEvents: function() {
1278 if(!this.href || this.preventDefault){
1279 this.el.on('click', this.onClick, this);
1283 onClick : function(e)
1285 if(this.preventDefault){
1288 //Roo.log('img onclick');
1289 this.fireEvent('click', this, e);
1302 * @class Roo.bootstrap.Header
1303 * @extends Roo.bootstrap.Component
1304 * Bootstrap Header class
1305 * @cfg {String} html content of header
1306 * @cfg {Number} level (1|2|3|4|5|6) default 1
1309 * Create a new Header
1310 * @param {Object} config The config object
1314 Roo.bootstrap.Header = function(config){
1315 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1318 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1326 getAutoCreate : function(){
1329 tag: 'h' + (1 *this.level),
1330 html: this.html || 'fill in html'
1342 * Ext JS Library 1.1.1
1343 * Copyright(c) 2006-2007, Ext JS, LLC.
1345 * Originally Released Under LGPL - original licence link has changed is not relivant.
1348 * <script type="text/javascript">
1352 * @class Roo.bootstrap.MenuMgr
1353 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1356 Roo.bootstrap.MenuMgr = function(){
1357 var menus, active, groups = {}, attached = false, lastShow = new Date();
1359 // private - called when first menu is created
1362 active = new Roo.util.MixedCollection();
1363 Roo.get(document).addKeyListener(27, function(){
1364 if(active.length > 0){
1372 if(active && active.length > 0){
1373 var c = active.clone();
1383 if(active.length < 1){
1384 Roo.get(document).un("mouseup", onMouseDown);
1392 var last = active.last();
1393 lastShow = new Date();
1396 Roo.get(document).on("mouseup", onMouseDown);
1401 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1402 m.parentMenu.activeChild = m;
1403 }else if(last && last.isVisible()){
1404 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1409 function onBeforeHide(m){
1411 m.activeChild.hide();
1413 if(m.autoHideTimer){
1414 clearTimeout(m.autoHideTimer);
1415 delete m.autoHideTimer;
1420 function onBeforeShow(m){
1421 var pm = m.parentMenu;
1422 if(!pm && !m.allowOtherMenus){
1424 }else if(pm && pm.activeChild && active != m){
1425 pm.activeChild.hide();
1430 function onMouseDown(e){
1431 Roo.log("on MouseDown");
1432 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1440 function onBeforeCheck(mi, state){
1442 var g = groups[mi.group];
1443 for(var i = 0, l = g.length; i < l; i++){
1445 g[i].setChecked(false);
1454 * Hides all menus that are currently visible
1456 hideAll : function(){
1461 register : function(menu){
1465 menus[menu.id] = menu;
1466 menu.on("beforehide", onBeforeHide);
1467 menu.on("hide", onHide);
1468 menu.on("beforeshow", onBeforeShow);
1469 menu.on("show", onShow);
1471 if(g && menu.events["checkchange"]){
1475 groups[g].push(menu);
1476 menu.on("checkchange", onCheck);
1481 * Returns a {@link Roo.menu.Menu} object
1482 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1483 * be used to generate and return a new Menu instance.
1485 get : function(menu){
1486 if(typeof menu == "string"){ // menu id
1488 }else if(menu.events){ // menu instance
1491 /*else if(typeof menu.length == 'number'){ // array of menu items?
1492 return new Roo.bootstrap.Menu({items:menu});
1493 }else{ // otherwise, must be a config
1494 return new Roo.bootstrap.Menu(menu);
1501 unregister : function(menu){
1502 delete menus[menu.id];
1503 menu.un("beforehide", onBeforeHide);
1504 menu.un("hide", onHide);
1505 menu.un("beforeshow", onBeforeShow);
1506 menu.un("show", onShow);
1508 if(g && menu.events["checkchange"]){
1509 groups[g].remove(menu);
1510 menu.un("checkchange", onCheck);
1515 registerCheckable : function(menuItem){
1516 var g = menuItem.group;
1521 groups[g].push(menuItem);
1522 menuItem.on("beforecheckchange", onBeforeCheck);
1527 unregisterCheckable : function(menuItem){
1528 var g = menuItem.group;
1530 groups[g].remove(menuItem);
1531 menuItem.un("beforecheckchange", onBeforeCheck);
1543 * @class Roo.bootstrap.Menu
1544 * @extends Roo.bootstrap.Component
1545 * Bootstrap Menu class - container for MenuItems
1546 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1550 * @param {Object} config The config object
1554 Roo.bootstrap.Menu = function(config){
1555 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1556 if (this.registerMenu) {
1557 Roo.bootstrap.MenuMgr.register(this);
1562 * Fires before this menu is displayed
1563 * @param {Roo.menu.Menu} this
1568 * Fires before this menu is hidden
1569 * @param {Roo.menu.Menu} this
1574 * Fires after this menu is displayed
1575 * @param {Roo.menu.Menu} this
1580 * Fires after this menu is hidden
1581 * @param {Roo.menu.Menu} this
1586 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1587 * @param {Roo.menu.Menu} this
1588 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1589 * @param {Roo.EventObject} e
1594 * Fires when the mouse is hovering over 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 the mouse exits this menu
1603 * @param {Roo.menu.Menu} this
1604 * @param {Roo.EventObject} e
1605 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1610 * Fires when a menu item contained in this menu is clicked
1611 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1612 * @param {Roo.EventObject} e
1616 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1619 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1623 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1626 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1628 registerMenu : true,
1630 menuItems :false, // stores the menu items..
1636 getChildContainer : function() {
1640 getAutoCreate : function(){
1642 //if (['right'].indexOf(this.align)!==-1) {
1643 // cfg.cn[1].cls += ' pull-right'
1649 cls : 'dropdown-menu' ,
1650 style : 'z-index:1000'
1654 if (this.type === 'submenu') {
1655 cfg.cls = 'submenu active';
1657 if (this.type === 'treeview') {
1658 cfg.cls = 'treeview-menu';
1663 initEvents : function() {
1665 // Roo.log("ADD event");
1666 // Roo.log(this.triggerEl.dom);
1667 this.triggerEl.on('click', this.onTriggerPress, this);
1668 this.triggerEl.addClass('dropdown-toggle');
1669 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1671 this.el.on("mouseover", this.onMouseOver, this);
1672 this.el.on("mouseout", this.onMouseOut, this);
1676 findTargetItem : function(e){
1677 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1681 //Roo.log(t); Roo.log(t.id);
1683 //Roo.log(this.menuitems);
1684 return this.menuitems.get(t.id);
1686 //return this.items.get(t.menuItemId);
1691 onClick : function(e){
1692 Roo.log("menu.onClick");
1693 var t = this.findTargetItem(e);
1699 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1700 if(t == this.activeItem && t.shouldDeactivate(e)){
1701 this.activeItem.deactivate();
1702 delete this.activeItem;
1706 this.setActiveItem(t, true);
1713 Roo.log('pass click event');
1717 this.fireEvent("click", this, t, e);
1721 onMouseOver : function(e){
1722 var t = this.findTargetItem(e);
1725 // if(t.canActivate && !t.disabled){
1726 // this.setActiveItem(t, true);
1730 this.fireEvent("mouseover", this, e, t);
1732 isVisible : function(){
1733 return !this.hidden;
1735 onMouseOut : function(e){
1736 var t = this.findTargetItem(e);
1739 // if(t == this.activeItem && t.shouldDeactivate(e)){
1740 // this.activeItem.deactivate();
1741 // delete this.activeItem;
1744 this.fireEvent("mouseout", this, e, t);
1749 * Displays this menu relative to another element
1750 * @param {String/HTMLElement/Roo.Element} element The element to align to
1751 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1752 * the element (defaults to this.defaultAlign)
1753 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1755 show : function(el, pos, parentMenu){
1756 this.parentMenu = parentMenu;
1760 this.fireEvent("beforeshow", this);
1761 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1764 * Displays this menu at a specific xy position
1765 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1766 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1768 showAt : function(xy, parentMenu, /* private: */_e){
1769 this.parentMenu = parentMenu;
1774 this.fireEvent("beforeshow", this);
1776 //xy = this.el.adjustForConstraints(xy);
1778 //this.el.setXY(xy);
1780 this.hideMenuItems();
1781 this.hidden = false;
1782 this.triggerEl.addClass('open');
1784 this.fireEvent("show", this);
1790 this.doFocus.defer(50, this);
1794 doFocus : function(){
1796 this.focusEl.focus();
1801 * Hides this menu and optionally all parent menus
1802 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1804 hide : function(deep){
1806 this.hideMenuItems();
1807 if(this.el && this.isVisible()){
1808 this.fireEvent("beforehide", this);
1809 if(this.activeItem){
1810 this.activeItem.deactivate();
1811 this.activeItem = null;
1813 this.triggerEl.removeClass('open');;
1815 this.fireEvent("hide", this);
1817 if(deep === true && this.parentMenu){
1818 this.parentMenu.hide(true);
1822 onTriggerPress : function(e)
1825 Roo.log('trigger press');
1826 //Roo.log(e.getTarget());
1827 // Roo.log(this.triggerEl.dom);
1828 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1831 if (this.isVisible()) {
1835 this.show(this.triggerEl, false, false);
1844 hideMenuItems : function()
1846 //$(backdrop).remove()
1847 Roo.select('.open',true).each(function(aa) {
1849 aa.removeClass('open');
1850 //var parent = getParent($(this))
1851 //var relatedTarget = { relatedTarget: this }
1853 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1854 //if (e.isDefaultPrevented()) return
1855 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1858 addxtypeChild : function (tree, cntr) {
1859 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1861 this.menuitems.add(comp);
1882 * @class Roo.bootstrap.MenuItem
1883 * @extends Roo.bootstrap.Component
1884 * Bootstrap MenuItem class
1885 * @cfg {String} html the menu label
1886 * @cfg {String} href the link
1887 * @cfg {Boolean} preventDefault (true | false) default true
1891 * Create a new MenuItem
1892 * @param {Object} config The config object
1896 Roo.bootstrap.MenuItem = function(config){
1897 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1902 * The raw click event for the entire grid.
1903 * @param {Roo.EventObject} e
1909 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1913 preventDefault: true,
1915 getAutoCreate : function(){
1918 cls: 'dropdown-menu-item',
1927 if (this.parent().type == 'treeview') {
1928 cfg.cls = 'treeview-menu';
1931 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1932 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1936 initEvents: function() {
1938 //this.el.select('a').on('click', this.onClick, this);
1941 onClick : function(e)
1943 Roo.log('item on click ');
1944 //if(this.preventDefault){
1945 // e.preventDefault();
1947 //this.parent().hideMenuItems();
1949 this.fireEvent('click', this, e);
1968 * @class Roo.bootstrap.MenuSeparator
1969 * @extends Roo.bootstrap.Component
1970 * Bootstrap MenuSeparator class
1973 * Create a new MenuItem
1974 * @param {Object} config The config object
1978 Roo.bootstrap.MenuSeparator = function(config){
1979 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1982 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1984 getAutoCreate : function(){
1999 <div class="modal fade">
2000 <div class="modal-dialog">
2001 <div class="modal-content">
2002 <div class="modal-header">
2003 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2004 <h4 class="modal-title">Modal title</h4>
2006 <div class="modal-body">
2007 <p>One fine body…</p>
2009 <div class="modal-footer">
2010 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2011 <button type="button" class="btn btn-primary">Save changes</button>
2013 </div><!-- /.modal-content -->
2014 </div><!-- /.modal-dialog -->
2015 </div><!-- /.modal -->
2025 * @class Roo.bootstrap.Modal
2026 * @extends Roo.bootstrap.Component
2027 * Bootstrap Modal class
2028 * @cfg {String} title Title of dialog
2029 * @cfg {Boolean} specificTitle (true|false) default false
2030 * @cfg {Array} buttons Array of buttons or standard button set..
2031 * @cfg {String} buttonPosition (left|right|center) default right
2034 * Create a new Modal Dialog
2035 * @param {Object} config The config object
2038 Roo.bootstrap.Modal = function(config){
2039 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2044 * The raw btnclick event for the button
2045 * @param {Roo.EventObject} e
2049 this.buttons = this.buttons || [];
2052 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2054 title : 'test dialog',
2061 specificTitle: false,
2063 buttonPosition: 'right',
2065 onRender : function(ct, position)
2067 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2070 var cfg = Roo.apply({}, this.getAutoCreate());
2073 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2075 //if (!cfg.name.length) {
2079 cfg.cls += ' ' + this.cls;
2082 cfg.style = this.style;
2084 this.el = Roo.get(document.body).createChild(cfg, position);
2086 //var type = this.el.dom.type;
2088 if(this.tabIndex !== undefined){
2089 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2094 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2095 this.maskEl.enableDisplayMode("block");
2097 //this.el.addClass("x-dlg-modal");
2099 if (this.buttons.length) {
2100 Roo.each(this.buttons, function(bb) {
2101 b = Roo.apply({}, bb);
2102 b.xns = b.xns || Roo.bootstrap;
2103 b.xtype = b.xtype || 'Button';
2104 if (typeof(b.listeners) == 'undefined') {
2105 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2108 var btn = Roo.factory(b);
2110 btn.onRender(this.el.select('.modal-footer div').first());
2114 // render the children.
2117 if(typeof(this.items) != 'undefined'){
2118 var items = this.items;
2121 for(var i =0;i < items.length;i++) {
2122 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2126 this.items = nitems;
2128 this.body = this.el.select('.modal-body',true).first();
2129 this.close = this.el.select('.modal-header .close', true).first();
2130 this.footer = this.el.select('.modal-footer',true).first();
2132 //this.el.addClass([this.fieldClass, this.cls]);
2135 getAutoCreate : function(){
2140 html : this.html || ''
2145 cls : 'modal-title',
2149 if(this.specificTitle){
2155 style : 'display: none',
2158 cls: "modal-dialog",
2161 cls : "modal-content",
2164 cls : 'modal-header',
2176 cls : 'modal-footer',
2180 cls: 'btn-' + this.buttonPosition
2199 getChildContainer : function() {
2201 return this.el.select('.modal-body',true).first();
2204 getButtonContainer : function() {
2205 return this.el.select('.modal-footer div',true).first();
2208 initEvents : function()
2210 this.el.select('.modal-header .close').on('click', this.hide, this);
2212 // this.addxtype(this);
2216 if (!this.rendered) {
2220 this.el.addClass('on');
2221 this.el.removeClass('fade');
2222 this.el.setStyle('display', 'block');
2223 Roo.get(document.body).addClass("x-body-masked");
2224 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2226 this.el.setStyle('zIndex', '10001');
2227 this.fireEvent('show', this);
2233 Roo.log('Modal hide?!');
2235 Roo.get(document.body).removeClass("x-body-masked");
2236 this.el.removeClass('on');
2237 this.el.addClass('fade');
2238 this.el.setStyle('display', 'none');
2239 this.fireEvent('hide', this);
2242 addButton : function(str, cb)
2246 var b = Roo.apply({}, { html : str } );
2247 b.xns = b.xns || Roo.bootstrap;
2248 b.xtype = b.xtype || 'Button';
2249 if (typeof(b.listeners) == 'undefined') {
2250 b.listeners = { click : cb.createDelegate(this) };
2253 var btn = Roo.factory(b);
2255 btn.onRender(this.el.select('.modal-footer div').first());
2261 setDefaultButton : function(btn)
2263 //this.el.select('.modal-footer').()
2265 resizeTo: function(w,h)
2269 setContentSize : function(w, h)
2273 onButtonClick: function(btn,e)
2276 this.fireEvent('btnclick', btn.name, e);
2278 setTitle: function(str) {
2279 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2285 Roo.apply(Roo.bootstrap.Modal, {
2287 * Button config that displays a single OK button
2296 * Button config that displays Yes and No buttons
2312 * Button config that displays OK and Cancel buttons
2327 * Button config that displays Yes, No and Cancel buttons
2349 * messagebox - can be used as a replace
2353 * @class Roo.MessageBox
2354 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2358 Roo.Msg.alert('Status', 'Changes saved successfully.');
2360 // Prompt for user data:
2361 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2363 // process text value...
2367 // Show a dialog using config options:
2369 title:'Save Changes?',
2370 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2371 buttons: Roo.Msg.YESNOCANCEL,
2378 Roo.bootstrap.MessageBox = function(){
2379 var dlg, opt, mask, waitTimer;
2380 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2381 var buttons, activeTextEl, bwidth;
2385 var handleButton = function(button){
2387 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2391 var handleHide = function(){
2393 dlg.el.removeClass(opt.cls);
2396 // Roo.TaskMgr.stop(waitTimer);
2397 // waitTimer = null;
2402 var updateButtons = function(b){
2405 buttons["ok"].hide();
2406 buttons["cancel"].hide();
2407 buttons["yes"].hide();
2408 buttons["no"].hide();
2409 //dlg.footer.dom.style.display = 'none';
2412 dlg.footer.dom.style.display = '';
2413 for(var k in buttons){
2414 if(typeof buttons[k] != "function"){
2417 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2418 width += buttons[k].el.getWidth()+15;
2428 var handleEsc = function(d, k, e){
2429 if(opt && opt.closable !== false){
2439 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2440 * @return {Roo.BasicDialog} The BasicDialog element
2442 getDialog : function(){
2444 dlg = new Roo.bootstrap.Modal( {
2447 //constraintoviewport:false,
2449 //collapsible : false,
2454 //buttonAlign:"center",
2455 closeClick : function(){
2456 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2459 handleButton("cancel");
2464 dlg.on("hide", handleHide);
2466 //dlg.addKeyListener(27, handleEsc);
2468 this.buttons = buttons;
2469 var bt = this.buttonText;
2470 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2471 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2472 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2473 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2475 bodyEl = dlg.body.createChild({
2477 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2478 '<textarea class="roo-mb-textarea"></textarea>' +
2479 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2481 msgEl = bodyEl.dom.firstChild;
2482 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2483 textboxEl.enableDisplayMode();
2484 textboxEl.addKeyListener([10,13], function(){
2485 if(dlg.isVisible() && opt && opt.buttons){
2488 }else if(opt.buttons.yes){
2489 handleButton("yes");
2493 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2494 textareaEl.enableDisplayMode();
2495 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2496 progressEl.enableDisplayMode();
2497 var pf = progressEl.dom.firstChild;
2499 pp = Roo.get(pf.firstChild);
2500 pp.setHeight(pf.offsetHeight);
2508 * Updates the message box body text
2509 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2510 * the XHTML-compliant non-breaking space character '&#160;')
2511 * @return {Roo.MessageBox} This message box
2513 updateText : function(text){
2514 if(!dlg.isVisible() && !opt.width){
2515 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2517 msgEl.innerHTML = text || ' ';
2519 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2520 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2522 Math.min(opt.width || cw , this.maxWidth),
2523 Math.max(opt.minWidth || this.minWidth, bwidth)
2526 activeTextEl.setWidth(w);
2528 if(dlg.isVisible()){
2529 dlg.fixedcenter = false;
2531 // to big, make it scroll. = But as usual stupid IE does not support
2534 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2535 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2536 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2538 bodyEl.dom.style.height = '';
2539 bodyEl.dom.style.overflowY = '';
2542 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2544 bodyEl.dom.style.overflowX = '';
2547 dlg.setContentSize(w, bodyEl.getHeight());
2548 if(dlg.isVisible()){
2549 dlg.fixedcenter = true;
2555 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2556 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2557 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2558 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2559 * @return {Roo.MessageBox} This message box
2561 updateProgress : function(value, text){
2563 this.updateText(text);
2565 if (pp) { // weird bug on my firefox - for some reason this is not defined
2566 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2572 * Returns true if the message box is currently displayed
2573 * @return {Boolean} True if the message box is visible, else false
2575 isVisible : function(){
2576 return dlg && dlg.isVisible();
2580 * Hides the message box if it is displayed
2583 if(this.isVisible()){
2589 * Displays a new message box, or reinitializes an existing message box, based on the config options
2590 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2591 * The following config object properties are supported:
2593 Property Type Description
2594 ---------- --------------- ------------------------------------------------------------------------------------
2595 animEl String/Element An id or Element from which the message box should animate as it opens and
2596 closes (defaults to undefined)
2597 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2598 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2599 closable Boolean False to hide the top-right close button (defaults to true). Note that
2600 progress and wait dialogs will ignore this property and always hide the
2601 close button as they can only be closed programmatically.
2602 cls String A custom CSS class to apply to the message box element
2603 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2604 displayed (defaults to 75)
2605 fn Function A callback function to execute after closing the dialog. The arguments to the
2606 function will be btn (the name of the button that was clicked, if applicable,
2607 e.g. "ok"), and text (the value of the active text field, if applicable).
2608 Progress and wait dialogs will ignore this option since they do not respond to
2609 user actions and can only be closed programmatically, so any required function
2610 should be called by the same code after it closes the dialog.
2611 icon String A CSS class that provides a background image to be used as an icon for
2612 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2613 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2614 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2615 modal Boolean False to allow user interaction with the page while the message box is
2616 displayed (defaults to true)
2617 msg String A string that will replace the existing message box body text (defaults
2618 to the XHTML-compliant non-breaking space character ' ')
2619 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2620 progress Boolean True to display a progress bar (defaults to false)
2621 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2622 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2623 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2624 title String The title text
2625 value String The string value to set into the active textbox element if displayed
2626 wait Boolean True to display a progress bar (defaults to false)
2627 width Number The width of the dialog in pixels
2634 msg: 'Please enter your address:',
2636 buttons: Roo.MessageBox.OKCANCEL,
2639 animEl: 'addAddressBtn'
2642 * @param {Object} config Configuration options
2643 * @return {Roo.MessageBox} This message box
2645 show : function(options)
2648 // this causes nightmares if you show one dialog after another
2649 // especially on callbacks..
2651 if(this.isVisible()){
2654 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2655 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2656 Roo.log("New Dialog Message:" + options.msg )
2657 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2658 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2661 var d = this.getDialog();
2663 d.setTitle(opt.title || " ");
2664 d.close.setDisplayed(opt.closable !== false);
2665 activeTextEl = textboxEl;
2666 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2671 textareaEl.setHeight(typeof opt.multiline == "number" ?
2672 opt.multiline : this.defaultTextHeight);
2673 activeTextEl = textareaEl;
2682 progressEl.setDisplayed(opt.progress === true);
2683 this.updateProgress(0);
2684 activeTextEl.dom.value = opt.value || "";
2686 dlg.setDefaultButton(activeTextEl);
2688 var bs = opt.buttons;
2692 }else if(bs && bs.yes){
2693 db = buttons["yes"];
2695 dlg.setDefaultButton(db);
2697 bwidth = updateButtons(opt.buttons);
2698 this.updateText(opt.msg);
2700 d.el.addClass(opt.cls);
2702 d.proxyDrag = opt.proxyDrag === true;
2703 d.modal = opt.modal !== false;
2704 d.mask = opt.modal !== false ? mask : false;
2706 // force it to the end of the z-index stack so it gets a cursor in FF
2707 document.body.appendChild(dlg.el.dom);
2708 d.animateTarget = null;
2709 d.show(options.animEl);
2715 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2716 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2717 * and closing the message box when the process is complete.
2718 * @param {String} title The title bar text
2719 * @param {String} msg The message box body text
2720 * @return {Roo.MessageBox} This message box
2722 progress : function(title, msg){
2729 minWidth: this.minProgressWidth,
2736 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2737 * If a callback function is passed it will be called after the user clicks the button, and the
2738 * id of the button that was clicked will be passed as the only parameter to the callback
2739 * (could also be the top-right close button).
2740 * @param {String} title The title bar text
2741 * @param {String} msg The message box body text
2742 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2743 * @param {Object} scope (optional) The scope of the callback function
2744 * @return {Roo.MessageBox} This message box
2746 alert : function(title, msg, fn, scope){
2759 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2760 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2761 * You are responsible for closing the message box when the process is complete.
2762 * @param {String} msg The message box body text
2763 * @param {String} title (optional) The title bar text
2764 * @return {Roo.MessageBox} This message box
2766 wait : function(msg, title){
2777 waitTimer = Roo.TaskMgr.start({
2779 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2787 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2788 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2789 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2790 * @param {String} title The title bar text
2791 * @param {String} msg The message box body text
2792 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2793 * @param {Object} scope (optional) The scope of the callback function
2794 * @return {Roo.MessageBox} This message box
2796 confirm : function(title, msg, fn, scope){
2800 buttons: this.YESNO,
2809 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2810 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2811 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2812 * (could also be the top-right close button) and the text that was entered will be passed as the two
2813 * parameters to the callback.
2814 * @param {String} title The title bar text
2815 * @param {String} msg The message box body text
2816 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2817 * @param {Object} scope (optional) The scope of the callback function
2818 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2819 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2820 * @return {Roo.MessageBox} This message box
2822 prompt : function(title, msg, fn, scope, multiline){
2826 buttons: this.OKCANCEL,
2831 multiline: multiline,
2838 * Button config that displays a single OK button
2843 * Button config that displays Yes and No buttons
2846 YESNO : {yes:true, no:true},
2848 * Button config that displays OK and Cancel buttons
2851 OKCANCEL : {ok:true, cancel:true},
2853 * Button config that displays Yes, No and Cancel buttons
2856 YESNOCANCEL : {yes:true, no:true, cancel:true},
2859 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2862 defaultTextHeight : 75,
2864 * The maximum width in pixels of the message box (defaults to 600)
2869 * The minimum width in pixels of the message box (defaults to 100)
2874 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2875 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2878 minProgressWidth : 250,
2880 * An object containing the default button text strings that can be overriden for localized language support.
2881 * Supported properties are: ok, cancel, yes and no.
2882 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2895 * Shorthand for {@link Roo.MessageBox}
2897 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2898 Roo.Msg = Roo.Msg || Roo.MessageBox;
2907 * @class Roo.bootstrap.Navbar
2908 * @extends Roo.bootstrap.Component
2909 * Bootstrap Navbar class
2912 * Create a new Navbar
2913 * @param {Object} config The config object
2917 Roo.bootstrap.Navbar = function(config){
2918 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2922 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2931 getAutoCreate : function(){
2934 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2938 initEvents :function ()
2940 //Roo.log(this.el.select('.navbar-toggle',true));
2941 this.el.select('.navbar-toggle',true).on('click', function() {
2942 // Roo.log('click');
2943 this.el.select('.navbar-collapse',true).toggleClass('in');
2951 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2953 var size = this.el.getSize();
2954 this.maskEl.setSize(size.width, size.height);
2955 this.maskEl.enableDisplayMode("block");
2964 getChildContainer : function()
2966 if (this.el.select('.collapse').getCount()) {
2967 return this.el.select('.collapse',true).first();
3000 * @class Roo.bootstrap.NavSimplebar
3001 * @extends Roo.bootstrap.Navbar
3002 * Bootstrap Sidebar class
3004 * @cfg {Boolean} inverse is inverted color
3006 * @cfg {String} type (nav | pills | tabs)
3007 * @cfg {Boolean} arrangement stacked | justified
3008 * @cfg {String} align (left | right) alignment
3010 * @cfg {Boolean} main (true|false) main nav bar? default false
3011 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3013 * @cfg {String} tag (header|footer|nav|div) default is nav
3019 * Create a new Sidebar
3020 * @param {Object} config The config object
3024 Roo.bootstrap.NavSimplebar = function(config){
3025 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3028 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3044 getAutoCreate : function(){
3048 tag : this.tag || 'div',
3061 this.type = this.type || 'nav';
3062 if (['tabs','pills'].indexOf(this.type)!==-1) {
3063 cfg.cn[0].cls += ' nav-' + this.type
3067 if (this.type!=='nav') {
3068 Roo.log('nav type must be nav/tabs/pills')
3070 cfg.cn[0].cls += ' navbar-nav'
3076 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3077 cfg.cn[0].cls += ' nav-' + this.arrangement;
3081 if (this.align === 'right') {
3082 cfg.cn[0].cls += ' navbar-right';
3086 cfg.cls += ' navbar-inverse';
3113 * @class Roo.bootstrap.NavHeaderbar
3114 * @extends Roo.bootstrap.NavSimplebar
3115 * Bootstrap Sidebar class
3117 * @cfg {String} brand what is brand
3118 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3119 * @cfg {String} brand_href href of the brand
3120 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3121 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3124 * Create a new Sidebar
3125 * @param {Object} config The config object
3129 Roo.bootstrap.NavHeaderbar = function(config){
3130 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3133 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3141 getAutoCreate : function(){
3144 tag: this.nav || 'nav',
3153 cls: 'navbar-header',
3158 cls: 'navbar-toggle',
3159 'data-toggle': 'collapse',
3164 html: 'Toggle navigation'
3186 cls: 'collapse navbar-collapse',
3190 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3192 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3193 cfg.cls += ' navbar-' + this.position;
3195 // tag can override this..
3197 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3200 if (this.brand !== '') {
3203 href: this.brand_href ? this.brand_href : '#',
3204 cls: 'navbar-brand',
3212 cfg.cls += ' main-nav';
3220 initEvents : function()
3222 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3224 if (this.autohide) {
3229 Roo.get(document).on('scroll',function(e) {
3230 var ns = Roo.get(document).getScroll().top;
3231 var os = prevScroll;
3235 ft.removeClass('slideDown');
3236 ft.addClass('slideUp');
3239 ft.removeClass('slideUp');
3240 ft.addClass('slideDown');
3264 * @class Roo.bootstrap.NavSidebar
3265 * @extends Roo.bootstrap.Navbar
3266 * Bootstrap Sidebar class
3269 * Create a new Sidebar
3270 * @param {Object} config The config object
3274 Roo.bootstrap.NavSidebar = function(config){
3275 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3278 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3280 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3282 getAutoCreate : function(){
3287 cls: 'sidebar sidebar-nav'
3309 * @class Roo.bootstrap.NavGroup
3310 * @extends Roo.bootstrap.Component
3311 * Bootstrap NavGroup class
3312 * @cfg {String} align left | right
3313 * @cfg {Boolean} inverse false | true
3314 * @cfg {String} type (nav|pills|tab) default nav
3315 * @cfg {String} navId - reference Id for navbar.
3319 * Create a new nav group
3320 * @param {Object} config The config object
3323 Roo.bootstrap.NavGroup = function(config){
3324 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3327 Roo.bootstrap.NavGroup.register(this);
3331 * Fires when the active item changes
3332 * @param {Roo.bootstrap.NavGroup} this
3333 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3334 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3341 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3352 getAutoCreate : function()
3354 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3361 if (['tabs','pills'].indexOf(this.type)!==-1) {
3362 cfg.cls += ' nav-' + this.type
3364 if (this.type!=='nav') {
3365 Roo.log('nav type must be nav/tabs/pills')
3367 cfg.cls += ' navbar-nav'
3370 if (this.parent().sidebar) {
3373 cls: 'dashboard-menu sidebar-menu'
3379 if (this.form === true) {
3385 if (this.align === 'right') {
3386 cfg.cls += ' navbar-right';
3388 cfg.cls += ' navbar-left';
3392 if (this.align === 'right') {
3393 cfg.cls += ' navbar-right';
3397 cfg.cls += ' navbar-inverse';
3405 * sets the active Navigation item
3406 * @param {Roo.bootstrap.NavItem} the new current navitem
3408 setActiveItem : function(item)
3411 Roo.each(this.navItems, function(v){
3416 v.setActive(false, true);
3423 item.setActive(true, true);
3424 this.fireEvent('changed', this, item, prev);
3429 * gets the active Navigation item
3430 * @return {Roo.bootstrap.NavItem} the current navitem
3432 getActive : function()
3436 Roo.each(this.navItems, function(v){
3447 indexOfNav : function()
3451 Roo.each(this.navItems, function(v,i){
3462 * adds a Navigation item
3463 * @param {Roo.bootstrap.NavItem} the navitem to add
3465 addItem : function(cfg)
3467 var cn = new Roo.bootstrap.NavItem(cfg);
3469 cn.parentId = this.id;
3470 cn.onRender(this.el, null);
3474 * register a Navigation item
3475 * @param {Roo.bootstrap.NavItem} the navitem to add
3477 register : function(item)
3479 this.navItems.push( item);
3480 item.navId = this.navId;
3485 getNavItem: function(tabId)
3488 Roo.each(this.navItems, function(e) {
3489 if (e.tabId == tabId) {
3499 setActiveNext : function()
3501 var i = this.indexOfNav(this.getActive());
3502 if (i > this.navItems.length) {
3505 this.setActiveItem(this.navItems[i+1]);
3507 setActivePrev : function()
3509 var i = this.indexOfNav(this.getActive());
3513 this.setActiveItem(this.navItems[i-1]);
3515 clearWasActive : function(except) {
3516 Roo.each(this.navItems, function(e) {
3517 if (e.tabId != except.tabId && e.was_active) {
3518 e.was_active = false;
3525 getWasActive : function ()
3528 Roo.each(this.navItems, function(e) {
3543 Roo.apply(Roo.bootstrap.NavGroup, {
3547 * register a Navigation Group
3548 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3550 register : function(navgrp)
3552 this.groups[navgrp.navId] = navgrp;
3556 * fetch a Navigation Group based on the navigation ID
3557 * @param {string} the navgroup to add
3558 * @returns {Roo.bootstrap.NavGroup} the navgroup
3560 get: function(navId) {
3561 if (typeof(this.groups[navId]) == 'undefined') {
3563 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3565 return this.groups[navId] ;
3580 * @class Roo.bootstrap.NavItem
3581 * @extends Roo.bootstrap.Component
3582 * Bootstrap Navbar.NavItem class
3583 * @cfg {String} href link to
3584 * @cfg {String} html content of button
3585 * @cfg {String} badge text inside badge
3586 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3587 * @cfg {String} glyphicon name of glyphicon
3588 * @cfg {String} icon name of font awesome icon
3589 * @cfg {Boolean} active Is item active
3590 * @cfg {Boolean} disabled Is item disabled
3592 * @cfg {Boolean} preventDefault (true | false) default false
3593 * @cfg {String} tabId the tab that this item activates.
3594 * @cfg {String} tagtype (a|span) render as a href or span?
3597 * Create a new Navbar Item
3598 * @param {Object} config The config object
3600 Roo.bootstrap.NavItem = function(config){
3601 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3606 * The raw click event for the entire grid.
3607 * @param {Roo.EventObject} e
3612 * Fires when the active item active state changes
3613 * @param {Roo.bootstrap.NavItem} this
3614 * @param {boolean} state the new state
3622 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3630 preventDefault : false,
3637 getAutoCreate : function(){
3645 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3647 if (this.disabled) {
3648 cfg.cls += ' disabled';
3651 if (this.href || this.html || this.glyphicon || this.icon) {
3655 href : this.href || "#",
3656 html: this.html || ''
3661 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3664 if(this.glyphicon) {
3665 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3670 cfg.cn[0].html += " <span class='caret'></span>";
3674 if (this.badge !== '') {
3676 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3684 initEvents: function() {
3685 // Roo.log('init events?');
3686 // Roo.log(this.el.dom);
3687 if (typeof (this.menu) != 'undefined') {
3688 this.menu.parentType = this.xtype;
3689 this.menu.triggerEl = this.el;
3690 this.addxtype(Roo.apply({}, this.menu));
3694 this.el.select('a',true).on('click', this.onClick, this);
3695 // at this point parent should be available..
3696 this.parent().register(this);
3699 onClick : function(e)
3702 if(this.preventDefault){
3705 if (this.disabled) {
3709 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3710 if (tg && tg.transition) {
3711 Roo.log("waiting for the transitionend");
3715 Roo.log("fire event clicked");
3716 if(this.fireEvent('click', this, e) === false){
3719 var p = this.parent();
3720 if (['tabs','pills'].indexOf(p.type)!==-1) {
3721 if (typeof(p.setActiveItem) !== 'undefined') {
3722 p.setActiveItem(this);
3725 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3726 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3727 // remove the collapsed menu expand...
3728 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3733 isActive: function () {
3736 setActive : function(state, fire, is_was_active)
3738 if (this.active && !state & this.navId) {
3739 this.was_active = true;
3740 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3742 nv.clearWasActive(this);
3746 this.active = state;
3749 this.el.removeClass('active');
3750 } else if (!this.el.hasClass('active')) {
3751 this.el.addClass('active');
3754 this.fireEvent('changed', this, state);
3757 // show a panel if it's registered and related..
3759 if (!this.navId || !this.tabId || !state || is_was_active) {
3763 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3767 var pan = tg.getPanelByName(this.tabId);
3771 // if we can not flip to new panel - go back to old nav highlight..
3772 if (false == tg.showPanel(pan)) {
3773 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3775 var onav = nv.getWasActive();
3777 onav.setActive(true, false, true);
3786 // this should not be here...
3787 setDisabled : function(state)
3789 this.disabled = state;
3791 this.el.removeClass('disabled');
3792 } else if (!this.el.hasClass('disabled')) {
3793 this.el.addClass('disabled');
3806 * <span> icon </span>
3807 * <span> text </span>
3808 * <span>badge </span>
3812 * @class Roo.bootstrap.NavSidebarItem
3813 * @extends Roo.bootstrap.NavItem
3814 * Bootstrap Navbar.NavSidebarItem class
3816 * Create a new Navbar Button
3817 * @param {Object} config The config object
3819 Roo.bootstrap.NavSidebarItem = function(config){
3820 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3825 * The raw click event for the entire grid.
3826 * @param {Roo.EventObject} e
3831 * Fires when the active item active state changes
3832 * @param {Roo.bootstrap.NavSidebarItem} this
3833 * @param {boolean} state the new state
3841 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3844 getAutoCreate : function(){
3849 href : this.href || '#',
3861 html : this.html || ''
3866 cfg.cls += ' active';
3870 if (this.glyphicon || this.icon) {
3871 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3872 a.cn.push({ tag : 'i', cls : c }) ;
3877 if (this.badge !== '') {
3878 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3882 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3883 a.cls += 'dropdown-toggle treeview' ;
3907 * @class Roo.bootstrap.Row
3908 * @extends Roo.bootstrap.Component
3909 * Bootstrap Row class (contains columns...)
3913 * @param {Object} config The config object
3916 Roo.bootstrap.Row = function(config){
3917 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3920 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3922 getAutoCreate : function(){
3941 * @class Roo.bootstrap.Element
3942 * @extends Roo.bootstrap.Component
3943 * Bootstrap Element class
3944 * @cfg {String} html contents of the element
3945 * @cfg {String} tag tag of the element
3946 * @cfg {String} cls class of the element
3949 * Create a new Element
3950 * @param {Object} config The config object
3953 Roo.bootstrap.Element = function(config){
3954 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3957 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3964 getAutoCreate : function(){
3989 * @class Roo.bootstrap.Pagination
3990 * @extends Roo.bootstrap.Component
3991 * Bootstrap Pagination class
3992 * @cfg {String} size xs | sm | md | lg
3993 * @cfg {Boolean} inverse false | true
3996 * Create a new Pagination
3997 * @param {Object} config The config object
4000 Roo.bootstrap.Pagination = function(config){
4001 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4004 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4010 getAutoCreate : function(){
4016 cfg.cls += ' inverse';
4022 cfg.cls += " " + this.cls;
4040 * @class Roo.bootstrap.PaginationItem
4041 * @extends Roo.bootstrap.Component
4042 * Bootstrap PaginationItem class
4043 * @cfg {String} html text
4044 * @cfg {String} href the link
4045 * @cfg {Boolean} preventDefault (true | false) default true
4046 * @cfg {Boolean} active (true | false) default false
4050 * Create a new PaginationItem
4051 * @param {Object} config The config object
4055 Roo.bootstrap.PaginationItem = function(config){
4056 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4061 * The raw click event for the entire grid.
4062 * @param {Roo.EventObject} e
4068 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4072 preventDefault: true,
4076 getAutoCreate : function(){
4082 href : this.href ? this.href : '#',
4083 html : this.html ? this.html : ''
4093 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4099 initEvents: function() {
4101 this.el.on('click', this.onClick, this);
4104 onClick : function(e)
4106 Roo.log('PaginationItem on click ');
4107 if(this.preventDefault){
4111 this.fireEvent('click', this, e);
4127 * @class Roo.bootstrap.Slider
4128 * @extends Roo.bootstrap.Component
4129 * Bootstrap Slider class
4132 * Create a new Slider
4133 * @param {Object} config The config object
4136 Roo.bootstrap.Slider = function(config){
4137 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4140 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4142 getAutoCreate : function(){
4146 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4150 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4162 * Ext JS Library 1.1.1
4163 * Copyright(c) 2006-2007, Ext JS, LLC.
4165 * Originally Released Under LGPL - original licence link has changed is not relivant.
4168 * <script type="text/javascript">
4173 * @class Roo.grid.ColumnModel
4174 * @extends Roo.util.Observable
4175 * This is the default implementation of a ColumnModel used by the Grid. It defines
4176 * the columns in the grid.
4179 var colModel = new Roo.grid.ColumnModel([
4180 {header: "Ticker", width: 60, sortable: true, locked: true},
4181 {header: "Company Name", width: 150, sortable: true},
4182 {header: "Market Cap.", width: 100, sortable: true},
4183 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4184 {header: "Employees", width: 100, sortable: true, resizable: false}
4189 * The config options listed for this class are options which may appear in each
4190 * individual column definition.
4191 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4193 * @param {Object} config An Array of column config objects. See this class's
4194 * config objects for details.
4196 Roo.grid.ColumnModel = function(config){
4198 * The config passed into the constructor
4200 this.config = config;
4203 // if no id, create one
4204 // if the column does not have a dataIndex mapping,
4205 // map it to the order it is in the config
4206 for(var i = 0, len = config.length; i < len; i++){
4208 if(typeof c.dataIndex == "undefined"){
4211 if(typeof c.renderer == "string"){
4212 c.renderer = Roo.util.Format[c.renderer];
4214 if(typeof c.id == "undefined"){
4217 if(c.editor && c.editor.xtype){
4218 c.editor = Roo.factory(c.editor, Roo.grid);
4220 if(c.editor && c.editor.isFormField){
4221 c.editor = new Roo.grid.GridEditor(c.editor);
4223 this.lookup[c.id] = c;
4227 * The width of columns which have no width specified (defaults to 100)
4230 this.defaultWidth = 100;
4233 * Default sortable of columns which have no sortable specified (defaults to false)
4236 this.defaultSortable = false;
4240 * @event widthchange
4241 * Fires when the width of a column changes.
4242 * @param {ColumnModel} this
4243 * @param {Number} columnIndex The column index
4244 * @param {Number} newWidth The new width
4246 "widthchange": true,
4248 * @event headerchange
4249 * Fires when the text of a header changes.
4250 * @param {ColumnModel} this
4251 * @param {Number} columnIndex The column index
4252 * @param {Number} newText The new header text
4254 "headerchange": true,
4256 * @event hiddenchange
4257 * Fires when a column is hidden or "unhidden".
4258 * @param {ColumnModel} this
4259 * @param {Number} columnIndex The column index
4260 * @param {Boolean} hidden true if hidden, false otherwise
4262 "hiddenchange": true,
4264 * @event columnmoved
4265 * Fires when a column is moved.
4266 * @param {ColumnModel} this
4267 * @param {Number} oldIndex
4268 * @param {Number} newIndex
4270 "columnmoved" : true,
4272 * @event columlockchange
4273 * Fires when a column's locked state is changed
4274 * @param {ColumnModel} this
4275 * @param {Number} colIndex
4276 * @param {Boolean} locked true if locked
4278 "columnlockchange" : true
4280 Roo.grid.ColumnModel.superclass.constructor.call(this);
4282 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4284 * @cfg {String} header The header text to display in the Grid view.
4287 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4288 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4289 * specified, the column's index is used as an index into the Record's data Array.
4292 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4293 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4296 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4297 * Defaults to the value of the {@link #defaultSortable} property.
4298 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4301 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4304 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4307 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4310 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4313 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4314 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4315 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4316 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4319 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4322 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4326 * Returns the id of the column at the specified index.
4327 * @param {Number} index The column index
4328 * @return {String} the id
4330 getColumnId : function(index){
4331 return this.config[index].id;
4335 * Returns the column for a specified id.
4336 * @param {String} id The column id
4337 * @return {Object} the column
4339 getColumnById : function(id){
4340 return this.lookup[id];
4345 * Returns the column for a specified dataIndex.
4346 * @param {String} dataIndex The column dataIndex
4347 * @return {Object|Boolean} the column or false if not found
4349 getColumnByDataIndex: function(dataIndex){
4350 var index = this.findColumnIndex(dataIndex);
4351 return index > -1 ? this.config[index] : false;
4355 * Returns the index for a specified column id.
4356 * @param {String} id The column id
4357 * @return {Number} the index, or -1 if not found
4359 getIndexById : function(id){
4360 for(var i = 0, len = this.config.length; i < len; i++){
4361 if(this.config[i].id == id){
4369 * Returns the index for a specified column dataIndex.
4370 * @param {String} dataIndex The column dataIndex
4371 * @return {Number} the index, or -1 if not found
4374 findColumnIndex : function(dataIndex){
4375 for(var i = 0, len = this.config.length; i < len; i++){
4376 if(this.config[i].dataIndex == dataIndex){
4384 moveColumn : function(oldIndex, newIndex){
4385 var c = this.config[oldIndex];
4386 this.config.splice(oldIndex, 1);
4387 this.config.splice(newIndex, 0, c);
4388 this.dataMap = null;
4389 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4392 isLocked : function(colIndex){
4393 return this.config[colIndex].locked === true;
4396 setLocked : function(colIndex, value, suppressEvent){
4397 if(this.isLocked(colIndex) == value){
4400 this.config[colIndex].locked = value;
4402 this.fireEvent("columnlockchange", this, colIndex, value);
4406 getTotalLockedWidth : function(){
4408 for(var i = 0; i < this.config.length; i++){
4409 if(this.isLocked(i) && !this.isHidden(i)){
4410 this.totalWidth += this.getColumnWidth(i);
4416 getLockedCount : function(){
4417 for(var i = 0, len = this.config.length; i < len; i++){
4418 if(!this.isLocked(i)){
4425 * Returns the number of columns.
4428 getColumnCount : function(visibleOnly){
4429 if(visibleOnly === true){
4431 for(var i = 0, len = this.config.length; i < len; i++){
4432 if(!this.isHidden(i)){
4438 return this.config.length;
4442 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4443 * @param {Function} fn
4444 * @param {Object} scope (optional)
4445 * @return {Array} result
4447 getColumnsBy : function(fn, scope){
4449 for(var i = 0, len = this.config.length; i < len; i++){
4450 var c = this.config[i];
4451 if(fn.call(scope||this, c, i) === true){
4459 * Returns true if the specified column is sortable.
4460 * @param {Number} col The column index
4463 isSortable : function(col){
4464 if(typeof this.config[col].sortable == "undefined"){
4465 return this.defaultSortable;
4467 return this.config[col].sortable;
4471 * Returns the rendering (formatting) function defined for the column.
4472 * @param {Number} col The column index.
4473 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4475 getRenderer : function(col){
4476 if(!this.config[col].renderer){
4477 return Roo.grid.ColumnModel.defaultRenderer;
4479 return this.config[col].renderer;
4483 * Sets the rendering (formatting) function for a column.
4484 * @param {Number} col The column index
4485 * @param {Function} fn The function to use to process the cell's raw data
4486 * to return HTML markup for the grid view. The render function is called with
4487 * the following parameters:<ul>
4488 * <li>Data value.</li>
4489 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4490 * <li>css A CSS style string to apply to the table cell.</li>
4491 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4492 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4493 * <li>Row index</li>
4494 * <li>Column index</li>
4495 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4497 setRenderer : function(col, fn){
4498 this.config[col].renderer = fn;
4502 * Returns the width for the specified column.
4503 * @param {Number} col The column index
4506 getColumnWidth : function(col){
4507 return this.config[col].width * 1 || this.defaultWidth;
4511 * Sets the width for a column.
4512 * @param {Number} col The column index
4513 * @param {Number} width The new width
4515 setColumnWidth : function(col, width, suppressEvent){
4516 this.config[col].width = width;
4517 this.totalWidth = null;
4519 this.fireEvent("widthchange", this, col, width);
4524 * Returns the total width of all columns.
4525 * @param {Boolean} includeHidden True to include hidden column widths
4528 getTotalWidth : function(includeHidden){
4529 if(!this.totalWidth){
4530 this.totalWidth = 0;
4531 for(var i = 0, len = this.config.length; i < len; i++){
4532 if(includeHidden || !this.isHidden(i)){
4533 this.totalWidth += this.getColumnWidth(i);
4537 return this.totalWidth;
4541 * Returns the header for the specified column.
4542 * @param {Number} col The column index
4545 getColumnHeader : function(col){
4546 return this.config[col].header;
4550 * Sets the header for a column.
4551 * @param {Number} col The column index
4552 * @param {String} header The new header
4554 setColumnHeader : function(col, header){
4555 this.config[col].header = header;
4556 this.fireEvent("headerchange", this, col, header);
4560 * Returns the tooltip for the specified column.
4561 * @param {Number} col The column index
4564 getColumnTooltip : function(col){
4565 return this.config[col].tooltip;
4568 * Sets the tooltip for a column.
4569 * @param {Number} col The column index
4570 * @param {String} tooltip The new tooltip
4572 setColumnTooltip : function(col, tooltip){
4573 this.config[col].tooltip = tooltip;
4577 * Returns the dataIndex for the specified column.
4578 * @param {Number} col The column index
4581 getDataIndex : function(col){
4582 return this.config[col].dataIndex;
4586 * Sets the dataIndex for a column.
4587 * @param {Number} col The column index
4588 * @param {Number} dataIndex The new dataIndex
4590 setDataIndex : function(col, dataIndex){
4591 this.config[col].dataIndex = dataIndex;
4597 * Returns true if the cell is editable.
4598 * @param {Number} colIndex The column index
4599 * @param {Number} rowIndex The row index
4602 isCellEditable : function(colIndex, rowIndex){
4603 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4607 * Returns the editor defined for the cell/column.
4608 * return false or null to disable editing.
4609 * @param {Number} colIndex The column index
4610 * @param {Number} rowIndex The row index
4613 getCellEditor : function(colIndex, rowIndex){
4614 return this.config[colIndex].editor;
4618 * Sets if a column is editable.
4619 * @param {Number} col The column index
4620 * @param {Boolean} editable True if the column is editable
4622 setEditable : function(col, editable){
4623 this.config[col].editable = editable;
4628 * Returns true if the column is hidden.
4629 * @param {Number} colIndex The column index
4632 isHidden : function(colIndex){
4633 return this.config[colIndex].hidden;
4638 * Returns true if the column width cannot be changed
4640 isFixed : function(colIndex){
4641 return this.config[colIndex].fixed;
4645 * Returns true if the column can be resized
4648 isResizable : function(colIndex){
4649 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4652 * Sets if a column is hidden.
4653 * @param {Number} colIndex The column index
4654 * @param {Boolean} hidden True if the column is hidden
4656 setHidden : function(colIndex, hidden){
4657 this.config[colIndex].hidden = hidden;
4658 this.totalWidth = null;
4659 this.fireEvent("hiddenchange", this, colIndex, hidden);
4663 * Sets the editor for a column.
4664 * @param {Number} col The column index
4665 * @param {Object} editor The editor object
4667 setEditor : function(col, editor){
4668 this.config[col].editor = editor;
4672 Roo.grid.ColumnModel.defaultRenderer = function(value){
4673 if(typeof value == "string" && value.length < 1){
4679 // Alias for backwards compatibility
4680 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4683 * Ext JS Library 1.1.1
4684 * Copyright(c) 2006-2007, Ext JS, LLC.
4686 * Originally Released Under LGPL - original licence link has changed is not relivant.
4689 * <script type="text/javascript">
4693 * @class Roo.LoadMask
4694 * A simple utility class for generically masking elements while loading data. If the element being masked has
4695 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4696 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4697 * element's UpdateManager load indicator and will be destroyed after the initial load.
4699 * Create a new LoadMask
4700 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4701 * @param {Object} config The config object
4703 Roo.LoadMask = function(el, config){
4704 this.el = Roo.get(el);
4705 Roo.apply(this, config);
4707 this.store.on('beforeload', this.onBeforeLoad, this);
4708 this.store.on('load', this.onLoad, this);
4709 this.store.on('loadexception', this.onLoadException, this);
4710 this.removeMask = false;
4712 var um = this.el.getUpdateManager();
4713 um.showLoadIndicator = false; // disable the default indicator
4714 um.on('beforeupdate', this.onBeforeLoad, this);
4715 um.on('update', this.onLoad, this);
4716 um.on('failure', this.onLoad, this);
4717 this.removeMask = true;
4721 Roo.LoadMask.prototype = {
4723 * @cfg {Boolean} removeMask
4724 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4725 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4729 * The text to display in a centered loading message box (defaults to 'Loading...')
4733 * @cfg {String} msgCls
4734 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4736 msgCls : 'x-mask-loading',
4739 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4745 * Disables the mask to prevent it from being displayed
4747 disable : function(){
4748 this.disabled = true;
4752 * Enables the mask so that it can be displayed
4754 enable : function(){
4755 this.disabled = false;
4758 onLoadException : function()
4762 if (typeof(arguments[3]) != 'undefined') {
4763 Roo.MessageBox.alert("Error loading",arguments[3]);
4767 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4768 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4777 this.el.unmask(this.removeMask);
4782 this.el.unmask(this.removeMask);
4786 onBeforeLoad : function(){
4788 this.el.mask(this.msg, this.msgCls);
4793 destroy : function(){
4795 this.store.un('beforeload', this.onBeforeLoad, this);
4796 this.store.un('load', this.onLoad, this);
4797 this.store.un('loadexception', this.onLoadException, this);
4799 var um = this.el.getUpdateManager();
4800 um.un('beforeupdate', this.onBeforeLoad, this);
4801 um.un('update', this.onLoad, this);
4802 um.un('failure', this.onLoad, this);
4813 * @class Roo.bootstrap.Table
4814 * @extends Roo.bootstrap.Component
4815 * Bootstrap Table class
4816 * @cfg {String} cls table class
4817 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4818 * @cfg {String} bgcolor Specifies the background color for a table
4819 * @cfg {Number} border Specifies whether the table cells should have borders or not
4820 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4821 * @cfg {Number} cellspacing Specifies the space between cells
4822 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4823 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4824 * @cfg {String} sortable Specifies that the table should be sortable
4825 * @cfg {String} summary Specifies a summary of the content of a table
4826 * @cfg {Number} width Specifies the width of a table
4827 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4829 * @cfg {boolean} striped Should the rows be alternative striped
4830 * @cfg {boolean} bordered Add borders to the table
4831 * @cfg {boolean} hover Add hover highlighting
4832 * @cfg {boolean} condensed Format condensed
4833 * @cfg {boolean} responsive Format condensed
4834 * @cfg {Boolean} loadMask (true|false) default false
4835 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4836 * @cfg {Boolean} thead (true|false) generate thead, default true
4837 * @cfg {Boolean} RowSelection (true|false) default false
4838 * @cfg {Boolean} CellSelection (true|false) default false
4840 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4844 * Create a new Table
4845 * @param {Object} config The config object
4848 Roo.bootstrap.Table = function(config){
4849 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4852 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4853 this.sm = this.selModel;
4854 this.sm.xmodule = this.xmodule || false;
4856 if (this.cm && typeof(this.cm.config) == 'undefined') {
4857 this.colModel = new Roo.grid.ColumnModel(this.cm);
4858 this.cm = this.colModel;
4859 this.cm.xmodule = this.xmodule || false;
4862 this.store= Roo.factory(this.store, Roo.data);
4863 this.ds = this.store;
4864 this.ds.xmodule = this.xmodule || false;
4867 if (this.footer && this.store) {
4868 this.footer.dataSource = this.ds;
4869 this.footer = Roo.factory(this.footer);
4876 * Fires when a cell is clicked
4877 * @param {Roo.bootstrap.Table} this
4878 * @param {Roo.Element} el
4879 * @param {Number} rowIndex
4880 * @param {Number} columnIndex
4881 * @param {Roo.EventObject} e
4885 * @event celldblclick
4886 * Fires when a cell is double clicked
4887 * @param {Roo.bootstrap.Table} this
4888 * @param {Roo.Element} el
4889 * @param {Number} rowIndex
4890 * @param {Number} columnIndex
4891 * @param {Roo.EventObject} e
4893 "celldblclick" : true,
4896 * Fires when a row is clicked
4897 * @param {Roo.bootstrap.Table} this
4898 * @param {Roo.Element} el
4899 * @param {Number} rowIndex
4900 * @param {Roo.EventObject} e
4904 * @event rowdblclick
4905 * Fires when a row is double clicked
4906 * @param {Roo.bootstrap.Table} this
4907 * @param {Roo.Element} el
4908 * @param {Number} rowIndex
4909 * @param {Roo.EventObject} e
4911 "rowdblclick" : true,
4914 * Fires when a mouseover occur
4915 * @param {Roo.bootstrap.Table} this
4916 * @param {Roo.Element} el
4917 * @param {Number} rowIndex
4918 * @param {Number} columnIndex
4919 * @param {Roo.EventObject} e
4924 * Fires when a mouseout occur
4925 * @param {Roo.bootstrap.Table} this
4926 * @param {Roo.Element} el
4927 * @param {Number} rowIndex
4928 * @param {Number} columnIndex
4929 * @param {Roo.EventObject} e
4934 * Fires when a row is rendered, so you can change add a style to it.
4935 * @param {Roo.bootstrap.Table} this
4936 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4943 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4967 RowSelection : false,
4968 CellSelection : false,
4971 // Roo.Element - the tbody
4974 getAutoCreate : function(){
4975 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4984 cfg.cls += ' table-striped';
4988 cfg.cls += ' table-hover';
4990 if (this.bordered) {
4991 cfg.cls += ' table-bordered';
4993 if (this.condensed) {
4994 cfg.cls += ' table-condensed';
4996 if (this.responsive) {
4997 cfg.cls += ' table-responsive';
5001 cfg.cls+= ' ' +this.cls;
5004 // this lot should be simplifed...
5007 cfg.align=this.align;
5010 cfg.bgcolor=this.bgcolor;
5013 cfg.border=this.border;
5015 if (this.cellpadding) {
5016 cfg.cellpadding=this.cellpadding;
5018 if (this.cellspacing) {
5019 cfg.cellspacing=this.cellspacing;
5022 cfg.frame=this.frame;
5025 cfg.rules=this.rules;
5027 if (this.sortable) {
5028 cfg.sortable=this.sortable;
5031 cfg.summary=this.summary;
5034 cfg.width=this.width;
5037 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5040 if(this.store || this.cm){
5042 cfg.cn.push(this.renderHeader());
5045 cfg.cn.push(this.renderBody());
5048 cfg.cn.push(this.renderFooter());
5051 cfg.cls+= ' TableGrid';
5054 return { cn : [ cfg ] };
5057 initEvents : function()
5059 if(!this.store || !this.cm){
5063 //Roo.log('initEvents with ds!!!!');
5065 this.mainBody = this.el.select('tbody', true).first();
5070 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5071 e.on('click', _this.sort, _this);
5074 this.el.on("click", this.onClick, this);
5075 this.el.on("dblclick", this.onDblClick, this);
5077 this.parent().el.setStyle('position', 'relative');
5079 this.footer.parentId = this.id;
5080 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5083 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5085 this.store.on('load', this.onLoad, this);
5086 this.store.on('beforeload', this.onBeforeLoad, this);
5087 this.store.on('update', this.onUpdate, this);
5091 onMouseover : function(e, el)
5093 var cell = Roo.get(el);
5099 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5100 cell = cell.findParent('td', false, true);
5103 var row = cell.findParent('tr', false, true);
5104 var cellIndex = cell.dom.cellIndex;
5105 var rowIndex = row.dom.rowIndex - 1; // start from 0
5107 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5111 onMouseout : function(e, el)
5113 var cell = Roo.get(el);
5119 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5120 cell = cell.findParent('td', false, true);
5123 var row = cell.findParent('tr', false, true);
5124 var cellIndex = cell.dom.cellIndex;
5125 var rowIndex = row.dom.rowIndex - 1; // start from 0
5127 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5131 onClick : function(e, el)
5133 var cell = Roo.get(el);
5135 if(!cell || (!this.CellSelection && !this.RowSelection)){
5140 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5141 cell = cell.findParent('td', false, true);
5144 var row = cell.findParent('tr', false, true);
5145 var cellIndex = cell.dom.cellIndex;
5146 var rowIndex = row.dom.rowIndex - 1;
5148 if(this.CellSelection){
5149 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5152 if(this.RowSelection){
5153 this.fireEvent('rowclick', this, row, rowIndex, e);
5159 onDblClick : function(e,el)
5161 var cell = Roo.get(el);
5163 if(!cell || (!this.CellSelection && !this.RowSelection)){
5167 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5168 cell = cell.findParent('td', false, true);
5171 var row = cell.findParent('tr', false, true);
5172 var cellIndex = cell.dom.cellIndex;
5173 var rowIndex = row.dom.rowIndex - 1;
5175 if(this.CellSelection){
5176 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5179 if(this.RowSelection){
5180 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5184 sort : function(e,el)
5186 var col = Roo.get(el)
5188 if(!col.hasClass('sortable')){
5192 var sort = col.attr('sort');
5195 if(col.hasClass('glyphicon-arrow-up')){
5199 this.store.sortInfo = {field : sort, direction : dir};
5202 Roo.log("calling footer first");
5203 this.footer.onClick('first');
5206 this.store.load({ params : { start : 0 } });
5210 renderHeader : function()
5219 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5221 var config = cm.config[i];
5226 html: cm.getColumnHeader(i)
5229 if(typeof(config.hidden) != 'undefined' && config.hidden){
5230 c.style += ' display:none;';
5233 if(typeof(config.dataIndex) != 'undefined'){
5234 c.sort = config.dataIndex;
5237 if(typeof(config.sortable) != 'undefined' && config.sortable){
5241 if(typeof(config.align) != 'undefined' && config.align.length){
5242 c.style += ' text-align:' + config.align + ';';
5245 if(typeof(config.width) != 'undefined'){
5246 c.style += ' width:' + config.width + 'px;';
5255 renderBody : function()
5265 colspan : this.cm.getColumnCount()
5275 renderFooter : function()
5285 colspan : this.cm.getColumnCount()
5299 Roo.log('ds onload');
5304 var ds = this.store;
5306 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5307 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5309 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5310 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5313 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5314 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5318 var tbody = this.mainBody;
5320 if(ds.getCount() > 0){
5321 ds.data.each(function(d,rowIndex){
5322 var row = this.renderRow(cm, ds, rowIndex);
5324 tbody.createChild(row);
5328 if(row.cellObjects.length){
5329 Roo.each(row.cellObjects, function(r){
5330 _this.renderCellObject(r);
5337 Roo.each(this.el.select('tbody td', true).elements, function(e){
5338 e.on('mouseover', _this.onMouseover, _this);
5341 Roo.each(this.el.select('tbody td', true).elements, function(e){
5342 e.on('mouseout', _this.onMouseout, _this);
5345 //if(this.loadMask){
5346 // this.maskEl.hide();
5351 onUpdate : function(ds,record)
5353 this.refreshRow(record);
5355 onRemove : function(ds, record, index, isUpdate){
5356 if(isUpdate !== true){
5357 this.fireEvent("beforerowremoved", this, index, record);
5359 var bt = this.mainBody.dom;
5361 bt.removeChild(bt.rows[index]);
5364 if(isUpdate !== true){
5365 //this.stripeRows(index);
5366 //this.syncRowHeights(index, index);
5368 this.fireEvent("rowremoved", this, index, record);
5373 refreshRow : function(record){
5374 var ds = this.store, index;
5375 if(typeof record == 'number'){
5377 record = ds.getAt(index);
5379 index = ds.indexOf(record);
5381 this.insertRow(ds, index, true);
5382 this.onRemove(ds, record, index+1, true);
5383 //this.syncRowHeights(index, index);
5385 this.fireEvent("rowupdated", this, index, record);
5388 insertRow : function(dm, rowIndex, isUpdate){
5391 this.fireEvent("beforerowsinserted", this, rowIndex);
5393 //var s = this.getScrollState();
5394 var row = this.renderRow(this.cm, this.store, rowIndex);
5395 // insert before rowIndex..
5396 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5400 if(row.cellObjects.length){
5401 Roo.each(row.cellObjects, function(r){
5402 _this.renderCellObject(r);
5407 this.fireEvent("rowsinserted", this, rowIndex);
5408 //this.syncRowHeights(firstRow, lastRow);
5409 //this.stripeRows(firstRow);
5416 getRowDom : function(rowIndex)
5418 // not sure if I need to check this.. but let's do it anyway..
5419 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5420 this.mainBody.dom.rows[rowIndex] : false
5422 // returns the object tree for a tr..
5425 renderRow : function(cm, ds, rowIndex) {
5427 var d = ds.getAt(rowIndex);
5434 var cellObjects = [];
5436 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5437 var config = cm.config[i];
5439 var renderer = cm.getRenderer(i);
5443 if(typeof(renderer) !== 'undefined'){
5444 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5446 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5447 // and are rendered into the cells after the row is rendered - using the id for the element.
5449 if(typeof(value) === 'object'){
5459 rowIndex : rowIndex,
5464 this.fireEvent('rowclass', this, rowcfg);
5468 cls : rowcfg.rowClass,
5470 html: (typeof(value) === 'object') ? '' : value
5477 if(typeof(config.hidden) != 'undefined' && config.hidden){
5478 td.style += ' display:none;';
5481 if(typeof(config.align) != 'undefined' && config.align.length){
5482 td.style += ' text-align:' + config.align + ';';
5485 if(typeof(config.width) != 'undefined'){
5486 td.style += ' width:' + config.width + 'px;';
5493 row.cellObjects = cellObjects;
5501 onBeforeLoad : function()
5503 //Roo.log('ds onBeforeLoad');
5507 //if(this.loadMask){
5508 // this.maskEl.show();
5514 this.el.select('tbody', true).first().dom.innerHTML = '';
5517 getSelectionModel : function(){
5519 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5521 return this.selModel;
5524 * Render the Roo.bootstrap object from renderder
5526 renderCellObject : function(r)
5530 var t = r.cfg.render(r.container);
5533 Roo.each(r.cfg.cn, function(c){
5535 container: t.getChildContainer(),
5538 _this.renderCellObject(child);
5555 * @class Roo.bootstrap.TableCell
5556 * @extends Roo.bootstrap.Component
5557 * Bootstrap TableCell class
5558 * @cfg {String} html cell contain text
5559 * @cfg {String} cls cell class
5560 * @cfg {String} tag cell tag (td|th) default td
5561 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5562 * @cfg {String} align Aligns the content in a cell
5563 * @cfg {String} axis Categorizes cells
5564 * @cfg {String} bgcolor Specifies the background color of a cell
5565 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5566 * @cfg {Number} colspan Specifies the number of columns a cell should span
5567 * @cfg {String} headers Specifies one or more header cells a cell is related to
5568 * @cfg {Number} height Sets the height of a cell
5569 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5570 * @cfg {Number} rowspan Sets the number of rows a cell should span
5571 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5572 * @cfg {String} valign Vertical aligns the content in a cell
5573 * @cfg {Number} width Specifies the width of a cell
5576 * Create a new TableCell
5577 * @param {Object} config The config object
5580 Roo.bootstrap.TableCell = function(config){
5581 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5584 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5604 getAutoCreate : function(){
5605 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5625 cfg.align=this.align
5631 cfg.bgcolor=this.bgcolor
5634 cfg.charoff=this.charoff
5637 cfg.colspan=this.colspan
5640 cfg.headers=this.headers
5643 cfg.height=this.height
5646 cfg.nowrap=this.nowrap
5649 cfg.rowspan=this.rowspan
5652 cfg.scope=this.scope
5655 cfg.valign=this.valign
5658 cfg.width=this.width
5677 * @class Roo.bootstrap.TableRow
5678 * @extends Roo.bootstrap.Component
5679 * Bootstrap TableRow class
5680 * @cfg {String} cls row class
5681 * @cfg {String} align Aligns the content in a table row
5682 * @cfg {String} bgcolor Specifies a background color for a table row
5683 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5684 * @cfg {String} valign Vertical aligns the content in a table row
5687 * Create a new TableRow
5688 * @param {Object} config The config object
5691 Roo.bootstrap.TableRow = function(config){
5692 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5695 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5703 getAutoCreate : function(){
5704 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5714 cfg.align = this.align;
5717 cfg.bgcolor = this.bgcolor;
5720 cfg.charoff = this.charoff;
5723 cfg.valign = this.valign;
5741 * @class Roo.bootstrap.TableBody
5742 * @extends Roo.bootstrap.Component
5743 * Bootstrap TableBody class
5744 * @cfg {String} cls element class
5745 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5746 * @cfg {String} align Aligns the content inside the element
5747 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5748 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5751 * Create a new TableBody
5752 * @param {Object} config The config object
5755 Roo.bootstrap.TableBody = function(config){
5756 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5759 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5767 getAutoCreate : function(){
5768 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5782 cfg.align = this.align;
5785 cfg.charoff = this.charoff;
5788 cfg.valign = this.valign;
5795 // initEvents : function()
5802 // this.store = Roo.factory(this.store, Roo.data);
5803 // this.store.on('load', this.onLoad, this);
5805 // this.store.load();
5809 // onLoad: function ()
5811 // this.fireEvent('load', this);
5821 * Ext JS Library 1.1.1
5822 * Copyright(c) 2006-2007, Ext JS, LLC.
5824 * Originally Released Under LGPL - original licence link has changed is not relivant.
5827 * <script type="text/javascript">
5830 // as we use this in bootstrap.
5831 Roo.namespace('Roo.form');
5833 * @class Roo.form.Action
5834 * Internal Class used to handle form actions
5836 * @param {Roo.form.BasicForm} el The form element or its id
5837 * @param {Object} config Configuration options
5842 // define the action interface
5843 Roo.form.Action = function(form, options){
5845 this.options = options || {};
5848 * Client Validation Failed
5851 Roo.form.Action.CLIENT_INVALID = 'client';
5853 * Server Validation Failed
5856 Roo.form.Action.SERVER_INVALID = 'server';
5858 * Connect to Server Failed
5861 Roo.form.Action.CONNECT_FAILURE = 'connect';
5863 * Reading Data from Server Failed
5866 Roo.form.Action.LOAD_FAILURE = 'load';
5868 Roo.form.Action.prototype = {
5870 failureType : undefined,
5871 response : undefined,
5875 run : function(options){
5880 success : function(response){
5885 handleResponse : function(response){
5889 // default connection failure
5890 failure : function(response){
5892 this.response = response;
5893 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5894 this.form.afterAction(this, false);
5897 processResponse : function(response){
5898 this.response = response;
5899 if(!response.responseText){
5902 this.result = this.handleResponse(response);
5906 // utility functions used internally
5907 getUrl : function(appendParams){
5908 var url = this.options.url || this.form.url || this.form.el.dom.action;
5910 var p = this.getParams();
5912 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5918 getMethod : function(){
5919 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5922 getParams : function(){
5923 var bp = this.form.baseParams;
5924 var p = this.options.params;
5926 if(typeof p == "object"){
5927 p = Roo.urlEncode(Roo.applyIf(p, bp));
5928 }else if(typeof p == 'string' && bp){
5929 p += '&' + Roo.urlEncode(bp);
5932 p = Roo.urlEncode(bp);
5937 createCallback : function(){
5939 success: this.success,
5940 failure: this.failure,
5942 timeout: (this.form.timeout*1000),
5943 upload: this.form.fileUpload ? this.success : undefined
5948 Roo.form.Action.Submit = function(form, options){
5949 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5952 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5955 haveProgress : false,
5956 uploadComplete : false,
5958 // uploadProgress indicator.
5959 uploadProgress : function()
5961 if (!this.form.progressUrl) {
5965 if (!this.haveProgress) {
5966 Roo.MessageBox.progress("Uploading", "Uploading");
5968 if (this.uploadComplete) {
5969 Roo.MessageBox.hide();
5973 this.haveProgress = true;
5975 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5977 var c = new Roo.data.Connection();
5979 url : this.form.progressUrl,
5984 success : function(req){
5985 //console.log(data);
5989 rdata = Roo.decode(req.responseText)
5991 Roo.log("Invalid data from server..");
5995 if (!rdata || !rdata.success) {
5997 Roo.MessageBox.alert(Roo.encode(rdata));
6000 var data = rdata.data;
6002 if (this.uploadComplete) {
6003 Roo.MessageBox.hide();
6008 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6009 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6012 this.uploadProgress.defer(2000,this);
6015 failure: function(data) {
6016 Roo.log('progress url failed ');
6027 // run get Values on the form, so it syncs any secondary forms.
6028 this.form.getValues();
6030 var o = this.options;
6031 var method = this.getMethod();
6032 var isPost = method == 'POST';
6033 if(o.clientValidation === false || this.form.isValid()){
6035 if (this.form.progressUrl) {
6036 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6037 (new Date() * 1) + '' + Math.random());
6042 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6043 form:this.form.el.dom,
6044 url:this.getUrl(!isPost),
6046 params:isPost ? this.getParams() : null,
6047 isUpload: this.form.fileUpload
6050 this.uploadProgress();
6052 }else if (o.clientValidation !== false){ // client validation failed
6053 this.failureType = Roo.form.Action.CLIENT_INVALID;
6054 this.form.afterAction(this, false);
6058 success : function(response)
6060 this.uploadComplete= true;
6061 if (this.haveProgress) {
6062 Roo.MessageBox.hide();
6066 var result = this.processResponse(response);
6067 if(result === true || result.success){
6068 this.form.afterAction(this, true);
6072 this.form.markInvalid(result.errors);
6073 this.failureType = Roo.form.Action.SERVER_INVALID;
6075 this.form.afterAction(this, false);
6077 failure : function(response)
6079 this.uploadComplete= true;
6080 if (this.haveProgress) {
6081 Roo.MessageBox.hide();
6084 this.response = response;
6085 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6086 this.form.afterAction(this, false);
6089 handleResponse : function(response){
6090 if(this.form.errorReader){
6091 var rs = this.form.errorReader.read(response);
6094 for(var i = 0, len = rs.records.length; i < len; i++) {
6095 var r = rs.records[i];
6099 if(errors.length < 1){
6103 success : rs.success,
6109 ret = Roo.decode(response.responseText);
6113 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6123 Roo.form.Action.Load = function(form, options){
6124 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6125 this.reader = this.form.reader;
6128 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6133 Roo.Ajax.request(Roo.apply(
6134 this.createCallback(), {
6135 method:this.getMethod(),
6136 url:this.getUrl(false),
6137 params:this.getParams()
6141 success : function(response){
6143 var result = this.processResponse(response);
6144 if(result === true || !result.success || !result.data){
6145 this.failureType = Roo.form.Action.LOAD_FAILURE;
6146 this.form.afterAction(this, false);
6149 this.form.clearInvalid();
6150 this.form.setValues(result.data);
6151 this.form.afterAction(this, true);
6154 handleResponse : function(response){
6155 if(this.form.reader){
6156 var rs = this.form.reader.read(response);
6157 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6159 success : rs.success,
6163 return Roo.decode(response.responseText);
6167 Roo.form.Action.ACTION_TYPES = {
6168 'load' : Roo.form.Action.Load,
6169 'submit' : Roo.form.Action.Submit
6178 * @class Roo.bootstrap.Form
6179 * @extends Roo.bootstrap.Component
6180 * Bootstrap Form class
6181 * @cfg {String} method GET | POST (default POST)
6182 * @cfg {String} labelAlign top | left (default top)
6183 * @cfg {String} align left | right - for navbars
6184 * @cfg {Boolean} loadMask load mask when submit (default true)
6189 * @param {Object} config The config object
6193 Roo.bootstrap.Form = function(config){
6194 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6197 * @event clientvalidation
6198 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6199 * @param {Form} this
6200 * @param {Boolean} valid true if the form has passed client-side validation
6202 clientvalidation: true,
6204 * @event beforeaction
6205 * Fires before any action is performed. Return false to cancel the action.
6206 * @param {Form} this
6207 * @param {Action} action The action to be performed
6211 * @event actionfailed
6212 * Fires when an action fails.
6213 * @param {Form} this
6214 * @param {Action} action The action that failed
6216 actionfailed : true,
6218 * @event actioncomplete
6219 * Fires when an action is completed.
6220 * @param {Form} this
6221 * @param {Action} action The action that completed
6223 actioncomplete : true
6228 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6231 * @cfg {String} method
6232 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6237 * The URL to use for form actions if one isn't supplied in the action options.
6240 * @cfg {Boolean} fileUpload
6241 * Set to true if this form is a file upload.
6245 * @cfg {Object} baseParams
6246 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6250 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6254 * @cfg {Sting} align (left|right) for navbar forms
6259 activeAction : null,
6262 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6263 * element by passing it or its id or mask the form itself by passing in true.
6266 waitMsgTarget : false,
6270 getAutoCreate : function(){
6274 method : this.method || 'POST',
6275 id : this.id || Roo.id(),
6278 if (this.parent().xtype.match(/^Nav/)) {
6279 cfg.cls = 'navbar-form navbar-' + this.align;
6283 if (this.labelAlign == 'left' ) {
6284 cfg.cls += ' form-horizontal';
6290 initEvents : function()
6292 this.el.on('submit', this.onSubmit, this);
6293 // this was added as random key presses on the form where triggering form submit.
6294 this.el.on('keypress', function(e) {
6295 if (e.getCharCode() != 13) {
6298 // we might need to allow it for textareas.. and some other items.
6299 // check e.getTarget().
6301 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6305 Roo.log("keypress blocked");
6313 onSubmit : function(e){
6318 * Returns true if client-side validation on the form is successful.
6321 isValid : function(){
6322 var items = this.getItems();
6324 items.each(function(f){
6333 * Returns true if any fields in this form have changed since their original load.
6336 isDirty : function(){
6338 var items = this.getItems();
6339 items.each(function(f){
6349 * Performs a predefined action (submit or load) or custom actions you define on this form.
6350 * @param {String} actionName The name of the action type
6351 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6352 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6353 * accept other config options):
6355 Property Type Description
6356 ---------------- --------------- ----------------------------------------------------------------------------------
6357 url String The url for the action (defaults to the form's url)
6358 method String The form method to use (defaults to the form's method, or POST if not defined)
6359 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6360 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6361 validate the form on the client (defaults to false)
6363 * @return {BasicForm} this
6365 doAction : function(action, options){
6366 if(typeof action == 'string'){
6367 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6369 if(this.fireEvent('beforeaction', this, action) !== false){
6370 this.beforeAction(action);
6371 action.run.defer(100, action);
6377 beforeAction : function(action){
6378 var o = action.options;
6381 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6383 // not really supported yet.. ??
6385 //if(this.waitMsgTarget === true){
6386 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6387 //}else if(this.waitMsgTarget){
6388 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6389 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6391 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6397 afterAction : function(action, success){
6398 this.activeAction = null;
6399 var o = action.options;
6401 //if(this.waitMsgTarget === true){
6403 //}else if(this.waitMsgTarget){
6404 // this.waitMsgTarget.unmask();
6406 // Roo.MessageBox.updateProgress(1);
6407 // Roo.MessageBox.hide();
6414 Roo.callback(o.success, o.scope, [this, action]);
6415 this.fireEvent('actioncomplete', this, action);
6419 // failure condition..
6420 // we have a scenario where updates need confirming.
6421 // eg. if a locking scenario exists..
6422 // we look for { errors : { needs_confirm : true }} in the response.
6424 (typeof(action.result) != 'undefined') &&
6425 (typeof(action.result.errors) != 'undefined') &&
6426 (typeof(action.result.errors.needs_confirm) != 'undefined')
6429 Roo.log("not supported yet");
6432 Roo.MessageBox.confirm(
6433 "Change requires confirmation",
6434 action.result.errorMsg,
6439 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6449 Roo.callback(o.failure, o.scope, [this, action]);
6450 // show an error message if no failed handler is set..
6451 if (!this.hasListener('actionfailed')) {
6452 Roo.log("need to add dialog support");
6454 Roo.MessageBox.alert("Error",
6455 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6456 action.result.errorMsg :
6457 "Saving Failed, please check your entries or try again"
6462 this.fireEvent('actionfailed', this, action);
6467 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6468 * @param {String} id The value to search for
6471 findField : function(id){
6472 var items = this.getItems();
6473 var field = items.get(id);
6475 items.each(function(f){
6476 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6483 return field || null;
6486 * Mark fields in this form invalid in bulk.
6487 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6488 * @return {BasicForm} this
6490 markInvalid : function(errors){
6491 if(errors instanceof Array){
6492 for(var i = 0, len = errors.length; i < len; i++){
6493 var fieldError = errors[i];
6494 var f = this.findField(fieldError.id);
6496 f.markInvalid(fieldError.msg);
6502 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6503 field.markInvalid(errors[id]);
6507 //Roo.each(this.childForms || [], function (f) {
6508 // f.markInvalid(errors);
6515 * Set values for fields in this form in bulk.
6516 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6517 * @return {BasicForm} this
6519 setValues : function(values){
6520 if(values instanceof Array){ // array of objects
6521 for(var i = 0, len = values.length; i < len; i++){
6523 var f = this.findField(v.id);
6525 f.setValue(v.value);
6526 if(this.trackResetOnLoad){
6527 f.originalValue = f.getValue();
6531 }else{ // object hash
6534 if(typeof values[id] != 'function' && (field = this.findField(id))){
6536 if (field.setFromData &&
6538 field.displayField &&
6539 // combos' with local stores can
6540 // be queried via setValue()
6541 // to set their value..
6542 (field.store && !field.store.isLocal)
6546 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6547 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6548 field.setFromData(sd);
6551 field.setValue(values[id]);
6555 if(this.trackResetOnLoad){
6556 field.originalValue = field.getValue();
6562 //Roo.each(this.childForms || [], function (f) {
6563 // f.setValues(values);
6570 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6571 * they are returned as an array.
6572 * @param {Boolean} asString
6575 getValues : function(asString){
6576 //if (this.childForms) {
6577 // copy values from the child forms
6578 // Roo.each(this.childForms, function (f) {
6579 // this.setValues(f.getValues());
6585 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6586 if(asString === true){
6589 return Roo.urlDecode(fs);
6593 * Returns the fields in this form as an object with key/value pairs.
6594 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6597 getFieldValues : function(with_hidden)
6599 var items = this.getItems();
6601 items.each(function(f){
6605 var v = f.getValue();
6606 if (f.inputType =='radio') {
6607 if (typeof(ret[f.getName()]) == 'undefined') {
6608 ret[f.getName()] = ''; // empty..
6611 if (!f.el.dom.checked) {
6619 // not sure if this supported any more..
6620 if ((typeof(v) == 'object') && f.getRawValue) {
6621 v = f.getRawValue() ; // dates..
6623 // combo boxes where name != hiddenName...
6624 if (f.name != f.getName()) {
6625 ret[f.name] = f.getRawValue();
6627 ret[f.getName()] = v;
6634 * Clears all invalid messages in this form.
6635 * @return {BasicForm} this
6637 clearInvalid : function(){
6638 var items = this.getItems();
6640 items.each(function(f){
6651 * @return {BasicForm} this
6654 var items = this.getItems();
6655 items.each(function(f){
6659 Roo.each(this.childForms || [], function (f) {
6666 getItems : function()
6668 var r=new Roo.util.MixedCollection(false, function(o){
6669 return o.id || (o.id = Roo.id());
6671 var iter = function(el) {
6678 Roo.each(el.items,function(e) {
6697 * Ext JS Library 1.1.1
6698 * Copyright(c) 2006-2007, Ext JS, LLC.
6700 * Originally Released Under LGPL - original licence link has changed is not relivant.
6703 * <script type="text/javascript">
6706 * @class Roo.form.VTypes
6707 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6710 Roo.form.VTypes = function(){
6711 // closure these in so they are only created once.
6712 var alpha = /^[a-zA-Z_]+$/;
6713 var alphanum = /^[a-zA-Z0-9_]+$/;
6714 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6715 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6717 // All these messages and functions are configurable
6720 * The function used to validate email addresses
6721 * @param {String} value The email address
6723 'email' : function(v){
6724 return email.test(v);
6727 * The error text to display when the email validation function returns false
6730 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6732 * The keystroke filter mask to be applied on email input
6735 'emailMask' : /[a-z0-9_\.\-@]/i,
6738 * The function used to validate URLs
6739 * @param {String} value The URL
6741 'url' : function(v){
6745 * The error text to display when the url validation function returns false
6748 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6751 * The function used to validate alpha values
6752 * @param {String} value The value
6754 'alpha' : function(v){
6755 return alpha.test(v);
6758 * The error text to display when the alpha validation function returns false
6761 'alphaText' : 'This field should only contain letters and _',
6763 * The keystroke filter mask to be applied on alpha input
6766 'alphaMask' : /[a-z_]/i,
6769 * The function used to validate alphanumeric values
6770 * @param {String} value The value
6772 'alphanum' : function(v){
6773 return alphanum.test(v);
6776 * The error text to display when the alphanumeric validation function returns false
6779 'alphanumText' : 'This field should only contain letters, numbers and _',
6781 * The keystroke filter mask to be applied on alphanumeric input
6784 'alphanumMask' : /[a-z0-9_]/i
6794 * @class Roo.bootstrap.Input
6795 * @extends Roo.bootstrap.Component
6796 * Bootstrap Input class
6797 * @cfg {Boolean} disabled is it disabled
6798 * @cfg {String} fieldLabel - the label associated
6799 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6800 * @cfg {String} name name of the input
6801 * @cfg {string} fieldLabel - the label associated
6802 * @cfg {string} inputType - input / file submit ...
6803 * @cfg {string} placeholder - placeholder to put in text.
6804 * @cfg {string} before - input group add on before
6805 * @cfg {string} after - input group add on after
6806 * @cfg {string} size - (lg|sm) or leave empty..
6807 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6808 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6809 * @cfg {Number} md colspan out of 12 for computer-sized screens
6810 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6811 * @cfg {string} value default value of the input
6812 * @cfg {Number} labelWidth set the width of label (0-12)
6813 * @cfg {String} labelAlign (top|left)
6814 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6815 * @cfg {String} align (left|center|right) Default left
6819 * Create a new Input
6820 * @param {Object} config The config object
6823 Roo.bootstrap.Input = function(config){
6824 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6829 * Fires when this field receives input focus.
6830 * @param {Roo.form.Field} this
6835 * Fires when this field loses input focus.
6836 * @param {Roo.form.Field} this
6841 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6842 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6843 * @param {Roo.form.Field} this
6844 * @param {Roo.EventObject} e The event object
6849 * Fires just before the field blurs if the field value has changed.
6850 * @param {Roo.form.Field} this
6851 * @param {Mixed} newValue The new value
6852 * @param {Mixed} oldValue The original value
6857 * Fires after the field has been marked as invalid.
6858 * @param {Roo.form.Field} this
6859 * @param {String} msg The validation message
6864 * Fires after the field has been validated with no errors.
6865 * @param {Roo.form.Field} this
6870 * Fires after the key up
6871 * @param {Roo.form.Field} this
6872 * @param {Roo.EventObject} e The event Object
6878 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6880 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6881 automatic validation (defaults to "keyup").
6883 validationEvent : "keyup",
6885 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6887 validateOnBlur : true,
6889 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6891 validationDelay : 250,
6893 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6895 focusClass : "x-form-focus", // not needed???
6899 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6901 invalidClass : "has-error",
6904 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6906 selectOnFocus : false,
6909 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6913 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6918 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6920 disableKeyFilter : false,
6923 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6927 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6931 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6933 blankText : "This field is required",
6936 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6940 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6942 maxLength : Number.MAX_VALUE,
6944 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6946 minLengthText : "The minimum length for this field is {0}",
6948 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6950 maxLengthText : "The maximum length for this field is {0}",
6954 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6955 * If available, this function will be called only after the basic validators all return true, and will be passed the
6956 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6960 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6961 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6962 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6966 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6989 formatedValue : false,
6991 parentLabelAlign : function()
6994 while (parent.parent()) {
6995 parent = parent.parent();
6996 if (typeof(parent.labelAlign) !='undefined') {
6997 return parent.labelAlign;
7004 getAutoCreate : function(){
7006 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7012 if(this.inputType != 'hidden'){
7013 cfg.cls = 'form-group' //input-group
7019 type : this.inputType,
7021 cls : 'form-control',
7022 placeholder : this.placeholder || ''
7027 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7030 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7031 input.maxLength = this.maxLength;
7034 if (this.disabled) {
7035 input.disabled=true;
7038 if (this.readOnly) {
7039 input.readonly=true;
7043 input.name = this.name;
7046 input.cls += ' input-' + this.size;
7049 ['xs','sm','md','lg'].map(function(size){
7050 if (settings[size]) {
7051 cfg.cls += ' col-' + size + '-' + settings[size];
7055 var inputblock = input;
7057 if (this.before || this.after) {
7060 cls : 'input-group',
7063 if (this.before && typeof(this.before) == 'string') {
7065 inputblock.cn.push({
7067 cls : 'roo-input-before input-group-addon',
7071 if (this.before && typeof(this.before) == 'object') {
7072 this.before = Roo.factory(this.before);
7073 Roo.log(this.before);
7074 inputblock.cn.push({
7076 cls : 'roo-input-before input-group-' +
7077 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7081 inputblock.cn.push(input);
7083 if (this.after && typeof(this.after) == 'string') {
7084 inputblock.cn.push({
7086 cls : 'roo-input-after input-group-addon',
7090 if (this.after && typeof(this.after) == 'object') {
7091 this.after = Roo.factory(this.after);
7092 Roo.log(this.after);
7093 inputblock.cn.push({
7095 cls : 'roo-input-after input-group-' +
7096 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7101 if (align ==='left' && this.fieldLabel.length) {
7102 Roo.log("left and has label");
7108 cls : 'control-label col-sm-' + this.labelWidth,
7109 html : this.fieldLabel
7113 cls : "col-sm-" + (12 - this.labelWidth),
7120 } else if ( this.fieldLabel.length) {
7126 //cls : 'input-group-addon',
7127 html : this.fieldLabel
7137 Roo.log(" no label && no align");
7146 Roo.log('input-parentType: ' + this.parentType);
7148 if (this.parentType === 'Navbar' && this.parent().bar) {
7149 cfg.cls += ' navbar-form';
7157 * return the real input element.
7159 inputEl: function ()
7161 return this.el.select('input.form-control',true).first();
7163 setDisabled : function(v)
7165 var i = this.inputEl().dom;
7167 i.removeAttribute('disabled');
7171 i.setAttribute('disabled','true');
7173 initEvents : function()
7176 this.inputEl().on("keydown" , this.fireKey, this);
7177 this.inputEl().on("focus", this.onFocus, this);
7178 this.inputEl().on("blur", this.onBlur, this);
7180 this.inputEl().relayEvent('keyup', this);
7182 // reference to original value for reset
7183 this.originalValue = this.getValue();
7184 //Roo.form.TextField.superclass.initEvents.call(this);
7185 if(this.validationEvent == 'keyup'){
7186 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7187 this.inputEl().on('keyup', this.filterValidation, this);
7189 else if(this.validationEvent !== false){
7190 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7193 if(this.selectOnFocus){
7194 this.on("focus", this.preFocus, this);
7197 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7198 this.inputEl().on("keypress", this.filterKeys, this);
7201 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7202 this.el.on("click", this.autoSize, this);
7205 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7206 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7209 if (typeof(this.before) == 'object') {
7210 this.before.render(this.el.select('.roo-input-before',true).first());
7212 if (typeof(this.after) == 'object') {
7213 this.after.render(this.el.select('.roo-input-after',true).first());
7218 filterValidation : function(e){
7219 if(!e.isNavKeyPress()){
7220 this.validationTask.delay(this.validationDelay);
7224 * Validates the field value
7225 * @return {Boolean} True if the value is valid, else false
7227 validate : function(){
7228 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7229 if(this.disabled || this.validateValue(this.getRawValue())){
7230 this.clearInvalid();
7238 * Validates a value according to the field's validation rules and marks the field as invalid
7239 * if the validation fails
7240 * @param {Mixed} value The value to validate
7241 * @return {Boolean} True if the value is valid, else false
7243 validateValue : function(value){
7244 if(value.length < 1) { // if it's blank
7245 if(this.allowBlank){
7246 this.clearInvalid();
7249 this.markInvalid(this.blankText);
7253 if(value.length < this.minLength){
7254 this.markInvalid(String.format(this.minLengthText, this.minLength));
7257 if(value.length > this.maxLength){
7258 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7262 var vt = Roo.form.VTypes;
7263 if(!vt[this.vtype](value, this)){
7264 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7268 if(typeof this.validator == "function"){
7269 var msg = this.validator(value);
7271 this.markInvalid(msg);
7275 if(this.regex && !this.regex.test(value)){
7276 this.markInvalid(this.regexText);
7285 fireKey : function(e){
7286 //Roo.log('field ' + e.getKey());
7287 if(e.isNavKeyPress()){
7288 this.fireEvent("specialkey", this, e);
7291 focus : function (selectText){
7293 this.inputEl().focus();
7294 if(selectText === true){
7295 this.inputEl().dom.select();
7301 onFocus : function(){
7302 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7303 // this.el.addClass(this.focusClass);
7306 this.hasFocus = true;
7307 this.startValue = this.getValue();
7308 this.fireEvent("focus", this);
7312 beforeBlur : Roo.emptyFn,
7316 onBlur : function(){
7318 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7319 //this.el.removeClass(this.focusClass);
7321 this.hasFocus = false;
7322 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7325 var v = this.getValue();
7326 if(String(v) !== String(this.startValue)){
7327 this.fireEvent('change', this, v, this.startValue);
7329 this.fireEvent("blur", this);
7333 * Resets the current field value to the originally loaded value and clears any validation messages
7336 this.setValue(this.originalValue);
7337 this.clearInvalid();
7340 * Returns the name of the field
7341 * @return {Mixed} name The name field
7343 getName: function(){
7347 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7348 * @return {Mixed} value The field value
7350 getValue : function(){
7352 var v = this.inputEl().getValue();
7357 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7358 * @return {Mixed} value The field value
7360 getRawValue : function(){
7361 var v = this.inputEl().getValue();
7367 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7368 * @param {Mixed} value The value to set
7370 setRawValue : function(v){
7371 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7374 selectText : function(start, end){
7375 var v = this.getRawValue();
7377 start = start === undefined ? 0 : start;
7378 end = end === undefined ? v.length : end;
7379 var d = this.inputEl().dom;
7380 if(d.setSelectionRange){
7381 d.setSelectionRange(start, end);
7382 }else if(d.createTextRange){
7383 var range = d.createTextRange();
7384 range.moveStart("character", start);
7385 range.moveEnd("character", v.length-end);
7392 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7393 * @param {Mixed} value The value to set
7395 setValue : function(v){
7398 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7404 processValue : function(value){
7405 if(this.stripCharsRe){
7406 var newValue = value.replace(this.stripCharsRe, '');
7407 if(newValue !== value){
7408 this.setRawValue(newValue);
7415 preFocus : function(){
7417 if(this.selectOnFocus){
7418 this.inputEl().dom.select();
7421 filterKeys : function(e){
7423 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7426 var c = e.getCharCode(), cc = String.fromCharCode(c);
7427 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7430 if(!this.maskRe.test(cc)){
7435 * Clear any invalid styles/messages for this field
7437 clearInvalid : function(){
7439 if(!this.el || this.preventMark){ // not rendered
7442 this.el.removeClass(this.invalidClass);
7444 switch(this.msgTarget){
7446 this.el.dom.qtip = '';
7449 this.el.dom.title = '';
7453 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7458 this.errorIcon.dom.qtip = '';
7459 this.errorIcon.hide();
7460 this.un('resize', this.alignErrorIcon, this);
7464 var t = Roo.getDom(this.msgTarget);
7466 t.style.display = 'none';
7470 this.fireEvent('valid', this);
7473 * Mark this field as invalid
7474 * @param {String} msg The validation message
7476 markInvalid : function(msg){
7477 if(!this.el || this.preventMark){ // not rendered
7480 this.el.addClass(this.invalidClass);
7482 msg = msg || this.invalidText;
7483 switch(this.msgTarget){
7485 this.el.dom.qtip = msg;
7486 this.el.dom.qclass = 'x-form-invalid-tip';
7487 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7488 Roo.QuickTips.enable();
7492 this.el.dom.title = msg;
7496 var elp = this.el.findParent('.x-form-element', 5, true);
7497 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7498 this.errorEl.setWidth(elp.getWidth(true)-20);
7500 this.errorEl.update(msg);
7501 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7504 if(!this.errorIcon){
7505 var elp = this.el.findParent('.x-form-element', 5, true);
7506 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7508 this.alignErrorIcon();
7509 this.errorIcon.dom.qtip = msg;
7510 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7511 this.errorIcon.show();
7512 this.on('resize', this.alignErrorIcon, this);
7515 var t = Roo.getDom(this.msgTarget);
7517 t.style.display = this.msgDisplay;
7521 this.fireEvent('invalid', this, msg);
7524 SafariOnKeyDown : function(event)
7526 // this is a workaround for a password hang bug on chrome/ webkit.
7528 var isSelectAll = false;
7530 if(this.inputEl().dom.selectionEnd > 0){
7531 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7533 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7534 event.preventDefault();
7539 if(isSelectAll){ // backspace and delete key
7541 event.preventDefault();
7542 // this is very hacky as keydown always get's upper case.
7544 var cc = String.fromCharCode(event.getCharCode());
7545 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7549 adjustWidth : function(tag, w){
7550 tag = tag.toLowerCase();
7551 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7552 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7556 if(tag == 'textarea'){
7559 }else if(Roo.isOpera){
7563 if(tag == 'textarea'){
7582 * @class Roo.bootstrap.TextArea
7583 * @extends Roo.bootstrap.Input
7584 * Bootstrap TextArea class
7585 * @cfg {Number} cols Specifies the visible width of a text area
7586 * @cfg {Number} rows Specifies the visible number of lines in a text area
7587 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7588 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7589 * @cfg {string} html text
7592 * Create a new TextArea
7593 * @param {Object} config The config object
7596 Roo.bootstrap.TextArea = function(config){
7597 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7601 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7611 getAutoCreate : function(){
7613 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7624 value : this.value || '',
7625 html: this.html || '',
7626 cls : 'form-control',
7627 placeholder : this.placeholder || ''
7631 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7632 input.maxLength = this.maxLength;
7636 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7640 input.cols = this.cols;
7643 if (this.readOnly) {
7644 input.readonly = true;
7648 input.name = this.name;
7652 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7656 ['xs','sm','md','lg'].map(function(size){
7657 if (settings[size]) {
7658 cfg.cls += ' col-' + size + '-' + settings[size];
7662 var inputblock = input;
7664 if (this.before || this.after) {
7667 cls : 'input-group',
7671 inputblock.cn.push({
7673 cls : 'input-group-addon',
7677 inputblock.cn.push(input);
7679 inputblock.cn.push({
7681 cls : 'input-group-addon',
7688 if (align ==='left' && this.fieldLabel.length) {
7689 Roo.log("left and has label");
7695 cls : 'control-label col-sm-' + this.labelWidth,
7696 html : this.fieldLabel
7700 cls : "col-sm-" + (12 - this.labelWidth),
7707 } else if ( this.fieldLabel.length) {
7713 //cls : 'input-group-addon',
7714 html : this.fieldLabel
7724 Roo.log(" no label && no align");
7734 if (this.disabled) {
7735 input.disabled=true;
7742 * return the real textarea element.
7744 inputEl: function ()
7746 return this.el.select('textarea.form-control',true).first();
7754 * trigger field - base class for combo..
7759 * @class Roo.bootstrap.TriggerField
7760 * @extends Roo.bootstrap.Input
7761 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7762 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7763 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7764 * for which you can provide a custom implementation. For example:
7766 var trigger = new Roo.bootstrap.TriggerField();
7767 trigger.onTriggerClick = myTriggerFn;
7768 trigger.applyTo('my-field');
7771 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7772 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7773 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7774 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7776 * Create a new TriggerField.
7777 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7778 * to the base TextField)
7780 Roo.bootstrap.TriggerField = function(config){
7781 this.mimicing = false;
7782 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7785 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7787 * @cfg {String} triggerClass A CSS class to apply to the trigger
7790 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7794 /** @cfg {Boolean} grow @hide */
7795 /** @cfg {Number} growMin @hide */
7796 /** @cfg {Number} growMax @hide */
7802 autoSize: Roo.emptyFn,
7809 actionMode : 'wrap',
7813 getAutoCreate : function(){
7815 var align = this.labelAlign || this.parentLabelAlign();
7820 cls: 'form-group' //input-group
7827 type : this.inputType,
7828 cls : 'form-control',
7829 autocomplete: 'off',
7830 placeholder : this.placeholder || ''
7834 input.name = this.name;
7837 input.cls += ' input-' + this.size;
7840 if (this.disabled) {
7841 input.disabled=true;
7844 var inputblock = input;
7846 if (this.before || this.after) {
7849 cls : 'input-group',
7853 inputblock.cn.push({
7855 cls : 'input-group-addon',
7859 inputblock.cn.push(input);
7861 inputblock.cn.push({
7863 cls : 'input-group-addon',
7876 cls: 'form-hidden-field'
7884 Roo.log('multiple');
7892 cls: 'form-hidden-field'
7896 cls: 'select2-choices',
7900 cls: 'select2-search-field',
7913 cls: 'select2-container input-group',
7918 // cls: 'typeahead typeahead-long dropdown-menu',
7919 // style: 'display:none'
7924 if(!this.multiple && this.showToggleBtn){
7927 cls : 'input-group-addon btn dropdown-toggle',
7935 cls: 'combobox-clear',
7949 combobox.cls += ' select2-container-multi';
7952 if (align ==='left' && this.fieldLabel.length) {
7954 Roo.log("left and has label");
7960 cls : 'control-label col-sm-' + this.labelWidth,
7961 html : this.fieldLabel
7965 cls : "col-sm-" + (12 - this.labelWidth),
7972 } else if ( this.fieldLabel.length) {
7978 //cls : 'input-group-addon',
7979 html : this.fieldLabel
7989 Roo.log(" no label && no align");
7996 ['xs','sm','md','lg'].map(function(size){
7997 if (settings[size]) {
7998 cfg.cls += ' col-' + size + '-' + settings[size];
8009 onResize : function(w, h){
8010 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8011 // if(typeof w == 'number'){
8012 // var x = w - this.trigger.getWidth();
8013 // this.inputEl().setWidth(this.adjustWidth('input', x));
8014 // this.trigger.setStyle('left', x+'px');
8019 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8022 getResizeEl : function(){
8023 return this.inputEl();
8027 getPositionEl : function(){
8028 return this.inputEl();
8032 alignErrorIcon : function(){
8033 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8037 initEvents : function(){
8041 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8042 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8043 if(!this.multiple && this.showToggleBtn){
8044 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8045 if(this.hideTrigger){
8046 this.trigger.setDisplayed(false);
8048 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8052 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8055 //this.trigger.addClassOnOver('x-form-trigger-over');
8056 //this.trigger.addClassOnClick('x-form-trigger-click');
8059 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8063 createList : function()
8065 this.list = Roo.get(document.body).createChild({
8067 cls: 'typeahead typeahead-long dropdown-menu',
8068 style: 'display:none'
8071 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8076 initTrigger : function(){
8081 onDestroy : function(){
8083 this.trigger.removeAllListeners();
8084 // this.trigger.remove();
8087 // this.wrap.remove();
8089 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8093 onFocus : function(){
8094 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8097 this.wrap.addClass('x-trigger-wrap-focus');
8098 this.mimicing = true;
8099 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8100 if(this.monitorTab){
8101 this.el.on("keydown", this.checkTab, this);
8108 checkTab : function(e){
8109 if(e.getKey() == e.TAB){
8115 onBlur : function(){
8120 mimicBlur : function(e, t){
8122 if(!this.wrap.contains(t) && this.validateBlur()){
8129 triggerBlur : function(){
8130 this.mimicing = false;
8131 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8132 if(this.monitorTab){
8133 this.el.un("keydown", this.checkTab, this);
8135 //this.wrap.removeClass('x-trigger-wrap-focus');
8136 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8140 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8141 validateBlur : function(e, t){
8146 onDisable : function(){
8147 this.inputEl().dom.disabled = true;
8148 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8150 // this.wrap.addClass('x-item-disabled');
8155 onEnable : function(){
8156 this.inputEl().dom.disabled = false;
8157 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8159 // this.el.removeClass('x-item-disabled');
8164 onShow : function(){
8165 var ae = this.getActionEl();
8168 ae.dom.style.display = '';
8169 ae.dom.style.visibility = 'visible';
8175 onHide : function(){
8176 var ae = this.getActionEl();
8177 ae.dom.style.display = 'none';
8181 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8182 * by an implementing function.
8184 * @param {EventObject} e
8186 onTriggerClick : Roo.emptyFn
8190 * Ext JS Library 1.1.1
8191 * Copyright(c) 2006-2007, Ext JS, LLC.
8193 * Originally Released Under LGPL - original licence link has changed is not relivant.
8196 * <script type="text/javascript">
8201 * @class Roo.data.SortTypes
8203 * Defines the default sorting (casting?) comparison functions used when sorting data.
8205 Roo.data.SortTypes = {
8207 * Default sort that does nothing
8208 * @param {Mixed} s The value being converted
8209 * @return {Mixed} The comparison value
8216 * The regular expression used to strip tags
8220 stripTagsRE : /<\/?[^>]+>/gi,
8223 * Strips all HTML tags to sort on text only
8224 * @param {Mixed} s The value being converted
8225 * @return {String} The comparison value
8227 asText : function(s){
8228 return String(s).replace(this.stripTagsRE, "");
8232 * Strips all HTML tags to sort on text only - Case insensitive
8233 * @param {Mixed} s The value being converted
8234 * @return {String} The comparison value
8236 asUCText : function(s){
8237 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8241 * Case insensitive string
8242 * @param {Mixed} s The value being converted
8243 * @return {String} The comparison value
8245 asUCString : function(s) {
8246 return String(s).toUpperCase();
8251 * @param {Mixed} s The value being converted
8252 * @return {Number} The comparison value
8254 asDate : function(s) {
8258 if(s instanceof Date){
8261 return Date.parse(String(s));
8266 * @param {Mixed} s The value being converted
8267 * @return {Float} The comparison value
8269 asFloat : function(s) {
8270 var val = parseFloat(String(s).replace(/,/g, ""));
8271 if(isNaN(val)) val = 0;
8277 * @param {Mixed} s The value being converted
8278 * @return {Number} The comparison value
8280 asInt : function(s) {
8281 var val = parseInt(String(s).replace(/,/g, ""));
8282 if(isNaN(val)) val = 0;
8287 * Ext JS Library 1.1.1
8288 * Copyright(c) 2006-2007, Ext JS, LLC.
8290 * Originally Released Under LGPL - original licence link has changed is not relivant.
8293 * <script type="text/javascript">
8297 * @class Roo.data.Record
8298 * Instances of this class encapsulate both record <em>definition</em> information, and record
8299 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8300 * to access Records cached in an {@link Roo.data.Store} object.<br>
8302 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8303 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8306 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8308 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8309 * {@link #create}. The parameters are the same.
8310 * @param {Array} data An associative Array of data values keyed by the field name.
8311 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8312 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8313 * not specified an integer id is generated.
8315 Roo.data.Record = function(data, id){
8316 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8321 * Generate a constructor for a specific record layout.
8322 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8323 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8324 * Each field definition object may contain the following properties: <ul>
8325 * <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,
8326 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8327 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8328 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8329 * is being used, then this is a string containing the javascript expression to reference the data relative to
8330 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8331 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8332 * this may be omitted.</p></li>
8333 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8334 * <ul><li>auto (Default, implies no conversion)</li>
8339 * <li>date</li></ul></p></li>
8340 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8341 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8342 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8343 * by the Reader into an object that will be stored in the Record. It is passed the
8344 * following parameters:<ul>
8345 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8347 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8349 * <br>usage:<br><pre><code>
8350 var TopicRecord = Roo.data.Record.create(
8351 {name: 'title', mapping: 'topic_title'},
8352 {name: 'author', mapping: 'username'},
8353 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8354 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8355 {name: 'lastPoster', mapping: 'user2'},
8356 {name: 'excerpt', mapping: 'post_text'}
8359 var myNewRecord = new TopicRecord({
8360 title: 'Do my job please',
8363 lastPost: new Date(),
8364 lastPoster: 'Animal',
8365 excerpt: 'No way dude!'
8367 myStore.add(myNewRecord);
8372 Roo.data.Record.create = function(o){
8374 f.superclass.constructor.apply(this, arguments);
8376 Roo.extend(f, Roo.data.Record);
8377 var p = f.prototype;
8378 p.fields = new Roo.util.MixedCollection(false, function(field){
8381 for(var i = 0, len = o.length; i < len; i++){
8382 p.fields.add(new Roo.data.Field(o[i]));
8384 f.getField = function(name){
8385 return p.fields.get(name);
8390 Roo.data.Record.AUTO_ID = 1000;
8391 Roo.data.Record.EDIT = 'edit';
8392 Roo.data.Record.REJECT = 'reject';
8393 Roo.data.Record.COMMIT = 'commit';
8395 Roo.data.Record.prototype = {
8397 * Readonly flag - true if this record has been modified.
8406 join : function(store){
8411 * Set the named field to the specified value.
8412 * @param {String} name The name of the field to set.
8413 * @param {Object} value The value to set the field to.
8415 set : function(name, value){
8416 if(this.data[name] == value){
8423 if(typeof this.modified[name] == 'undefined'){
8424 this.modified[name] = this.data[name];
8426 this.data[name] = value;
8427 if(!this.editing && this.store){
8428 this.store.afterEdit(this);
8433 * Get the value of the named field.
8434 * @param {String} name The name of the field to get the value of.
8435 * @return {Object} The value of the field.
8437 get : function(name){
8438 return this.data[name];
8442 beginEdit : function(){
8443 this.editing = true;
8448 cancelEdit : function(){
8449 this.editing = false;
8450 delete this.modified;
8454 endEdit : function(){
8455 this.editing = false;
8456 if(this.dirty && this.store){
8457 this.store.afterEdit(this);
8462 * Usually called by the {@link Roo.data.Store} which owns the Record.
8463 * Rejects all changes made to the Record since either creation, or the last commit operation.
8464 * Modified fields are reverted to their original values.
8466 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8467 * of reject operations.
8469 reject : function(){
8470 var m = this.modified;
8472 if(typeof m[n] != "function"){
8473 this.data[n] = m[n];
8477 delete this.modified;
8478 this.editing = false;
8480 this.store.afterReject(this);
8485 * Usually called by the {@link Roo.data.Store} which owns the Record.
8486 * Commits all changes made to the Record since either creation, or the last commit operation.
8488 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8489 * of commit operations.
8491 commit : function(){
8493 delete this.modified;
8494 this.editing = false;
8496 this.store.afterCommit(this);
8501 hasError : function(){
8502 return this.error != null;
8506 clearError : function(){
8511 * Creates a copy of this record.
8512 * @param {String} id (optional) A new record id if you don't want to use this record's id
8515 copy : function(newId) {
8516 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8520 * Ext JS Library 1.1.1
8521 * Copyright(c) 2006-2007, Ext JS, LLC.
8523 * Originally Released Under LGPL - original licence link has changed is not relivant.
8526 * <script type="text/javascript">
8532 * @class Roo.data.Store
8533 * @extends Roo.util.Observable
8534 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8535 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8537 * 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
8538 * has no knowledge of the format of the data returned by the Proxy.<br>
8540 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8541 * instances from the data object. These records are cached and made available through accessor functions.
8543 * Creates a new Store.
8544 * @param {Object} config A config object containing the objects needed for the Store to access data,
8545 * and read the data into Records.
8547 Roo.data.Store = function(config){
8548 this.data = new Roo.util.MixedCollection(false);
8549 this.data.getKey = function(o){
8552 this.baseParams = {};
8559 "multisort" : "_multisort"
8562 if(config && config.data){
8563 this.inlineData = config.data;
8567 Roo.apply(this, config);
8569 if(this.reader){ // reader passed
8570 this.reader = Roo.factory(this.reader, Roo.data);
8571 this.reader.xmodule = this.xmodule || false;
8572 if(!this.recordType){
8573 this.recordType = this.reader.recordType;
8575 if(this.reader.onMetaChange){
8576 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8580 if(this.recordType){
8581 this.fields = this.recordType.prototype.fields;
8587 * @event datachanged
8588 * Fires when the data cache has changed, and a widget which is using this Store
8589 * as a Record cache should refresh its view.
8590 * @param {Store} this
8595 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8596 * @param {Store} this
8597 * @param {Object} meta The JSON metadata
8602 * Fires when Records have been added to the Store
8603 * @param {Store} this
8604 * @param {Roo.data.Record[]} records The array of Records added
8605 * @param {Number} index The index at which the record(s) were added
8610 * Fires when a Record has been removed from the Store
8611 * @param {Store} this
8612 * @param {Roo.data.Record} record The Record that was removed
8613 * @param {Number} index The index at which the record was removed
8618 * Fires when a Record has been updated
8619 * @param {Store} this
8620 * @param {Roo.data.Record} record The Record that was updated
8621 * @param {String} operation The update operation being performed. Value may be one of:
8623 Roo.data.Record.EDIT
8624 Roo.data.Record.REJECT
8625 Roo.data.Record.COMMIT
8631 * Fires when the data cache has been cleared.
8632 * @param {Store} this
8637 * Fires before a request is made for a new data object. If the beforeload handler returns false
8638 * the load action will be canceled.
8639 * @param {Store} this
8640 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8644 * @event beforeloadadd
8645 * Fires after a new set of Records has been loaded.
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)
8650 beforeloadadd : true,
8653 * Fires after a new set of Records has been loaded, before they are added to the store.
8654 * @param {Store} this
8655 * @param {Roo.data.Record[]} records The Records that were loaded
8656 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8657 * @params {Object} return from reader
8661 * @event loadexception
8662 * Fires if an exception occurs in the Proxy during loading.
8663 * Called with the signature of the Proxy's "loadexception" event.
8664 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8667 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8668 * @param {Object} load options
8669 * @param {Object} jsonData from your request (normally this contains the Exception)
8671 loadexception : true
8675 this.proxy = Roo.factory(this.proxy, Roo.data);
8676 this.proxy.xmodule = this.xmodule || false;
8677 this.relayEvents(this.proxy, ["loadexception"]);
8679 this.sortToggle = {};
8680 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8682 Roo.data.Store.superclass.constructor.call(this);
8684 if(this.inlineData){
8685 this.loadData(this.inlineData);
8686 delete this.inlineData;
8690 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8692 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8693 * without a remote query - used by combo/forms at present.
8697 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8700 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8703 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8704 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8707 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8708 * on any HTTP request
8711 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8714 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8718 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8719 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8724 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8725 * loaded or when a record is removed. (defaults to false).
8727 pruneModifiedRecords : false,
8733 * Add Records to the Store and fires the add event.
8734 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8736 add : function(records){
8737 records = [].concat(records);
8738 for(var i = 0, len = records.length; i < len; i++){
8739 records[i].join(this);
8741 var index = this.data.length;
8742 this.data.addAll(records);
8743 this.fireEvent("add", this, records, index);
8747 * Remove a Record from the Store and fires the remove event.
8748 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8750 remove : function(record){
8751 var index = this.data.indexOf(record);
8752 this.data.removeAt(index);
8753 if(this.pruneModifiedRecords){
8754 this.modified.remove(record);
8756 this.fireEvent("remove", this, record, index);
8760 * Remove all Records from the Store and fires the clear event.
8762 removeAll : function(){
8764 if(this.pruneModifiedRecords){
8767 this.fireEvent("clear", this);
8771 * Inserts Records to the Store at the given index and fires the add event.
8772 * @param {Number} index The start index at which to insert the passed Records.
8773 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8775 insert : function(index, records){
8776 records = [].concat(records);
8777 for(var i = 0, len = records.length; i < len; i++){
8778 this.data.insert(index, records[i]);
8779 records[i].join(this);
8781 this.fireEvent("add", this, records, index);
8785 * Get the index within the cache of the passed Record.
8786 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8787 * @return {Number} The index of the passed Record. Returns -1 if not found.
8789 indexOf : function(record){
8790 return this.data.indexOf(record);
8794 * Get the index within the cache of the Record with the passed id.
8795 * @param {String} id The id of the Record to find.
8796 * @return {Number} The index of the Record. Returns -1 if not found.
8798 indexOfId : function(id){
8799 return this.data.indexOfKey(id);
8803 * Get the Record with the specified id.
8804 * @param {String} id The id of the Record to find.
8805 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8807 getById : function(id){
8808 return this.data.key(id);
8812 * Get the Record at the specified index.
8813 * @param {Number} index The index of the Record to find.
8814 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8816 getAt : function(index){
8817 return this.data.itemAt(index);
8821 * Returns a range of Records between specified indices.
8822 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8823 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8824 * @return {Roo.data.Record[]} An array of Records
8826 getRange : function(start, end){
8827 return this.data.getRange(start, end);
8831 storeOptions : function(o){
8832 o = Roo.apply({}, o);
8835 this.lastOptions = o;
8839 * Loads the Record cache from the configured Proxy using the configured Reader.
8841 * If using remote paging, then the first load call must specify the <em>start</em>
8842 * and <em>limit</em> properties in the options.params property to establish the initial
8843 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8845 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8846 * and this call will return before the new data has been loaded. Perform any post-processing
8847 * in a callback function, or in a "load" event handler.</strong>
8849 * @param {Object} options An object containing properties which control loading options:<ul>
8850 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8851 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8852 * passed the following arguments:<ul>
8853 * <li>r : Roo.data.Record[]</li>
8854 * <li>options: Options object from the load call</li>
8855 * <li>success: Boolean success indicator</li></ul></li>
8856 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8857 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8860 load : function(options){
8861 options = options || {};
8862 if(this.fireEvent("beforeload", this, options) !== false){
8863 this.storeOptions(options);
8864 var p = Roo.apply(options.params || {}, this.baseParams);
8865 // if meta was not loaded from remote source.. try requesting it.
8866 if (!this.reader.metaFromRemote) {
8869 if(this.sortInfo && this.remoteSort){
8870 var pn = this.paramNames;
8871 p[pn["sort"]] = this.sortInfo.field;
8872 p[pn["dir"]] = this.sortInfo.direction;
8874 if (this.multiSort) {
8875 var pn = this.paramNames;
8876 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8879 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8884 * Reloads the Record cache from the configured Proxy using the configured Reader and
8885 * the options from the last load operation performed.
8886 * @param {Object} options (optional) An object containing properties which may override the options
8887 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8888 * the most recently used options are reused).
8890 reload : function(options){
8891 this.load(Roo.applyIf(options||{}, this.lastOptions));
8895 // Called as a callback by the Reader during a load operation.
8896 loadRecords : function(o, options, success){
8897 if(!o || success === false){
8898 if(success !== false){
8899 this.fireEvent("load", this, [], options, o);
8901 if(options.callback){
8902 options.callback.call(options.scope || this, [], options, false);
8906 // if data returned failure - throw an exception.
8907 if (o.success === false) {
8908 // show a message if no listener is registered.
8909 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8910 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8912 // loadmask wil be hooked into this..
8913 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8916 var r = o.records, t = o.totalRecords || r.length;
8918 this.fireEvent("beforeloadadd", this, r, options, o);
8920 if(!options || options.add !== true){
8921 if(this.pruneModifiedRecords){
8924 for(var i = 0, len = r.length; i < len; i++){
8928 this.data = this.snapshot;
8929 delete this.snapshot;
8932 this.data.addAll(r);
8933 this.totalLength = t;
8935 this.fireEvent("datachanged", this);
8937 this.totalLength = Math.max(t, this.data.length+r.length);
8940 this.fireEvent("load", this, r, options, o);
8941 if(options.callback){
8942 options.callback.call(options.scope || this, r, options, true);
8948 * Loads data from a passed data block. A Reader which understands the format of the data
8949 * must have been configured in the constructor.
8950 * @param {Object} data The data block from which to read the Records. The format of the data expected
8951 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8952 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8954 loadData : function(o, append){
8955 var r = this.reader.readRecords(o);
8956 this.loadRecords(r, {add: append}, true);
8960 * Gets the number of cached records.
8962 * <em>If using paging, this may not be the total size of the dataset. If the data object
8963 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8964 * the data set size</em>
8966 getCount : function(){
8967 return this.data.length || 0;
8971 * Gets the total number of records in the dataset as returned by the server.
8973 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8974 * the dataset size</em>
8976 getTotalCount : function(){
8977 return this.totalLength || 0;
8981 * Returns the sort state of the Store as an object with two properties:
8983 field {String} The name of the field by which the Records are sorted
8984 direction {String} The sort order, "ASC" or "DESC"
8987 getSortState : function(){
8988 return this.sortInfo;
8992 applySort : function(){
8993 if(this.sortInfo && !this.remoteSort){
8994 var s = this.sortInfo, f = s.field;
8995 var st = this.fields.get(f).sortType;
8996 var fn = function(r1, r2){
8997 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8998 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9000 this.data.sort(s.direction, fn);
9001 if(this.snapshot && this.snapshot != this.data){
9002 this.snapshot.sort(s.direction, fn);
9008 * Sets the default sort column and order to be used by the next load operation.
9009 * @param {String} fieldName The name of the field to sort by.
9010 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9012 setDefaultSort : function(field, dir){
9013 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9018 * If remote sorting is used, the sort is performed on the server, and the cache is
9019 * reloaded. If local sorting is used, the cache is sorted internally.
9020 * @param {String} fieldName The name of the field to sort by.
9021 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9023 sort : function(fieldName, dir){
9024 var f = this.fields.get(fieldName);
9026 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9028 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9029 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9034 this.sortToggle[f.name] = dir;
9035 this.sortInfo = {field: f.name, direction: dir};
9036 if(!this.remoteSort){
9038 this.fireEvent("datachanged", this);
9040 this.load(this.lastOptions);
9045 * Calls the specified function for each of the Records in the cache.
9046 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9047 * Returning <em>false</em> aborts and exits the iteration.
9048 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9050 each : function(fn, scope){
9051 this.data.each(fn, scope);
9055 * Gets all records modified since the last commit. Modified records are persisted across load operations
9056 * (e.g., during paging).
9057 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9059 getModifiedRecords : function(){
9060 return this.modified;
9064 createFilterFn : function(property, value, anyMatch){
9065 if(!value.exec){ // not a regex
9066 value = String(value);
9067 if(value.length == 0){
9070 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9073 return value.test(r.data[property]);
9078 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9079 * @param {String} property A field on your records
9080 * @param {Number} start The record index to start at (defaults to 0)
9081 * @param {Number} end The last record index to include (defaults to length - 1)
9082 * @return {Number} The sum
9084 sum : function(property, start, end){
9085 var rs = this.data.items, v = 0;
9087 end = (end || end === 0) ? end : rs.length-1;
9089 for(var i = start; i <= end; i++){
9090 v += (rs[i].data[property] || 0);
9096 * Filter the records by a specified property.
9097 * @param {String} field A field on your records
9098 * @param {String/RegExp} value Either a string that the field
9099 * should start with or a RegExp to test against the field
9100 * @param {Boolean} anyMatch True to match any part not just the beginning
9102 filter : function(property, value, anyMatch){
9103 var fn = this.createFilterFn(property, value, anyMatch);
9104 return fn ? this.filterBy(fn) : this.clearFilter();
9108 * Filter by a function. The specified function will be called with each
9109 * record in this data source. If the function returns true the record is included,
9110 * otherwise it is filtered.
9111 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9112 * @param {Object} scope (optional) The scope of the function (defaults to this)
9114 filterBy : function(fn, scope){
9115 this.snapshot = this.snapshot || this.data;
9116 this.data = this.queryBy(fn, scope||this);
9117 this.fireEvent("datachanged", this);
9121 * Query the records by a specified property.
9122 * @param {String} field A field on your records
9123 * @param {String/RegExp} value Either a string that the field
9124 * should start with or a RegExp to test against the field
9125 * @param {Boolean} anyMatch True to match any part not just the beginning
9126 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9128 query : function(property, value, anyMatch){
9129 var fn = this.createFilterFn(property, value, anyMatch);
9130 return fn ? this.queryBy(fn) : this.data.clone();
9134 * Query by a function. The specified function will be called with each
9135 * record in this data source. If the function returns true the record is included
9137 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9138 * @param {Object} scope (optional) The scope of the function (defaults to this)
9139 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9141 queryBy : function(fn, scope){
9142 var data = this.snapshot || this.data;
9143 return data.filterBy(fn, scope||this);
9147 * Collects unique values for a particular dataIndex from this store.
9148 * @param {String} dataIndex The property to collect
9149 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9150 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9151 * @return {Array} An array of the unique values
9153 collect : function(dataIndex, allowNull, bypassFilter){
9154 var d = (bypassFilter === true && this.snapshot) ?
9155 this.snapshot.items : this.data.items;
9156 var v, sv, r = [], l = {};
9157 for(var i = 0, len = d.length; i < len; i++){
9158 v = d[i].data[dataIndex];
9160 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9169 * Revert to a view of the Record cache with no filtering applied.
9170 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9172 clearFilter : function(suppressEvent){
9173 if(this.snapshot && this.snapshot != this.data){
9174 this.data = this.snapshot;
9175 delete this.snapshot;
9176 if(suppressEvent !== true){
9177 this.fireEvent("datachanged", this);
9183 afterEdit : function(record){
9184 if(this.modified.indexOf(record) == -1){
9185 this.modified.push(record);
9187 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9191 afterReject : function(record){
9192 this.modified.remove(record);
9193 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9197 afterCommit : function(record){
9198 this.modified.remove(record);
9199 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9203 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9204 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9206 commitChanges : function(){
9207 var m = this.modified.slice(0);
9209 for(var i = 0, len = m.length; i < len; i++){
9215 * Cancel outstanding changes on all changed records.
9217 rejectChanges : function(){
9218 var m = this.modified.slice(0);
9220 for(var i = 0, len = m.length; i < len; i++){
9225 onMetaChange : function(meta, rtype, o){
9226 this.recordType = rtype;
9227 this.fields = rtype.prototype.fields;
9228 delete this.snapshot;
9229 this.sortInfo = meta.sortInfo || this.sortInfo;
9231 this.fireEvent('metachange', this, this.reader.meta);
9234 moveIndex : function(data, type)
9236 var index = this.indexOf(data);
9238 var newIndex = index + type;
9242 this.insert(newIndex, data);
9247 * Ext JS Library 1.1.1
9248 * Copyright(c) 2006-2007, Ext JS, LLC.
9250 * Originally Released Under LGPL - original licence link has changed is not relivant.
9253 * <script type="text/javascript">
9257 * @class Roo.data.SimpleStore
9258 * @extends Roo.data.Store
9259 * Small helper class to make creating Stores from Array data easier.
9260 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9261 * @cfg {Array} fields An array of field definition objects, or field name strings.
9262 * @cfg {Array} data The multi-dimensional array of data
9264 * @param {Object} config
9266 Roo.data.SimpleStore = function(config){
9267 Roo.data.SimpleStore.superclass.constructor.call(this, {
9269 reader: new Roo.data.ArrayReader({
9272 Roo.data.Record.create(config.fields)
9274 proxy : new Roo.data.MemoryProxy(config.data)
9278 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9280 * Ext JS Library 1.1.1
9281 * Copyright(c) 2006-2007, Ext JS, LLC.
9283 * Originally Released Under LGPL - original licence link has changed is not relivant.
9286 * <script type="text/javascript">
9291 * @extends Roo.data.Store
9292 * @class Roo.data.JsonStore
9293 * Small helper class to make creating Stores for JSON data easier. <br/>
9295 var store = new Roo.data.JsonStore({
9296 url: 'get-images.php',
9298 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9301 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9302 * JsonReader and HttpProxy (unless inline data is provided).</b>
9303 * @cfg {Array} fields An array of field definition objects, or field name strings.
9305 * @param {Object} config
9307 Roo.data.JsonStore = function(c){
9308 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9309 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9310 reader: new Roo.data.JsonReader(c, c.fields)
9313 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9315 * Ext JS Library 1.1.1
9316 * Copyright(c) 2006-2007, Ext JS, LLC.
9318 * Originally Released Under LGPL - original licence link has changed is not relivant.
9321 * <script type="text/javascript">
9325 Roo.data.Field = function(config){
9326 if(typeof config == "string"){
9327 config = {name: config};
9329 Roo.apply(this, config);
9335 var st = Roo.data.SortTypes;
9336 // named sortTypes are supported, here we look them up
9337 if(typeof this.sortType == "string"){
9338 this.sortType = st[this.sortType];
9341 // set default sortType for strings and dates
9345 this.sortType = st.asUCString;
9348 this.sortType = st.asDate;
9351 this.sortType = st.none;
9356 var stripRe = /[\$,%]/g;
9358 // prebuilt conversion function for this field, instead of
9359 // switching every time we're reading a value
9361 var cv, dateFormat = this.dateFormat;
9366 cv = function(v){ return v; };
9369 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9373 return v !== undefined && v !== null && v !== '' ?
9374 parseInt(String(v).replace(stripRe, ""), 10) : '';
9379 return v !== undefined && v !== null && v !== '' ?
9380 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9385 cv = function(v){ return v === true || v === "true" || v == 1; };
9392 if(v instanceof Date){
9396 if(dateFormat == "timestamp"){
9397 return new Date(v*1000);
9399 return Date.parseDate(v, dateFormat);
9401 var parsed = Date.parse(v);
9402 return parsed ? new Date(parsed) : null;
9411 Roo.data.Field.prototype = {
9419 * Ext JS Library 1.1.1
9420 * Copyright(c) 2006-2007, Ext JS, LLC.
9422 * Originally Released Under LGPL - original licence link has changed is not relivant.
9425 * <script type="text/javascript">
9428 // Base class for reading structured data from a data source. This class is intended to be
9429 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9432 * @class Roo.data.DataReader
9433 * Base class for reading structured data from a data source. This class is intended to be
9434 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9437 Roo.data.DataReader = function(meta, recordType){
9441 this.recordType = recordType instanceof Array ?
9442 Roo.data.Record.create(recordType) : recordType;
9445 Roo.data.DataReader.prototype = {
9447 * Create an empty record
9448 * @param {Object} data (optional) - overlay some values
9449 * @return {Roo.data.Record} record created.
9451 newRow : function(d) {
9453 this.recordType.prototype.fields.each(function(c) {
9455 case 'int' : da[c.name] = 0; break;
9456 case 'date' : da[c.name] = new Date(); break;
9457 case 'float' : da[c.name] = 0.0; break;
9458 case 'boolean' : da[c.name] = false; break;
9459 default : da[c.name] = ""; break;
9463 return new this.recordType(Roo.apply(da, d));
9468 * Ext JS Library 1.1.1
9469 * Copyright(c) 2006-2007, Ext JS, LLC.
9471 * Originally Released Under LGPL - original licence link has changed is not relivant.
9474 * <script type="text/javascript">
9478 * @class Roo.data.DataProxy
9479 * @extends Roo.data.Observable
9480 * This class is an abstract base class for implementations which provide retrieval of
9481 * unformatted data objects.<br>
9483 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9484 * (of the appropriate type which knows how to parse the data object) to provide a block of
9485 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9487 * Custom implementations must implement the load method as described in
9488 * {@link Roo.data.HttpProxy#load}.
9490 Roo.data.DataProxy = function(){
9494 * Fires before a network request is made to retrieve a data object.
9495 * @param {Object} This DataProxy object.
9496 * @param {Object} params The params parameter to the load function.
9501 * Fires before the load method's callback is called.
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.
9508 * @event loadexception
9509 * Fires if an Exception occurs during data retrieval.
9510 * @param {Object} This DataProxy object.
9511 * @param {Object} o The data object.
9512 * @param {Object} arg The callback argument object passed to the load function.
9513 * @param {Object} e The Exception.
9515 loadexception : true
9517 Roo.data.DataProxy.superclass.constructor.call(this);
9520 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9523 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9527 * Ext JS Library 1.1.1
9528 * Copyright(c) 2006-2007, Ext JS, LLC.
9530 * Originally Released Under LGPL - original licence link has changed is not relivant.
9533 * <script type="text/javascript">
9536 * @class Roo.data.MemoryProxy
9537 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9538 * to the Reader when its load method is called.
9540 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9542 Roo.data.MemoryProxy = function(data){
9546 Roo.data.MemoryProxy.superclass.constructor.call(this);
9550 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9552 * Load data from the requested source (in this case an in-memory
9553 * data object passed to the constructor), read the data object into
9554 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9555 * process that block using the passed callback.
9556 * @param {Object} params This parameter is not used by the MemoryProxy class.
9557 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9558 * object into a block of Roo.data.Records.
9559 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9560 * The function must be passed <ul>
9561 * <li>The Record block object</li>
9562 * <li>The "arg" argument from the load function</li>
9563 * <li>A boolean success indicator</li>
9565 * @param {Object} scope The scope in which to call the callback
9566 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9568 load : function(params, reader, callback, scope, arg){
9569 params = params || {};
9572 result = reader.readRecords(this.data);
9574 this.fireEvent("loadexception", this, arg, null, e);
9575 callback.call(scope, null, arg, false);
9578 callback.call(scope, result, arg, true);
9582 update : function(params, records){
9587 * Ext JS Library 1.1.1
9588 * Copyright(c) 2006-2007, Ext JS, LLC.
9590 * Originally Released Under LGPL - original licence link has changed is not relivant.
9593 * <script type="text/javascript">
9596 * @class Roo.data.HttpProxy
9597 * @extends Roo.data.DataProxy
9598 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9599 * configured to reference a certain URL.<br><br>
9601 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9602 * from which the running page was served.<br><br>
9604 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9606 * Be aware that to enable the browser to parse an XML document, the server must set
9607 * the Content-Type header in the HTTP response to "text/xml".
9609 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9610 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9611 * will be used to make the request.
9613 Roo.data.HttpProxy = function(conn){
9614 Roo.data.HttpProxy.superclass.constructor.call(this);
9615 // is conn a conn config or a real conn?
9617 this.useAjax = !conn || !conn.events;
9621 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9622 // thse are take from connection...
9625 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9628 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9629 * extra parameters to each request made by this object. (defaults to undefined)
9632 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9633 * to each request made by this object. (defaults to undefined)
9636 * @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)
9639 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9642 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9648 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9652 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9653 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9654 * a finer-grained basis than the DataProxy events.
9656 getConnection : function(){
9657 return this.useAjax ? Roo.Ajax : this.conn;
9661 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9662 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9663 * process that block using the passed callback.
9664 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9665 * for the request to the remote server.
9666 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9667 * object into a block of Roo.data.Records.
9668 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9669 * The function must be passed <ul>
9670 * <li>The Record block object</li>
9671 * <li>The "arg" argument from the load function</li>
9672 * <li>A boolean success indicator</li>
9674 * @param {Object} scope The scope in which to call the callback
9675 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9677 load : function(params, reader, callback, scope, arg){
9678 if(this.fireEvent("beforeload", this, params) !== false){
9680 params : params || {},
9682 callback : callback,
9687 callback : this.loadResponse,
9691 Roo.applyIf(o, this.conn);
9692 if(this.activeRequest){
9693 Roo.Ajax.abort(this.activeRequest);
9695 this.activeRequest = Roo.Ajax.request(o);
9697 this.conn.request(o);
9700 callback.call(scope||this, null, arg, false);
9705 loadResponse : function(o, success, response){
9706 delete this.activeRequest;
9708 this.fireEvent("loadexception", this, o, response);
9709 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9714 result = o.reader.read(response);
9716 this.fireEvent("loadexception", this, o, response, e);
9717 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9721 this.fireEvent("load", this, o, o.request.arg);
9722 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9726 update : function(dataSet){
9731 updateResponse : function(dataSet){
9736 * Ext JS Library 1.1.1
9737 * Copyright(c) 2006-2007, Ext JS, LLC.
9739 * Originally Released Under LGPL - original licence link has changed is not relivant.
9742 * <script type="text/javascript">
9746 * @class Roo.data.ScriptTagProxy
9747 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9748 * other than the originating domain of the running page.<br><br>
9750 * <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
9751 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9753 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9754 * source code that is used as the source inside a <script> tag.<br><br>
9756 * In order for the browser to process the returned data, the server must wrap the data object
9757 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9758 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9759 * depending on whether the callback name was passed:
9762 boolean scriptTag = false;
9763 String cb = request.getParameter("callback");
9766 response.setContentType("text/javascript");
9768 response.setContentType("application/x-json");
9770 Writer out = response.getWriter();
9772 out.write(cb + "(");
9774 out.print(dataBlock.toJsonString());
9781 * @param {Object} config A configuration object.
9783 Roo.data.ScriptTagProxy = function(config){
9784 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9785 Roo.apply(this, config);
9786 this.head = document.getElementsByTagName("head")[0];
9789 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9791 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9793 * @cfg {String} url The URL from which to request the data object.
9796 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9800 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9801 * the server the name of the callback function set up by the load call to process the returned data object.
9802 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9803 * javascript output which calls this named function passing the data object as its only parameter.
9805 callbackParam : "callback",
9807 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9808 * name to the request.
9813 * Load data from the configured URL, read the data object into
9814 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9815 * process that block using the passed callback.
9816 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9817 * for the request to the remote server.
9818 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9819 * object into a block of Roo.data.Records.
9820 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9821 * The function must be passed <ul>
9822 * <li>The Record block object</li>
9823 * <li>The "arg" argument from the load function</li>
9824 * <li>A boolean success indicator</li>
9826 * @param {Object} scope The scope in which to call the callback
9827 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9829 load : function(params, reader, callback, scope, arg){
9830 if(this.fireEvent("beforeload", this, params) !== false){
9832 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9835 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9837 url += "&_dc=" + (new Date().getTime());
9839 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9842 cb : "stcCallback"+transId,
9843 scriptId : "stcScript"+transId,
9847 callback : callback,
9853 window[trans.cb] = function(o){
9854 conn.handleResponse(o, trans);
9857 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9859 if(this.autoAbort !== false){
9863 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9865 var script = document.createElement("script");
9866 script.setAttribute("src", url);
9867 script.setAttribute("type", "text/javascript");
9868 script.setAttribute("id", trans.scriptId);
9869 this.head.appendChild(script);
9873 callback.call(scope||this, null, arg, false);
9878 isLoading : function(){
9879 return this.trans ? true : false;
9883 * Abort the current server request.
9886 if(this.isLoading()){
9887 this.destroyTrans(this.trans);
9892 destroyTrans : function(trans, isLoaded){
9893 this.head.removeChild(document.getElementById(trans.scriptId));
9894 clearTimeout(trans.timeoutId);
9896 window[trans.cb] = undefined;
9898 delete window[trans.cb];
9901 // if hasn't been loaded, wait for load to remove it to prevent script error
9902 window[trans.cb] = function(){
9903 window[trans.cb] = undefined;
9905 delete window[trans.cb];
9912 handleResponse : function(o, trans){
9914 this.destroyTrans(trans, true);
9917 result = trans.reader.readRecords(o);
9919 this.fireEvent("loadexception", this, o, trans.arg, e);
9920 trans.callback.call(trans.scope||window, null, trans.arg, false);
9923 this.fireEvent("load", this, o, trans.arg);
9924 trans.callback.call(trans.scope||window, result, trans.arg, true);
9928 handleFailure : function(trans){
9930 this.destroyTrans(trans, false);
9931 this.fireEvent("loadexception", this, null, trans.arg);
9932 trans.callback.call(trans.scope||window, null, trans.arg, false);
9936 * Ext JS Library 1.1.1
9937 * Copyright(c) 2006-2007, Ext JS, LLC.
9939 * Originally Released Under LGPL - original licence link has changed is not relivant.
9942 * <script type="text/javascript">
9946 * @class Roo.data.JsonReader
9947 * @extends Roo.data.DataReader
9948 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9949 * based on mappings in a provided Roo.data.Record constructor.
9951 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9952 * in the reply previously.
9957 var RecordDef = Roo.data.Record.create([
9958 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9959 {name: 'occupation'} // This field will use "occupation" as the mapping.
9961 var myReader = new Roo.data.JsonReader({
9962 totalProperty: "results", // The property which contains the total dataset size (optional)
9963 root: "rows", // The property which contains an Array of row objects
9964 id: "id" // The property within each row object that provides an ID for the record (optional)
9968 * This would consume a JSON file like this:
9970 { 'results': 2, 'rows': [
9971 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9972 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9975 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9976 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9977 * paged from the remote server.
9978 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9979 * @cfg {String} root name of the property which contains the Array of row objects.
9980 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9982 * Create a new JsonReader
9983 * @param {Object} meta Metadata configuration options
9984 * @param {Object} recordType Either an Array of field definition objects,
9985 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9987 Roo.data.JsonReader = function(meta, recordType){
9990 // set some defaults:
9992 totalProperty: 'total',
9993 successProperty : 'success',
9998 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10000 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10003 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10004 * Used by Store query builder to append _requestMeta to params.
10007 metaFromRemote : false,
10009 * This method is only used by a DataProxy which has retrieved data from a remote server.
10010 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10011 * @return {Object} data A data block which is used by an Roo.data.Store object as
10012 * a cache of Roo.data.Records.
10014 read : function(response){
10015 var json = response.responseText;
10017 var o = /* eval:var:o */ eval("("+json+")");
10019 throw {message: "JsonReader.read: Json object not found"};
10025 this.metaFromRemote = true;
10026 this.meta = o.metaData;
10027 this.recordType = Roo.data.Record.create(o.metaData.fields);
10028 this.onMetaChange(this.meta, this.recordType, o);
10030 return this.readRecords(o);
10033 // private function a store will implement
10034 onMetaChange : function(meta, recordType, o){
10041 simpleAccess: function(obj, subsc) {
10048 getJsonAccessor: function(){
10050 return function(expr) {
10052 return(re.test(expr))
10053 ? new Function("obj", "return obj." + expr)
10058 return Roo.emptyFn;
10063 * Create a data block containing Roo.data.Records from an XML document.
10064 * @param {Object} o An object which contains an Array of row objects in the property specified
10065 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10066 * which contains the total size of the dataset.
10067 * @return {Object} data A data block which is used by an Roo.data.Store object as
10068 * a cache of Roo.data.Records.
10070 readRecords : function(o){
10072 * After any data loads, the raw JSON data is available for further custom processing.
10076 var s = this.meta, Record = this.recordType,
10077 f = Record.prototype.fields, fi = f.items, fl = f.length;
10079 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10081 if(s.totalProperty) {
10082 this.getTotal = this.getJsonAccessor(s.totalProperty);
10084 if(s.successProperty) {
10085 this.getSuccess = this.getJsonAccessor(s.successProperty);
10087 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10089 var g = this.getJsonAccessor(s.id);
10090 this.getId = function(rec) {
10092 return (r === undefined || r === "") ? null : r;
10095 this.getId = function(){return null;};
10098 for(var jj = 0; jj < fl; jj++){
10100 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10101 this.ef[jj] = this.getJsonAccessor(map);
10105 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10106 if(s.totalProperty){
10107 var vt = parseInt(this.getTotal(o), 10);
10112 if(s.successProperty){
10113 var vs = this.getSuccess(o);
10114 if(vs === false || vs === 'false'){
10119 for(var i = 0; i < c; i++){
10122 var id = this.getId(n);
10123 for(var j = 0; j < fl; j++){
10125 var v = this.ef[j](n);
10127 Roo.log('missing convert for ' + f.name);
10131 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10133 var record = new Record(values, id);
10135 records[i] = record;
10141 totalRecords : totalRecords
10146 * Ext JS Library 1.1.1
10147 * Copyright(c) 2006-2007, Ext JS, LLC.
10149 * Originally Released Under LGPL - original licence link has changed is not relivant.
10152 * <script type="text/javascript">
10156 * @class Roo.data.ArrayReader
10157 * @extends Roo.data.DataReader
10158 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10159 * Each element of that Array represents a row of data fields. The
10160 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10161 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10165 var RecordDef = Roo.data.Record.create([
10166 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10167 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10169 var myReader = new Roo.data.ArrayReader({
10170 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10174 * This would consume an Array like this:
10176 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10178 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10180 * Create a new JsonReader
10181 * @param {Object} meta Metadata configuration options.
10182 * @param {Object} recordType Either an Array of field definition objects
10183 * as specified to {@link Roo.data.Record#create},
10184 * or an {@link Roo.data.Record} object
10185 * created using {@link Roo.data.Record#create}.
10187 Roo.data.ArrayReader = function(meta, recordType){
10188 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10191 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10193 * Create a data block containing Roo.data.Records from an XML document.
10194 * @param {Object} o An Array of row objects which represents the dataset.
10195 * @return {Object} data A data block which is used by an Roo.data.Store object as
10196 * a cache of Roo.data.Records.
10198 readRecords : function(o){
10199 var sid = this.meta ? this.meta.id : null;
10200 var recordType = this.recordType, fields = recordType.prototype.fields;
10203 for(var i = 0; i < root.length; i++){
10206 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10207 for(var j = 0, jlen = fields.length; j < jlen; j++){
10208 var f = fields.items[j];
10209 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10210 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10212 values[f.name] = v;
10214 var record = new recordType(values, id);
10216 records[records.length] = record;
10220 totalRecords : records.length
10229 * @class Roo.bootstrap.ComboBox
10230 * @extends Roo.bootstrap.TriggerField
10231 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10232 * @cfg {Boolean} append (true|false) default false
10233 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10234 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10235 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10236 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10237 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10239 * Create a new ComboBox.
10240 * @param {Object} config Configuration options
10242 Roo.bootstrap.ComboBox = function(config){
10243 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10247 * Fires when the dropdown list is expanded
10248 * @param {Roo.bootstrap.ComboBox} combo This combo box
10253 * Fires when the dropdown list is collapsed
10254 * @param {Roo.bootstrap.ComboBox} combo This combo box
10258 * @event beforeselect
10259 * Fires before a list item is selected. Return false to cancel the selection.
10260 * @param {Roo.bootstrap.ComboBox} combo This combo box
10261 * @param {Roo.data.Record} record The data record returned from the underlying store
10262 * @param {Number} index The index of the selected item in the dropdown list
10264 'beforeselect' : true,
10267 * Fires when a list item is selected
10268 * @param {Roo.bootstrap.ComboBox} combo This combo box
10269 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10270 * @param {Number} index The index of the selected item in the dropdown list
10274 * @event beforequery
10275 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10276 * The event object passed has these properties:
10277 * @param {Roo.bootstrap.ComboBox} combo This combo box
10278 * @param {String} query The query
10279 * @param {Boolean} forceAll true to force "all" query
10280 * @param {Boolean} cancel true to cancel the query
10281 * @param {Object} e The query event object
10283 'beforequery': true,
10286 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10287 * @param {Roo.bootstrap.ComboBox} combo This combo box
10292 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10293 * @param {Roo.bootstrap.ComboBox} combo This combo box
10294 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10299 * Fires when the remove value from the combobox array
10300 * @param {Roo.bootstrap.ComboBox} combo This combo box
10307 this.tickItems = [];
10309 this.selectedIndex = -1;
10310 if(this.mode == 'local'){
10311 if(config.queryDelay === undefined){
10312 this.queryDelay = 10;
10314 if(config.minChars === undefined){
10320 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10323 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10324 * rendering into an Roo.Editor, defaults to false)
10327 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10328 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10331 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10334 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10335 * the dropdown list (defaults to undefined, with no header element)
10339 * @cfg {String/Roo.Template} tpl The template to use to render the output
10343 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10345 listWidth: undefined,
10347 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10348 * mode = 'remote' or 'text' if mode = 'local')
10350 displayField: undefined,
10352 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10353 * mode = 'remote' or 'value' if mode = 'local').
10354 * Note: use of a valueField requires the user make a selection
10355 * in order for a value to be mapped.
10357 valueField: undefined,
10361 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10362 * field's data value (defaults to the underlying DOM element's name)
10364 hiddenName: undefined,
10366 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10370 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10372 selectedClass: 'active',
10375 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10379 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10380 * anchor positions (defaults to 'tl-bl')
10382 listAlign: 'tl-bl?',
10384 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10388 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10389 * query specified by the allQuery config option (defaults to 'query')
10391 triggerAction: 'query',
10393 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10394 * (defaults to 4, does not apply if editable = false)
10398 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10399 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10403 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10404 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10408 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10409 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10413 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10414 * when editable = true (defaults to false)
10416 selectOnFocus:false,
10418 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10420 queryParam: 'query',
10422 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10423 * when mode = 'remote' (defaults to 'Loading...')
10425 loadingText: 'Loading...',
10427 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10431 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10435 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10436 * traditional select (defaults to true)
10440 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10444 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10448 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10449 * listWidth has a higher value)
10453 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10454 * allow the user to set arbitrary text into the field (defaults to false)
10456 forceSelection:false,
10458 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10459 * if typeAhead = true (defaults to 250)
10461 typeAheadDelay : 250,
10463 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10464 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10466 valueNotFoundText : undefined,
10468 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10470 blockFocus : false,
10473 * @cfg {Boolean} disableClear Disable showing of clear button.
10475 disableClear : false,
10477 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10479 alwaysQuery : false,
10482 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10496 btnPosition : 'right',
10497 triggerList : true,
10498 showToggleBtn : true,
10499 // element that contains real text value.. (when hidden is used..)
10501 getAutoCreate : function()
10508 if(!this.tickable){
10509 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10514 * ComboBox with tickable selections
10517 var align = this.labelAlign || this.parentLabelAlign();
10520 cls : 'form-group roo-combobox-tickable' //input-group
10526 cls : 'tickable-buttons',
10531 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10538 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10545 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10552 Roo.each(buttons.cn, function(c){
10554 c.cls += ' btn-' + _this.size;
10557 if (_this.disabled) {
10568 cls: 'form-hidden-field'
10572 cls: 'select2-choices',
10576 cls: 'select2-search-field',
10588 cls: 'select2-container input-group select2-container-multi',
10593 // cls: 'typeahead typeahead-long dropdown-menu',
10594 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10599 if (align ==='left' && this.fieldLabel.length) {
10601 Roo.log("left and has label");
10607 cls : 'control-label col-sm-' + this.labelWidth,
10608 html : this.fieldLabel
10612 cls : "col-sm-" + (12 - this.labelWidth),
10619 } else if ( this.fieldLabel.length) {
10625 //cls : 'input-group-addon',
10626 html : this.fieldLabel
10636 Roo.log(" no label && no align");
10643 ['xs','sm','md','lg'].map(function(size){
10644 if (settings[size]) {
10645 cfg.cls += ' col-' + size + '-' + settings[size];
10654 initEvents: function()
10658 throw "can not find store for combo";
10660 this.store = Roo.factory(this.store, Roo.data);
10663 this.initTickableEvents();
10667 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10669 if(this.hiddenName){
10671 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10673 this.hiddenField.dom.value =
10674 this.hiddenValue !== undefined ? this.hiddenValue :
10675 this.value !== undefined ? this.value : '';
10677 // prevent input submission
10678 this.el.dom.removeAttribute('name');
10679 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10684 // this.el.dom.setAttribute('autocomplete', 'off');
10687 var cls = 'x-combo-list';
10689 //this.list = new Roo.Layer({
10690 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10696 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10697 _this.list.setWidth(lw);
10700 this.list.on('mouseover', this.onViewOver, this);
10701 this.list.on('mousemove', this.onViewMove, this);
10703 this.list.on('scroll', this.onViewScroll, this);
10706 this.list.swallowEvent('mousewheel');
10707 this.assetHeight = 0;
10710 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10711 this.assetHeight += this.header.getHeight();
10714 this.innerList = this.list.createChild({cls:cls+'-inner'});
10715 this.innerList.on('mouseover', this.onViewOver, this);
10716 this.innerList.on('mousemove', this.onViewMove, this);
10717 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10719 if(this.allowBlank && !this.pageSize && !this.disableClear){
10720 this.footer = this.list.createChild({cls:cls+'-ft'});
10721 this.pageTb = new Roo.Toolbar(this.footer);
10725 this.footer = this.list.createChild({cls:cls+'-ft'});
10726 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10727 {pageSize: this.pageSize});
10731 if (this.pageTb && this.allowBlank && !this.disableClear) {
10733 this.pageTb.add(new Roo.Toolbar.Fill(), {
10734 cls: 'x-btn-icon x-btn-clear',
10736 handler: function()
10739 _this.clearValue();
10740 _this.onSelect(false, -1);
10745 this.assetHeight += this.footer.getHeight();
10750 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10753 this.view = new Roo.View(this.list, this.tpl, {
10754 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10756 //this.view.wrapEl.setDisplayed(false);
10757 this.view.on('click', this.onViewClick, this);
10761 this.store.on('beforeload', this.onBeforeLoad, this);
10762 this.store.on('load', this.onLoad, this);
10763 this.store.on('loadexception', this.onLoadException, this);
10765 if(this.resizable){
10766 this.resizer = new Roo.Resizable(this.list, {
10767 pinned:true, handles:'se'
10769 this.resizer.on('resize', function(r, w, h){
10770 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10771 this.listWidth = w;
10772 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10773 this.restrictHeight();
10775 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10778 if(!this.editable){
10779 this.editable = true;
10780 this.setEditable(false);
10785 if (typeof(this.events.add.listeners) != 'undefined') {
10787 this.addicon = this.wrap.createChild(
10788 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10790 this.addicon.on('click', function(e) {
10791 this.fireEvent('add', this);
10794 if (typeof(this.events.edit.listeners) != 'undefined') {
10796 this.editicon = this.wrap.createChild(
10797 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10798 if (this.addicon) {
10799 this.editicon.setStyle('margin-left', '40px');
10801 this.editicon.on('click', function(e) {
10803 // we fire even if inothing is selected..
10804 this.fireEvent('edit', this, this.lastData );
10810 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10811 "up" : function(e){
10812 this.inKeyMode = true;
10816 "down" : function(e){
10817 if(!this.isExpanded()){
10818 this.onTriggerClick();
10820 this.inKeyMode = true;
10825 "enter" : function(e){
10826 // this.onViewClick();
10830 if(this.fireEvent("specialkey", this, e)){
10831 this.onViewClick(false);
10837 "esc" : function(e){
10841 "tab" : function(e){
10844 if(this.fireEvent("specialkey", this, e)){
10845 this.onViewClick(false);
10853 doRelay : function(foo, bar, hname){
10854 if(hname == 'down' || this.scope.isExpanded()){
10855 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10864 this.queryDelay = Math.max(this.queryDelay || 10,
10865 this.mode == 'local' ? 10 : 250);
10868 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10870 if(this.typeAhead){
10871 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10873 if(this.editable !== false){
10874 this.inputEl().on("keyup", this.onKeyUp, this);
10876 if(this.forceSelection){
10877 this.inputEl().on('blur', this.doForce, this);
10881 this.choices = this.el.select('ul.select2-choices', true).first();
10882 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10886 initTickableEvents: function()
10890 if(this.hiddenName){
10892 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10894 this.hiddenField.dom.value =
10895 this.hiddenValue !== undefined ? this.hiddenValue :
10896 this.value !== undefined ? this.value : '';
10898 // prevent input submission
10899 this.el.dom.removeAttribute('name');
10900 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10905 // this.list = this.el.select('ul.dropdown-menu',true).first();
10907 this.choices = this.el.select('ul.select2-choices', true).first();
10908 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10909 if(this.triggerList){
10910 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10913 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10914 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10916 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10917 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10919 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10920 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10922 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10923 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10924 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10927 this.cancelBtn.hide();
10932 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10933 _this.list.setWidth(lw);
10936 this.list.on('mouseover', this.onViewOver, this);
10937 this.list.on('mousemove', this.onViewMove, this);
10939 this.list.on('scroll', this.onViewScroll, this);
10942 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>';
10945 this.view = new Roo.View(this.list, this.tpl, {
10946 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10949 //this.view.wrapEl.setDisplayed(false);
10950 this.view.on('click', this.onViewClick, this);
10954 this.store.on('beforeload', this.onBeforeLoad, this);
10955 this.store.on('load', this.onLoad, this);
10956 this.store.on('loadexception', this.onLoadException, this);
10958 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10959 // "up" : function(e){
10960 // this.inKeyMode = true;
10961 // this.selectPrev();
10964 // "down" : function(e){
10965 // if(!this.isExpanded()){
10966 // this.onTriggerClick();
10968 // this.inKeyMode = true;
10969 // this.selectNext();
10973 // "enter" : function(e){
10974 //// this.onViewClick();
10976 // this.collapse();
10978 // if(this.fireEvent("specialkey", this, e)){
10979 // this.onViewClick(false);
10985 // "esc" : function(e){
10986 // this.collapse();
10989 // "tab" : function(e){
10990 // this.collapse();
10992 // if(this.fireEvent("specialkey", this, e)){
10993 // this.onViewClick(false);
11001 // doRelay : function(foo, bar, hname){
11002 // if(hname == 'down' || this.scope.isExpanded()){
11003 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11008 // forceKeyDown: true
11012 this.queryDelay = Math.max(this.queryDelay || 10,
11013 this.mode == 'local' ? 10 : 250);
11016 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11018 if(this.typeAhead){
11019 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11023 onDestroy : function(){
11025 this.view.setStore(null);
11026 this.view.el.removeAllListeners();
11027 this.view.el.remove();
11028 this.view.purgeListeners();
11031 this.list.dom.innerHTML = '';
11035 this.store.un('beforeload', this.onBeforeLoad, this);
11036 this.store.un('load', this.onLoad, this);
11037 this.store.un('loadexception', this.onLoadException, this);
11039 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11043 fireKey : function(e){
11044 if(e.isNavKeyPress() && !this.list.isVisible()){
11045 this.fireEvent("specialkey", this, e);
11050 onResize: function(w, h){
11051 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11053 // if(typeof w != 'number'){
11054 // // we do not handle it!?!?
11057 // var tw = this.trigger.getWidth();
11058 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11059 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11061 // this.inputEl().setWidth( this.adjustWidth('input', x));
11063 // //this.trigger.setStyle('left', x+'px');
11065 // if(this.list && this.listWidth === undefined){
11066 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11067 // this.list.setWidth(lw);
11068 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11076 * Allow or prevent the user from directly editing the field text. If false is passed,
11077 * the user will only be able to select from the items defined in the dropdown list. This method
11078 * is the runtime equivalent of setting the 'editable' config option at config time.
11079 * @param {Boolean} value True to allow the user to directly edit the field text
11081 setEditable : function(value){
11082 if(value == this.editable){
11085 this.editable = value;
11087 this.inputEl().dom.setAttribute('readOnly', true);
11088 this.inputEl().on('mousedown', this.onTriggerClick, this);
11089 this.inputEl().addClass('x-combo-noedit');
11091 this.inputEl().dom.setAttribute('readOnly', false);
11092 this.inputEl().un('mousedown', this.onTriggerClick, this);
11093 this.inputEl().removeClass('x-combo-noedit');
11099 onBeforeLoad : function(combo,opts){
11100 if(!this.hasFocus){
11104 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11106 // this.restrictHeight();
11107 this.selectedIndex = -1;
11111 onLoad : function(){
11113 this.hasQuery = false;
11115 if(!this.hasFocus){
11119 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11120 this.loading.hide();
11123 if(this.store.getCount() > 0){
11125 // this.restrictHeight();
11126 if(this.lastQuery == this.allQuery){
11127 if(this.editable && !this.tickable){
11128 this.inputEl().dom.select();
11132 !this.selectByValue(this.value, true) &&
11133 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11134 this.store.lastOptions.add != true)
11136 this.select(0, true);
11139 if(this.autoFocus){
11142 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11143 this.taTask.delay(this.typeAheadDelay);
11147 this.onEmptyResults();
11153 onLoadException : function()
11155 this.hasQuery = false;
11157 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11158 this.loading.hide();
11162 Roo.log(this.store.reader.jsonData);
11163 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11165 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11171 onTypeAhead : function(){
11172 if(this.store.getCount() > 0){
11173 var r = this.store.getAt(0);
11174 var newValue = r.data[this.displayField];
11175 var len = newValue.length;
11176 var selStart = this.getRawValue().length;
11178 if(selStart != len){
11179 this.setRawValue(newValue);
11180 this.selectText(selStart, newValue.length);
11186 onSelect : function(record, index){
11188 if(this.fireEvent('beforeselect', this, record, index) !== false){
11190 this.setFromData(index > -1 ? record.data : false);
11193 this.fireEvent('select', this, record, index);
11198 * Returns the currently selected field value or empty string if no value is set.
11199 * @return {String} value The selected value
11201 getValue : function(){
11204 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11207 if(this.valueField){
11208 return typeof this.value != 'undefined' ? this.value : '';
11210 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11215 * Clears any text/value currently set in the field
11217 clearValue : function(){
11218 if(this.hiddenField){
11219 this.hiddenField.dom.value = '';
11222 this.setRawValue('');
11223 this.lastSelectionText = '';
11228 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11229 * will be displayed in the field. If the value does not match the data value of an existing item,
11230 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11231 * Otherwise the field will be blank (although the value will still be set).
11232 * @param {String} value The value to match
11234 setValue : function(v){
11241 if(this.valueField){
11242 var r = this.findRecord(this.valueField, v);
11244 text = r.data[this.displayField];
11245 }else if(this.valueNotFoundText !== undefined){
11246 text = this.valueNotFoundText;
11249 this.lastSelectionText = text;
11250 if(this.hiddenField){
11251 this.hiddenField.dom.value = v;
11253 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11257 * @property {Object} the last set data for the element
11262 * Sets the value of the field based on a object which is related to the record format for the store.
11263 * @param {Object} value the value to set as. or false on reset?
11265 setFromData : function(o){
11268 if(typeof o.display_name !== 'string'){
11269 for(var i=0;i<o.display_name.length;i++){
11270 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11278 var dv = ''; // display value
11279 var vv = ''; // value value..
11281 if (this.displayField) {
11282 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11284 // this is an error condition!!!
11285 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11288 if(this.valueField){
11289 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11292 if(this.hiddenField){
11293 this.hiddenField.dom.value = vv;
11295 this.lastSelectionText = dv;
11296 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11300 // no hidden field.. - we store the value in 'value', but still display
11301 // display field!!!!
11302 this.lastSelectionText = dv;
11303 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11309 reset : function(){
11310 // overridden so that last data is reset..
11311 this.setValue(this.originalValue);
11312 this.clearInvalid();
11313 this.lastData = false;
11315 this.view.clearSelections();
11319 findRecord : function(prop, value){
11321 if(this.store.getCount() > 0){
11322 this.store.each(function(r){
11323 if(r.data[prop] == value){
11333 getName: function()
11335 // returns hidden if it's set..
11336 if (!this.rendered) {return ''};
11337 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11341 onViewMove : function(e, t){
11342 this.inKeyMode = false;
11346 onViewOver : function(e, t){
11347 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11350 var item = this.view.findItemFromChild(t);
11353 var index = this.view.indexOf(item);
11354 this.select(index, false);
11359 onViewClick : function(view, doFocus, el, e)
11361 var index = this.view.getSelectedIndexes()[0];
11363 var r = this.store.getAt(index);
11367 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11374 Roo.each(this.tickItems, function(v,k){
11376 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11377 _this.tickItems.splice(k, 1);
11387 this.tickItems.push(r.data);
11392 this.onSelect(r, index);
11394 if(doFocus !== false && !this.blockFocus){
11395 this.inputEl().focus();
11400 restrictHeight : function(){
11401 //this.innerList.dom.style.height = '';
11402 //var inner = this.innerList.dom;
11403 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11404 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11405 //this.list.beginUpdate();
11406 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11407 this.list.alignTo(this.inputEl(), this.listAlign);
11408 this.list.alignTo(this.inputEl(), this.listAlign);
11409 //this.list.endUpdate();
11413 onEmptyResults : function(){
11418 * Returns true if the dropdown list is expanded, else false.
11420 isExpanded : function(){
11421 return this.list.isVisible();
11425 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11426 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11427 * @param {String} value The data value of the item to select
11428 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11429 * selected item if it is not currently in view (defaults to true)
11430 * @return {Boolean} True if the value matched an item in the list, else false
11432 selectByValue : function(v, scrollIntoView){
11433 if(v !== undefined && v !== null){
11434 var r = this.findRecord(this.valueField || this.displayField, v);
11436 this.select(this.store.indexOf(r), scrollIntoView);
11444 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11445 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11446 * @param {Number} index The zero-based index of the list item to select
11447 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11448 * selected item if it is not currently in view (defaults to true)
11450 select : function(index, scrollIntoView){
11451 this.selectedIndex = index;
11452 this.view.select(index);
11453 if(scrollIntoView !== false){
11454 var el = this.view.getNode(index);
11455 if(el && !this.multiple && !this.tickable){
11456 this.list.scrollChildIntoView(el, false);
11462 selectNext : function(){
11463 var ct = this.store.getCount();
11465 if(this.selectedIndex == -1){
11467 }else if(this.selectedIndex < ct-1){
11468 this.select(this.selectedIndex+1);
11474 selectPrev : function(){
11475 var ct = this.store.getCount();
11477 if(this.selectedIndex == -1){
11479 }else if(this.selectedIndex != 0){
11480 this.select(this.selectedIndex-1);
11486 onKeyUp : function(e){
11487 if(this.editable !== false && !e.isSpecialKey()){
11488 this.lastKey = e.getKey();
11489 this.dqTask.delay(this.queryDelay);
11494 validateBlur : function(){
11495 return !this.list || !this.list.isVisible();
11499 initQuery : function(){
11500 this.doQuery(this.getRawValue());
11504 doForce : function(){
11505 if(this.inputEl().dom.value.length > 0){
11506 this.inputEl().dom.value =
11507 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11513 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11514 * query allowing the query action to be canceled if needed.
11515 * @param {String} query The SQL query to execute
11516 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11517 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11518 * saved in the current store (defaults to false)
11520 doQuery : function(q, forceAll){
11522 if(q === undefined || q === null){
11527 forceAll: forceAll,
11531 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11536 forceAll = qe.forceAll;
11537 if(forceAll === true || (q.length >= this.minChars)){
11539 this.hasQuery = true;
11541 if(this.lastQuery != q || this.alwaysQuery){
11542 this.lastQuery = q;
11543 if(this.mode == 'local'){
11544 this.selectedIndex = -1;
11546 this.store.clearFilter();
11548 this.store.filter(this.displayField, q);
11552 this.store.baseParams[this.queryParam] = q;
11554 var options = {params : this.getParams(q)};
11557 options.add = true;
11558 options.params.start = this.page * this.pageSize;
11561 this.store.load(options);
11563 * this code will make the page width larger, at the beginning, the list not align correctly,
11564 * we should expand the list on onLoad
11565 * so command out it
11570 this.selectedIndex = -1;
11575 this.loadNext = false;
11579 getParams : function(q){
11581 //p[this.queryParam] = q;
11585 p.limit = this.pageSize;
11591 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11593 collapse : function(){
11594 if(!this.isExpanded()){
11602 this.cancelBtn.hide();
11603 this.trigger.show();
11606 Roo.get(document).un('mousedown', this.collapseIf, this);
11607 Roo.get(document).un('mousewheel', this.collapseIf, this);
11608 if (!this.editable) {
11609 Roo.get(document).un('keydown', this.listKeyPress, this);
11611 this.fireEvent('collapse', this);
11615 collapseIf : function(e){
11616 var in_combo = e.within(this.el);
11617 var in_list = e.within(this.list);
11618 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11620 if (in_combo || in_list || is_list) {
11621 //e.stopPropagation();
11626 this.onTickableFooterButtonClick(e, false, false);
11634 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11636 expand : function(){
11638 if(this.isExpanded() || !this.hasFocus){
11642 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11643 this.list.setWidth(lw);
11648 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11649 this.list.setWidth(lw);
11653 this.restrictHeight();
11657 this.tickItems = Roo.apply([], this.item);
11660 this.cancelBtn.show();
11661 this.trigger.hide();
11665 Roo.get(document).on('mousedown', this.collapseIf, this);
11666 Roo.get(document).on('mousewheel', this.collapseIf, this);
11667 if (!this.editable) {
11668 Roo.get(document).on('keydown', this.listKeyPress, this);
11671 this.fireEvent('expand', this);
11675 // Implements the default empty TriggerField.onTriggerClick function
11676 onTriggerClick : function(e)
11678 Roo.log('trigger click');
11680 if(this.disabled || !this.triggerList){
11685 this.loadNext = false;
11687 if(this.isExpanded()){
11689 if (!this.blockFocus) {
11690 this.inputEl().focus();
11694 this.hasFocus = true;
11695 if(this.triggerAction == 'all') {
11696 this.doQuery(this.allQuery, true);
11698 this.doQuery(this.getRawValue());
11700 if (!this.blockFocus) {
11701 this.inputEl().focus();
11706 onTickableTriggerClick : function(e)
11713 this.loadNext = false;
11714 this.hasFocus = true;
11716 if(this.triggerAction == 'all') {
11717 this.doQuery(this.allQuery, true);
11719 this.doQuery(this.getRawValue());
11723 onSearchFieldClick : function(e)
11725 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11730 this.loadNext = false;
11731 this.hasFocus = true;
11733 if(this.triggerAction == 'all') {
11734 this.doQuery(this.allQuery, true);
11736 this.doQuery(this.getRawValue());
11740 listKeyPress : function(e)
11742 //Roo.log('listkeypress');
11743 // scroll to first matching element based on key pres..
11744 if (e.isSpecialKey()) {
11747 var k = String.fromCharCode(e.getKey()).toUpperCase();
11750 var csel = this.view.getSelectedNodes();
11751 var cselitem = false;
11753 var ix = this.view.indexOf(csel[0]);
11754 cselitem = this.store.getAt(ix);
11755 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11761 this.store.each(function(v) {
11763 // start at existing selection.
11764 if (cselitem.id == v.id) {
11770 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11771 match = this.store.indexOf(v);
11777 if (match === false) {
11778 return true; // no more action?
11781 this.view.select(match);
11782 var sn = Roo.get(this.view.getSelectedNodes()[0])
11783 //sn.scrollIntoView(sn.dom.parentNode, false);
11786 onViewScroll : function(e, t){
11788 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){
11792 this.hasQuery = true;
11794 this.loading = this.list.select('.loading', true).first();
11796 if(this.loading === null){
11797 this.list.createChild({
11799 cls: 'loading select2-more-results select2-active',
11800 html: 'Loading more results...'
11803 this.loading = this.list.select('.loading', true).first();
11805 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11807 this.loading.hide();
11810 this.loading.show();
11815 this.loadNext = true;
11817 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11822 addItem : function(o)
11824 var dv = ''; // display value
11826 if (this.displayField) {
11827 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11829 // this is an error condition!!!
11830 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11837 var choice = this.choices.createChild({
11839 cls: 'select2-search-choice',
11848 cls: 'select2-search-choice-close',
11853 }, this.searchField);
11855 var close = choice.select('a.select2-search-choice-close', true).first()
11857 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11865 this.inputEl().dom.value = '';
11869 onRemoveItem : function(e, _self, o)
11871 e.preventDefault();
11872 var index = this.item.indexOf(o.data) * 1;
11875 Roo.log('not this item?!');
11879 this.item.splice(index, 1);
11884 this.fireEvent('remove', this, e);
11888 syncValue : function()
11890 if(!this.item.length){
11897 Roo.each(this.item, function(i){
11898 if(_this.valueField){
11899 value.push(i[_this.valueField]);
11906 this.value = value.join(',');
11908 if(this.hiddenField){
11909 this.hiddenField.dom.value = this.value;
11913 clearItem : function()
11915 if(!this.multiple){
11921 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11928 inputEl: function ()
11931 return this.searchField;
11933 return this.el.select('input.form-control',true).first();
11937 onTickableFooterButtonClick : function(e, btn, el)
11939 e.preventDefault();
11941 if(btn && btn.name == 'cancel'){
11942 this.tickItems = Roo.apply([], this.item);
11951 Roo.each(this.tickItems, function(o){
11962 * @cfg {Boolean} grow
11966 * @cfg {Number} growMin
11970 * @cfg {Number} growMax
11980 * Ext JS Library 1.1.1
11981 * Copyright(c) 2006-2007, Ext JS, LLC.
11983 * Originally Released Under LGPL - original licence link has changed is not relivant.
11986 * <script type="text/javascript">
11991 * @extends Roo.util.Observable
11992 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11993 * This class also supports single and multi selection modes. <br>
11994 * Create a data model bound view:
11996 var store = new Roo.data.Store(...);
11998 var view = new Roo.View({
12000 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12002 singleSelect: true,
12003 selectedClass: "ydataview-selected",
12007 // listen for node click?
12008 view.on("click", function(vw, index, node, e){
12009 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12013 dataModel.load("foobar.xml");
12015 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12017 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12018 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12020 * Note: old style constructor is still suported (container, template, config)
12023 * Create a new View
12024 * @param {Object} config The config object
12027 Roo.View = function(config, depreciated_tpl, depreciated_config){
12029 this.parent = false;
12031 if (typeof(depreciated_tpl) == 'undefined') {
12032 // new way.. - universal constructor.
12033 Roo.apply(this, config);
12034 this.el = Roo.get(this.el);
12037 this.el = Roo.get(config);
12038 this.tpl = depreciated_tpl;
12039 Roo.apply(this, depreciated_config);
12041 this.wrapEl = this.el.wrap().wrap();
12042 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12045 if(typeof(this.tpl) == "string"){
12046 this.tpl = new Roo.Template(this.tpl);
12048 // support xtype ctors..
12049 this.tpl = new Roo.factory(this.tpl, Roo);
12053 this.tpl.compile();
12058 * @event beforeclick
12059 * Fires before a click is processed. Returns false to cancel the default action.
12060 * @param {Roo.View} this
12061 * @param {Number} index The index of the target node
12062 * @param {HTMLElement} node The target node
12063 * @param {Roo.EventObject} e The raw event object
12065 "beforeclick" : true,
12068 * Fires when a template node is clicked.
12069 * @param {Roo.View} this
12070 * @param {Number} index The index of the target node
12071 * @param {HTMLElement} node The target node
12072 * @param {Roo.EventObject} e The raw event object
12077 * Fires when a template node is double clicked.
12078 * @param {Roo.View} this
12079 * @param {Number} index The index of the target node
12080 * @param {HTMLElement} node The target node
12081 * @param {Roo.EventObject} e The raw event object
12085 * @event contextmenu
12086 * Fires when a template node is right clicked.
12087 * @param {Roo.View} this
12088 * @param {Number} index The index of the target node
12089 * @param {HTMLElement} node The target node
12090 * @param {Roo.EventObject} e The raw event object
12092 "contextmenu" : true,
12094 * @event selectionchange
12095 * Fires when the selected nodes change.
12096 * @param {Roo.View} this
12097 * @param {Array} selections Array of the selected nodes
12099 "selectionchange" : true,
12102 * @event beforeselect
12103 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12104 * @param {Roo.View} this
12105 * @param {HTMLElement} node The node to be selected
12106 * @param {Array} selections Array of currently selected nodes
12108 "beforeselect" : true,
12110 * @event preparedata
12111 * Fires on every row to render, to allow you to change the data.
12112 * @param {Roo.View} this
12113 * @param {Object} data to be rendered (change this)
12115 "preparedata" : true
12123 "click": this.onClick,
12124 "dblclick": this.onDblClick,
12125 "contextmenu": this.onContextMenu,
12129 this.selections = [];
12131 this.cmp = new Roo.CompositeElementLite([]);
12133 this.store = Roo.factory(this.store, Roo.data);
12134 this.setStore(this.store, true);
12137 if ( this.footer && this.footer.xtype) {
12139 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12141 this.footer.dataSource = this.store
12142 this.footer.container = fctr;
12143 this.footer = Roo.factory(this.footer, Roo);
12144 fctr.insertFirst(this.el);
12146 // this is a bit insane - as the paging toolbar seems to detach the el..
12147 // dom.parentNode.parentNode.parentNode
12148 // they get detached?
12152 Roo.View.superclass.constructor.call(this);
12157 Roo.extend(Roo.View, Roo.util.Observable, {
12160 * @cfg {Roo.data.Store} store Data store to load data from.
12165 * @cfg {String|Roo.Element} el The container element.
12170 * @cfg {String|Roo.Template} tpl The template used by this View
12174 * @cfg {String} dataName the named area of the template to use as the data area
12175 * Works with domtemplates roo-name="name"
12179 * @cfg {String} selectedClass The css class to add to selected nodes
12181 selectedClass : "x-view-selected",
12183 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12188 * @cfg {String} text to display on mask (default Loading)
12192 * @cfg {Boolean} multiSelect Allow multiple selection
12194 multiSelect : false,
12196 * @cfg {Boolean} singleSelect Allow single selection
12198 singleSelect: false,
12201 * @cfg {Boolean} toggleSelect - selecting
12203 toggleSelect : false,
12206 * @cfg {Boolean} tickable - selecting
12211 * Returns the element this view is bound to.
12212 * @return {Roo.Element}
12214 getEl : function(){
12215 return this.wrapEl;
12221 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12223 refresh : function(){
12224 Roo.log('refresh');
12227 // if we are using something like 'domtemplate', then
12228 // the what gets used is:
12229 // t.applySubtemplate(NAME, data, wrapping data..)
12230 // the outer template then get' applied with
12231 // the store 'extra data'
12232 // and the body get's added to the
12233 // roo-name="data" node?
12234 // <span class='roo-tpl-{name}'></span> ?????
12238 this.clearSelections();
12239 this.el.update("");
12241 var records = this.store.getRange();
12242 if(records.length < 1) {
12244 // is this valid?? = should it render a template??
12246 this.el.update(this.emptyText);
12250 if (this.dataName) {
12251 this.el.update(t.apply(this.store.meta)); //????
12252 el = this.el.child('.roo-tpl-' + this.dataName);
12255 for(var i = 0, len = records.length; i < len; i++){
12256 var data = this.prepareData(records[i].data, i, records[i]);
12257 this.fireEvent("preparedata", this, data, i, records[i]);
12259 var d = Roo.apply({}, data);
12262 Roo.apply(d, {'roo-id' : Roo.id()});
12266 Roo.each(this.parent.item, function(item){
12267 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12270 Roo.apply(d, {'roo-data-checked' : 'checked'});
12274 html[html.length] = Roo.util.Format.trim(
12276 t.applySubtemplate(this.dataName, d, this.store.meta) :
12283 el.update(html.join(""));
12284 this.nodes = el.dom.childNodes;
12285 this.updateIndexes(0);
12290 * Function to override to reformat the data that is sent to
12291 * the template for each node.
12292 * DEPRICATED - use the preparedata event handler.
12293 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12294 * a JSON object for an UpdateManager bound view).
12296 prepareData : function(data, index, record)
12298 this.fireEvent("preparedata", this, data, index, record);
12302 onUpdate : function(ds, record){
12303 Roo.log('on update');
12304 this.clearSelections();
12305 var index = this.store.indexOf(record);
12306 var n = this.nodes[index];
12307 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12308 n.parentNode.removeChild(n);
12309 this.updateIndexes(index, index);
12315 onAdd : function(ds, records, index)
12317 Roo.log(['on Add', ds, records, index] );
12318 this.clearSelections();
12319 if(this.nodes.length == 0){
12323 var n = this.nodes[index];
12324 for(var i = 0, len = records.length; i < len; i++){
12325 var d = this.prepareData(records[i].data, i, records[i]);
12327 this.tpl.insertBefore(n, d);
12330 this.tpl.append(this.el, d);
12333 this.updateIndexes(index);
12336 onRemove : function(ds, record, index){
12337 Roo.log('onRemove');
12338 this.clearSelections();
12339 var el = this.dataName ?
12340 this.el.child('.roo-tpl-' + this.dataName) :
12343 el.dom.removeChild(this.nodes[index]);
12344 this.updateIndexes(index);
12348 * Refresh an individual node.
12349 * @param {Number} index
12351 refreshNode : function(index){
12352 this.onUpdate(this.store, this.store.getAt(index));
12355 updateIndexes : function(startIndex, endIndex){
12356 var ns = this.nodes;
12357 startIndex = startIndex || 0;
12358 endIndex = endIndex || ns.length - 1;
12359 for(var i = startIndex; i <= endIndex; i++){
12360 ns[i].nodeIndex = i;
12365 * Changes the data store this view uses and refresh the view.
12366 * @param {Store} store
12368 setStore : function(store, initial){
12369 if(!initial && this.store){
12370 this.store.un("datachanged", this.refresh);
12371 this.store.un("add", this.onAdd);
12372 this.store.un("remove", this.onRemove);
12373 this.store.un("update", this.onUpdate);
12374 this.store.un("clear", this.refresh);
12375 this.store.un("beforeload", this.onBeforeLoad);
12376 this.store.un("load", this.onLoad);
12377 this.store.un("loadexception", this.onLoad);
12381 store.on("datachanged", this.refresh, this);
12382 store.on("add", this.onAdd, this);
12383 store.on("remove", this.onRemove, this);
12384 store.on("update", this.onUpdate, this);
12385 store.on("clear", this.refresh, this);
12386 store.on("beforeload", this.onBeforeLoad, this);
12387 store.on("load", this.onLoad, this);
12388 store.on("loadexception", this.onLoad, this);
12396 * onbeforeLoad - masks the loading area.
12399 onBeforeLoad : function(store,opts)
12401 Roo.log('onBeforeLoad');
12403 this.el.update("");
12405 this.el.mask(this.mask ? this.mask : "Loading" );
12407 onLoad : function ()
12414 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12415 * @param {HTMLElement} node
12416 * @return {HTMLElement} The template node
12418 findItemFromChild : function(node){
12419 var el = this.dataName ?
12420 this.el.child('.roo-tpl-' + this.dataName,true) :
12423 if(!node || node.parentNode == el){
12426 var p = node.parentNode;
12427 while(p && p != el){
12428 if(p.parentNode == el){
12437 onClick : function(e){
12438 var item = this.findItemFromChild(e.getTarget());
12440 var index = this.indexOf(item);
12441 if(this.onItemClick(item, index, e) !== false){
12442 this.fireEvent("click", this, index, item, e);
12445 this.clearSelections();
12450 onContextMenu : function(e){
12451 var item = this.findItemFromChild(e.getTarget());
12453 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12458 onDblClick : function(e){
12459 var item = this.findItemFromChild(e.getTarget());
12461 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12465 onItemClick : function(item, index, e)
12467 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12470 if (this.toggleSelect) {
12471 var m = this.isSelected(item) ? 'unselect' : 'select';
12474 _t[m](item, true, false);
12477 if(this.multiSelect || this.singleSelect){
12478 if(this.multiSelect && e.shiftKey && this.lastSelection){
12479 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12481 this.select(item, this.multiSelect && e.ctrlKey);
12482 this.lastSelection = item;
12485 if(!this.tickable){
12486 e.preventDefault();
12494 * Get the number of selected nodes.
12497 getSelectionCount : function(){
12498 return this.selections.length;
12502 * Get the currently selected nodes.
12503 * @return {Array} An array of HTMLElements
12505 getSelectedNodes : function(){
12506 return this.selections;
12510 * Get the indexes of the selected nodes.
12513 getSelectedIndexes : function(){
12514 var indexes = [], s = this.selections;
12515 for(var i = 0, len = s.length; i < len; i++){
12516 indexes.push(s[i].nodeIndex);
12522 * Clear all selections
12523 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12525 clearSelections : function(suppressEvent){
12526 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12527 this.cmp.elements = this.selections;
12528 this.cmp.removeClass(this.selectedClass);
12529 this.selections = [];
12530 if(!suppressEvent){
12531 this.fireEvent("selectionchange", this, this.selections);
12537 * Returns true if the passed node is selected
12538 * @param {HTMLElement/Number} node The node or node index
12539 * @return {Boolean}
12541 isSelected : function(node){
12542 var s = this.selections;
12546 node = this.getNode(node);
12547 return s.indexOf(node) !== -1;
12552 * @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
12553 * @param {Boolean} keepExisting (optional) true to keep existing selections
12554 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12556 select : function(nodeInfo, keepExisting, suppressEvent){
12557 if(nodeInfo instanceof Array){
12559 this.clearSelections(true);
12561 for(var i = 0, len = nodeInfo.length; i < len; i++){
12562 this.select(nodeInfo[i], true, true);
12566 var node = this.getNode(nodeInfo);
12567 if(!node || this.isSelected(node)){
12568 return; // already selected.
12571 this.clearSelections(true);
12573 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12574 Roo.fly(node).addClass(this.selectedClass);
12575 this.selections.push(node);
12576 if(!suppressEvent){
12577 this.fireEvent("selectionchange", this, this.selections);
12585 * @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
12586 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12587 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12589 unselect : function(nodeInfo, keepExisting, suppressEvent)
12591 if(nodeInfo instanceof Array){
12592 Roo.each(this.selections, function(s) {
12593 this.unselect(s, nodeInfo);
12597 var node = this.getNode(nodeInfo);
12598 if(!node || !this.isSelected(node)){
12599 Roo.log("not selected");
12600 return; // not selected.
12604 Roo.each(this.selections, function(s) {
12606 Roo.fly(node).removeClass(this.selectedClass);
12613 this.selections= ns;
12614 this.fireEvent("selectionchange", this, this.selections);
12618 * Gets a template node.
12619 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12620 * @return {HTMLElement} The node or null if it wasn't found
12622 getNode : function(nodeInfo){
12623 if(typeof nodeInfo == "string"){
12624 return document.getElementById(nodeInfo);
12625 }else if(typeof nodeInfo == "number"){
12626 return this.nodes[nodeInfo];
12632 * Gets a range template nodes.
12633 * @param {Number} startIndex
12634 * @param {Number} endIndex
12635 * @return {Array} An array of nodes
12637 getNodes : function(start, end){
12638 var ns = this.nodes;
12639 start = start || 0;
12640 end = typeof end == "undefined" ? ns.length - 1 : end;
12643 for(var i = start; i <= end; i++){
12647 for(var i = start; i >= end; i--){
12655 * Finds the index of the passed node
12656 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12657 * @return {Number} The index of the node or -1
12659 indexOf : function(node){
12660 node = this.getNode(node);
12661 if(typeof node.nodeIndex == "number"){
12662 return node.nodeIndex;
12664 var ns = this.nodes;
12665 for(var i = 0, len = ns.length; i < len; i++){
12676 * based on jquery fullcalendar
12680 Roo.bootstrap = Roo.bootstrap || {};
12682 * @class Roo.bootstrap.Calendar
12683 * @extends Roo.bootstrap.Component
12684 * Bootstrap Calendar class
12685 * @cfg {Boolean} loadMask (true|false) default false
12686 * @cfg {Object} header generate the user specific header of the calendar, default false
12689 * Create a new Container
12690 * @param {Object} config The config object
12695 Roo.bootstrap.Calendar = function(config){
12696 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12700 * Fires when a date is selected
12701 * @param {DatePicker} this
12702 * @param {Date} date The selected date
12706 * @event monthchange
12707 * Fires when the displayed month changes
12708 * @param {DatePicker} this
12709 * @param {Date} date The selected month
12711 'monthchange': true,
12713 * @event evententer
12714 * Fires when mouse over an event
12715 * @param {Calendar} this
12716 * @param {event} Event
12718 'evententer': true,
12720 * @event eventleave
12721 * Fires when the mouse leaves an
12722 * @param {Calendar} this
12725 'eventleave': true,
12727 * @event eventclick
12728 * Fires when the mouse click an
12729 * @param {Calendar} this
12738 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12741 * @cfg {Number} startDay
12742 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12750 getAutoCreate : function(){
12753 var fc_button = function(name, corner, style, content ) {
12754 return Roo.apply({},{
12756 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12758 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12761 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12772 style : 'width:100%',
12779 cls : 'fc-header-left',
12781 fc_button('prev', 'left', 'arrow', '‹' ),
12782 fc_button('next', 'right', 'arrow', '›' ),
12783 { tag: 'span', cls: 'fc-header-space' },
12784 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12792 cls : 'fc-header-center',
12796 cls: 'fc-header-title',
12799 html : 'month / year'
12807 cls : 'fc-header-right',
12809 /* fc_button('month', 'left', '', 'month' ),
12810 fc_button('week', '', '', 'week' ),
12811 fc_button('day', 'right', '', 'day' )
12823 header = this.header;
12826 var cal_heads = function() {
12828 // fixme - handle this.
12830 for (var i =0; i < Date.dayNames.length; i++) {
12831 var d = Date.dayNames[i];
12834 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12835 html : d.substring(0,3)
12839 ret[0].cls += ' fc-first';
12840 ret[6].cls += ' fc-last';
12843 var cal_cell = function(n) {
12846 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12851 cls: 'fc-day-number',
12855 cls: 'fc-day-content',
12859 style: 'position: relative;' // height: 17px;
12871 var cal_rows = function() {
12874 for (var r = 0; r < 6; r++) {
12881 for (var i =0; i < Date.dayNames.length; i++) {
12882 var d = Date.dayNames[i];
12883 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12886 row.cn[0].cls+=' fc-first';
12887 row.cn[0].cn[0].style = 'min-height:90px';
12888 row.cn[6].cls+=' fc-last';
12892 ret[0].cls += ' fc-first';
12893 ret[4].cls += ' fc-prev-last';
12894 ret[5].cls += ' fc-last';
12901 cls: 'fc-border-separate',
12902 style : 'width:100%',
12910 cls : 'fc-first fc-last',
12928 cls : 'fc-content',
12929 style : "position: relative;",
12932 cls : 'fc-view fc-view-month fc-grid',
12933 style : 'position: relative',
12934 unselectable : 'on',
12937 cls : 'fc-event-container',
12938 style : 'position:absolute;z-index:8;top:0;left:0;'
12956 initEvents : function()
12959 throw "can not find store for calendar";
12965 style: "text-align:center",
12969 style: "background-color:white;width:50%;margin:250 auto",
12973 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12984 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12986 var size = this.el.select('.fc-content', true).first().getSize();
12987 this.maskEl.setSize(size.width, size.height);
12988 this.maskEl.enableDisplayMode("block");
12989 if(!this.loadMask){
12990 this.maskEl.hide();
12993 this.store = Roo.factory(this.store, Roo.data);
12994 this.store.on('load', this.onLoad, this);
12995 this.store.on('beforeload', this.onBeforeLoad, this);
12999 this.cells = this.el.select('.fc-day',true);
13000 //Roo.log(this.cells);
13001 this.textNodes = this.el.query('.fc-day-number');
13002 this.cells.addClassOnOver('fc-state-hover');
13004 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13005 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13006 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13007 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13009 this.on('monthchange', this.onMonthChange, this);
13011 this.update(new Date().clearTime());
13014 resize : function() {
13015 var sz = this.el.getSize();
13017 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13018 this.el.select('.fc-day-content div',true).setHeight(34);
13023 showPrevMonth : function(e){
13024 this.update(this.activeDate.add("mo", -1));
13026 showToday : function(e){
13027 this.update(new Date().clearTime());
13030 showNextMonth : function(e){
13031 this.update(this.activeDate.add("mo", 1));
13035 showPrevYear : function(){
13036 this.update(this.activeDate.add("y", -1));
13040 showNextYear : function(){
13041 this.update(this.activeDate.add("y", 1));
13046 update : function(date)
13048 var vd = this.activeDate;
13049 this.activeDate = date;
13050 // if(vd && this.el){
13051 // var t = date.getTime();
13052 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13053 // Roo.log('using add remove');
13055 // this.fireEvent('monthchange', this, date);
13057 // this.cells.removeClass("fc-state-highlight");
13058 // this.cells.each(function(c){
13059 // if(c.dateValue == t){
13060 // c.addClass("fc-state-highlight");
13061 // setTimeout(function(){
13062 // try{c.dom.firstChild.focus();}catch(e){}
13072 var days = date.getDaysInMonth();
13074 var firstOfMonth = date.getFirstDateOfMonth();
13075 var startingPos = firstOfMonth.getDay()-this.startDay;
13077 if(startingPos < this.startDay){
13081 var pm = date.add(Date.MONTH, -1);
13082 var prevStart = pm.getDaysInMonth()-startingPos;
13084 this.cells = this.el.select('.fc-day',true);
13085 this.textNodes = this.el.query('.fc-day-number');
13086 this.cells.addClassOnOver('fc-state-hover');
13088 var cells = this.cells.elements;
13089 var textEls = this.textNodes;
13091 Roo.each(cells, function(cell){
13092 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13095 days += startingPos;
13097 // convert everything to numbers so it's fast
13098 var day = 86400000;
13099 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13102 //Roo.log(prevStart);
13104 var today = new Date().clearTime().getTime();
13105 var sel = date.clearTime().getTime();
13106 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13107 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13108 var ddMatch = this.disabledDatesRE;
13109 var ddText = this.disabledDatesText;
13110 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13111 var ddaysText = this.disabledDaysText;
13112 var format = this.format;
13114 var setCellClass = function(cal, cell){
13118 //Roo.log('set Cell Class');
13120 var t = d.getTime();
13124 cell.dateValue = t;
13126 cell.className += " fc-today";
13127 cell.className += " fc-state-highlight";
13128 cell.title = cal.todayText;
13131 // disable highlight in other month..
13132 //cell.className += " fc-state-highlight";
13137 cell.className = " fc-state-disabled";
13138 cell.title = cal.minText;
13142 cell.className = " fc-state-disabled";
13143 cell.title = cal.maxText;
13147 if(ddays.indexOf(d.getDay()) != -1){
13148 cell.title = ddaysText;
13149 cell.className = " fc-state-disabled";
13152 if(ddMatch && format){
13153 var fvalue = d.dateFormat(format);
13154 if(ddMatch.test(fvalue)){
13155 cell.title = ddText.replace("%0", fvalue);
13156 cell.className = " fc-state-disabled";
13160 if (!cell.initialClassName) {
13161 cell.initialClassName = cell.dom.className;
13164 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13169 for(; i < startingPos; i++) {
13170 textEls[i].innerHTML = (++prevStart);
13171 d.setDate(d.getDate()+1);
13173 cells[i].className = "fc-past fc-other-month";
13174 setCellClass(this, cells[i]);
13179 for(; i < days; i++){
13180 intDay = i - startingPos + 1;
13181 textEls[i].innerHTML = (intDay);
13182 d.setDate(d.getDate()+1);
13184 cells[i].className = ''; // "x-date-active";
13185 setCellClass(this, cells[i]);
13189 for(; i < 42; i++) {
13190 textEls[i].innerHTML = (++extraDays);
13191 d.setDate(d.getDate()+1);
13193 cells[i].className = "fc-future fc-other-month";
13194 setCellClass(this, cells[i]);
13197 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13199 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13201 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13202 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13204 if(totalRows != 6){
13205 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13206 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13209 this.fireEvent('monthchange', this, date);
13213 if(!this.internalRender){
13214 var main = this.el.dom.firstChild;
13215 var w = main.offsetWidth;
13216 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13217 Roo.fly(main).setWidth(w);
13218 this.internalRender = true;
13219 // opera does not respect the auto grow header center column
13220 // then, after it gets a width opera refuses to recalculate
13221 // without a second pass
13222 if(Roo.isOpera && !this.secondPass){
13223 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13224 this.secondPass = true;
13225 this.update.defer(10, this, [date]);
13232 findCell : function(dt) {
13233 dt = dt.clearTime().getTime();
13235 this.cells.each(function(c){
13236 //Roo.log("check " +c.dateValue + '?=' + dt);
13237 if(c.dateValue == dt){
13247 findCells : function(ev) {
13248 var s = ev.start.clone().clearTime().getTime();
13250 var e= ev.end.clone().clearTime().getTime();
13253 this.cells.each(function(c){
13254 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13256 if(c.dateValue > e){
13259 if(c.dateValue < s){
13268 // findBestRow: function(cells)
13272 // for (var i =0 ; i < cells.length;i++) {
13273 // ret = Math.max(cells[i].rows || 0,ret);
13280 addItem : function(ev)
13282 // look for vertical location slot in
13283 var cells = this.findCells(ev);
13285 // ev.row = this.findBestRow(cells);
13287 // work out the location.
13291 for(var i =0; i < cells.length; i++) {
13293 cells[i].row = cells[0].row;
13296 cells[i].row = cells[i].row + 1;
13306 if (crow.start.getY() == cells[i].getY()) {
13308 crow.end = cells[i];
13325 cells[0].events.push(ev);
13327 this.calevents.push(ev);
13330 clearEvents: function() {
13332 if(!this.calevents){
13336 Roo.each(this.cells.elements, function(c){
13342 Roo.each(this.calevents, function(e) {
13343 Roo.each(e.els, function(el) {
13344 el.un('mouseenter' ,this.onEventEnter, this);
13345 el.un('mouseleave' ,this.onEventLeave, this);
13350 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13356 renderEvents: function()
13360 this.cells.each(function(c) {
13369 if(c.row != c.events.length){
13370 r = 4 - (4 - (c.row - c.events.length));
13373 c.events = ev.slice(0, r);
13374 c.more = ev.slice(r);
13376 if(c.more.length && c.more.length == 1){
13377 c.events.push(c.more.pop());
13380 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13384 this.cells.each(function(c) {
13386 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13389 for (var e = 0; e < c.events.length; e++){
13390 var ev = c.events[e];
13391 var rows = ev.rows;
13393 for(var i = 0; i < rows.length; i++) {
13395 // how many rows should it span..
13398 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13399 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13401 unselectable : "on",
13404 cls: 'fc-event-inner',
13408 // cls: 'fc-event-time',
13409 // html : cells.length > 1 ? '' : ev.time
13413 cls: 'fc-event-title',
13414 html : String.format('{0}', ev.title)
13421 cls: 'ui-resizable-handle ui-resizable-e',
13422 html : '  '
13429 cfg.cls += ' fc-event-start';
13431 if ((i+1) == rows.length) {
13432 cfg.cls += ' fc-event-end';
13435 var ctr = _this.el.select('.fc-event-container',true).first();
13436 var cg = ctr.createChild(cfg);
13438 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13439 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13441 var r = (c.more.length) ? 1 : 0;
13442 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13443 cg.setWidth(ebox.right - sbox.x -2);
13445 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13446 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13447 cg.on('click', _this.onEventClick, _this, ev);
13458 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13459 style : 'position: absolute',
13460 unselectable : "on",
13463 cls: 'fc-event-inner',
13467 cls: 'fc-event-title',
13475 cls: 'ui-resizable-handle ui-resizable-e',
13476 html : '  '
13482 var ctr = _this.el.select('.fc-event-container',true).first();
13483 var cg = ctr.createChild(cfg);
13485 var sbox = c.select('.fc-day-content',true).first().getBox();
13486 var ebox = c.select('.fc-day-content',true).first().getBox();
13488 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13489 cg.setWidth(ebox.right - sbox.x -2);
13491 cg.on('click', _this.onMoreEventClick, _this, c.more);
13501 onEventEnter: function (e, el,event,d) {
13502 this.fireEvent('evententer', this, el, event);
13505 onEventLeave: function (e, el,event,d) {
13506 this.fireEvent('eventleave', this, el, event);
13509 onEventClick: function (e, el,event,d) {
13510 this.fireEvent('eventclick', this, el, event);
13513 onMonthChange: function () {
13517 onMoreEventClick: function(e, el, more)
13521 this.calpopover.placement = 'right';
13522 this.calpopover.setTitle('More');
13524 this.calpopover.setContent('');
13526 var ctr = this.calpopover.el.select('.popover-content', true).first();
13528 Roo.each(more, function(m){
13530 cls : 'fc-event-hori fc-event-draggable',
13533 var cg = ctr.createChild(cfg);
13535 cg.on('click', _this.onEventClick, _this, m);
13538 this.calpopover.show(el);
13543 onLoad: function ()
13545 this.calevents = [];
13548 if(this.store.getCount() > 0){
13549 this.store.data.each(function(d){
13552 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13553 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13554 time : d.data.start_time,
13555 title : d.data.title,
13556 description : d.data.description,
13557 venue : d.data.venue
13562 this.renderEvents();
13564 if(this.calevents.length && this.loadMask){
13565 this.maskEl.hide();
13569 onBeforeLoad: function()
13571 this.clearEvents();
13573 this.maskEl.show();
13587 * @class Roo.bootstrap.Popover
13588 * @extends Roo.bootstrap.Component
13589 * Bootstrap Popover class
13590 * @cfg {String} html contents of the popover (or false to use children..)
13591 * @cfg {String} title of popover (or false to hide)
13592 * @cfg {String} placement how it is placed
13593 * @cfg {String} trigger click || hover (or false to trigger manually)
13594 * @cfg {String} over what (parent or false to trigger manually.)
13597 * Create a new Popover
13598 * @param {Object} config The config object
13601 Roo.bootstrap.Popover = function(config){
13602 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13605 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13607 title: 'Fill in a title',
13610 placement : 'right',
13611 trigger : 'hover', // hover
13615 can_build_overlaid : false,
13617 getChildContainer : function()
13619 return this.el.select('.popover-content',true).first();
13622 getAutoCreate : function(){
13623 Roo.log('make popover?');
13625 cls : 'popover roo-dynamic',
13626 style: 'display:block',
13632 cls : 'popover-inner',
13636 cls: 'popover-title',
13640 cls : 'popover-content',
13651 setTitle: function(str)
13653 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13655 setContent: function(str)
13657 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13659 // as it get's added to the bottom of the page.
13660 onRender : function(ct, position)
13662 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13664 var cfg = Roo.apply({}, this.getAutoCreate());
13668 cfg.cls += ' ' + this.cls;
13671 cfg.style = this.style;
13673 Roo.log("adding to ")
13674 this.el = Roo.get(document.body).createChild(cfg, position);
13680 initEvents : function()
13682 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13683 this.el.enableDisplayMode('block');
13685 if (this.over === false) {
13688 if (this.triggers === false) {
13691 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13692 var triggers = this.trigger ? this.trigger.split(' ') : [];
13693 Roo.each(triggers, function(trigger) {
13695 if (trigger == 'click') {
13696 on_el.on('click', this.toggle, this);
13697 } else if (trigger != 'manual') {
13698 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13699 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13701 on_el.on(eventIn ,this.enter, this);
13702 on_el.on(eventOut, this.leave, this);
13713 toggle : function () {
13714 this.hoverState == 'in' ? this.leave() : this.enter();
13717 enter : function () {
13720 clearTimeout(this.timeout);
13722 this.hoverState = 'in'
13724 if (!this.delay || !this.delay.show) {
13729 this.timeout = setTimeout(function () {
13730 if (_t.hoverState == 'in') {
13733 }, this.delay.show)
13735 leave : function() {
13736 clearTimeout(this.timeout);
13738 this.hoverState = 'out'
13740 if (!this.delay || !this.delay.hide) {
13745 this.timeout = setTimeout(function () {
13746 if (_t.hoverState == 'out') {
13749 }, this.delay.hide)
13752 show : function (on_el)
13755 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13758 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13759 if (this.html !== false) {
13760 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13762 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13763 if (!this.title.length) {
13764 this.el.select('.popover-title',true).hide();
13767 var placement = typeof this.placement == 'function' ?
13768 this.placement.call(this, this.el, on_el) :
13771 var autoToken = /\s?auto?\s?/i;
13772 var autoPlace = autoToken.test(placement);
13774 placement = placement.replace(autoToken, '') || 'top';
13778 //this.el.setXY([0,0]);
13780 this.el.dom.style.display='block';
13781 this.el.addClass(placement);
13783 //this.el.appendTo(on_el);
13785 var p = this.getPosition();
13786 var box = this.el.getBox();
13791 var align = Roo.bootstrap.Popover.alignment[placement]
13792 this.el.alignTo(on_el, align[0],align[1]);
13793 //var arrow = this.el.select('.arrow',true).first();
13794 //arrow.set(align[2],
13796 this.el.addClass('in');
13797 this.hoverState = null;
13799 if (this.el.hasClass('fade')) {
13806 this.el.setXY([0,0]);
13807 this.el.removeClass('in');
13814 Roo.bootstrap.Popover.alignment = {
13815 'left' : ['r-l', [-10,0], 'right'],
13816 'right' : ['l-r', [10,0], 'left'],
13817 'bottom' : ['t-b', [0,10], 'top'],
13818 'top' : [ 'b-t', [0,-10], 'bottom']
13829 * @class Roo.bootstrap.Progress
13830 * @extends Roo.bootstrap.Component
13831 * Bootstrap Progress class
13832 * @cfg {Boolean} striped striped of the progress bar
13833 * @cfg {Boolean} active animated of the progress bar
13837 * Create a new Progress
13838 * @param {Object} config The config object
13841 Roo.bootstrap.Progress = function(config){
13842 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13845 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13850 getAutoCreate : function(){
13858 cfg.cls += ' progress-striped';
13862 cfg.cls += ' active';
13881 * @class Roo.bootstrap.ProgressBar
13882 * @extends Roo.bootstrap.Component
13883 * Bootstrap ProgressBar class
13884 * @cfg {Number} aria_valuenow aria-value now
13885 * @cfg {Number} aria_valuemin aria-value min
13886 * @cfg {Number} aria_valuemax aria-value max
13887 * @cfg {String} label label for the progress bar
13888 * @cfg {String} panel (success | info | warning | danger )
13889 * @cfg {String} role role of the progress bar
13890 * @cfg {String} sr_only text
13894 * Create a new ProgressBar
13895 * @param {Object} config The config object
13898 Roo.bootstrap.ProgressBar = function(config){
13899 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13902 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13906 aria_valuemax : 100,
13912 getAutoCreate : function()
13917 cls: 'progress-bar',
13918 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13930 cfg.role = this.role;
13933 if(this.aria_valuenow){
13934 cfg['aria-valuenow'] = this.aria_valuenow;
13937 if(this.aria_valuemin){
13938 cfg['aria-valuemin'] = this.aria_valuemin;
13941 if(this.aria_valuemax){
13942 cfg['aria-valuemax'] = this.aria_valuemax;
13945 if(this.label && !this.sr_only){
13946 cfg.html = this.label;
13950 cfg.cls += ' progress-bar-' + this.panel;
13956 update : function(aria_valuenow)
13958 this.aria_valuenow = aria_valuenow;
13960 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13975 * @class Roo.bootstrap.TabGroup
13976 * @extends Roo.bootstrap.Column
13977 * Bootstrap Column class
13978 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13979 * @cfg {Boolean} carousel true to make the group behave like a carousel
13982 * Create a new TabGroup
13983 * @param {Object} config The config object
13986 Roo.bootstrap.TabGroup = function(config){
13987 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13989 this.navId = Roo.id();
13992 Roo.bootstrap.TabGroup.register(this);
13996 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13999 transition : false,
14001 getAutoCreate : function()
14003 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14005 cfg.cls += ' tab-content';
14007 if (this.carousel) {
14008 cfg.cls += ' carousel slide';
14010 cls : 'carousel-inner'
14017 getChildContainer : function()
14019 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14023 * register a Navigation item
14024 * @param {Roo.bootstrap.NavItem} the navitem to add
14026 register : function(item)
14028 this.tabs.push( item);
14029 item.navId = this.navId; // not really needed..
14033 getActivePanel : function()
14036 Roo.each(this.tabs, function(t) {
14046 getPanelByName : function(n)
14049 Roo.each(this.tabs, function(t) {
14050 if (t.tabId == n) {
14058 indexOfPanel : function(p)
14061 Roo.each(this.tabs, function(t,i) {
14062 if (t.tabId == p.tabId) {
14071 * show a specific panel
14072 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14073 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14075 showPanel : function (pan)
14078 if (typeof(pan) == 'number') {
14079 pan = this.tabs[pan];
14081 if (typeof(pan) == 'string') {
14082 pan = this.getPanelByName(pan);
14084 if (pan.tabId == this.getActivePanel().tabId) {
14087 var cur = this.getActivePanel();
14089 if (false === cur.fireEvent('beforedeactivate')) {
14093 if (this.carousel) {
14094 this.transition = true;
14095 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14096 var lr = dir == 'next' ? 'left' : 'right';
14097 pan.el.addClass(dir); // or prev
14098 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14099 cur.el.addClass(lr); // or right
14100 pan.el.addClass(lr);
14103 cur.el.on('transitionend', function() {
14104 Roo.log("trans end?");
14106 pan.el.removeClass([lr,dir]);
14107 pan.setActive(true);
14109 cur.el.removeClass([lr]);
14110 cur.setActive(false);
14112 _this.transition = false;
14114 }, this, { single: true } );
14118 cur.setActive(false);
14119 pan.setActive(true);
14123 showPanelNext : function()
14125 var i = this.indexOfPanel(this.getActivePanel());
14126 if (i > this.tabs.length) {
14129 this.showPanel(this.tabs[i+1]);
14131 showPanelPrev : function()
14133 var i = this.indexOfPanel(this.getActivePanel());
14137 this.showPanel(this.tabs[i-1]);
14148 Roo.apply(Roo.bootstrap.TabGroup, {
14152 * register a Navigation Group
14153 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14155 register : function(navgrp)
14157 this.groups[navgrp.navId] = navgrp;
14161 * fetch a Navigation Group based on the navigation ID
14162 * if one does not exist , it will get created.
14163 * @param {string} the navgroup to add
14164 * @returns {Roo.bootstrap.NavGroup} the navgroup
14166 get: function(navId) {
14167 if (typeof(this.groups[navId]) == 'undefined') {
14168 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14170 return this.groups[navId] ;
14185 * @class Roo.bootstrap.TabPanel
14186 * @extends Roo.bootstrap.Component
14187 * Bootstrap TabPanel class
14188 * @cfg {Boolean} active panel active
14189 * @cfg {String} html panel content
14190 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14191 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14195 * Create a new TabPanel
14196 * @param {Object} config The config object
14199 Roo.bootstrap.TabPanel = function(config){
14200 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14204 * Fires when the active status changes
14205 * @param {Roo.bootstrap.TabPanel} this
14206 * @param {Boolean} state the new state
14211 * @event beforedeactivate
14212 * Fires before a tab is de-activated - can be used to do validation on a form.
14213 * @param {Roo.bootstrap.TabPanel} this
14214 * @return {Boolean} false if there is an error
14217 'beforedeactivate': true
14220 this.tabId = this.tabId || Roo.id();
14224 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14231 getAutoCreate : function(){
14234 // item is needed for carousel - not sure if it has any effect otherwise
14235 cls: 'tab-pane item',
14236 html: this.html || ''
14240 cfg.cls += ' active';
14244 cfg.tabId = this.tabId;
14251 initEvents: function()
14253 Roo.log('-------- init events on tab panel ---------');
14255 var p = this.parent();
14256 this.navId = this.navId || p.navId;
14258 if (typeof(this.navId) != 'undefined') {
14259 // not really needed.. but just in case.. parent should be a NavGroup.
14260 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14261 Roo.log(['register', tg, this]);
14267 onRender : function(ct, position)
14269 // Roo.log("Call onRender: " + this.xtype);
14271 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14279 setActive: function(state)
14281 Roo.log("panel - set active " + this.tabId + "=" + state);
14283 this.active = state;
14285 this.el.removeClass('active');
14287 } else if (!this.el.hasClass('active')) {
14288 this.el.addClass('active');
14290 this.fireEvent('changed', this, state);
14307 * @class Roo.bootstrap.DateField
14308 * @extends Roo.bootstrap.Input
14309 * Bootstrap DateField class
14310 * @cfg {Number} weekStart default 0
14311 * @cfg {Number} weekStart default 0
14312 * @cfg {Number} viewMode default empty, (months|years)
14313 * @cfg {Number} minViewMode default empty, (months|years)
14314 * @cfg {Number} startDate default -Infinity
14315 * @cfg {Number} endDate default Infinity
14316 * @cfg {Boolean} todayHighlight default false
14317 * @cfg {Boolean} todayBtn default false
14318 * @cfg {Boolean} calendarWeeks default false
14319 * @cfg {Object} daysOfWeekDisabled default empty
14321 * @cfg {Boolean} keyboardNavigation default true
14322 * @cfg {String} language default en
14325 * Create a new DateField
14326 * @param {Object} config The config object
14329 Roo.bootstrap.DateField = function(config){
14330 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14334 * Fires when this field show.
14335 * @param {Roo.bootstrap.DateField} this
14336 * @param {Mixed} date The date value
14341 * Fires when this field hide.
14342 * @param {Roo.bootstrap.DateField} this
14343 * @param {Mixed} date The date value
14348 * Fires when select a date.
14349 * @param {Roo.bootstrap.DateField} this
14350 * @param {Mixed} date The date value
14356 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14359 * @cfg {String} format
14360 * The default date format string which can be overriden for localization support. The format must be
14361 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14365 * @cfg {String} altFormats
14366 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14367 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14369 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14377 todayHighlight : false,
14383 keyboardNavigation: true,
14385 calendarWeeks: false,
14387 startDate: -Infinity,
14391 daysOfWeekDisabled: [],
14395 UTCDate: function()
14397 return new Date(Date.UTC.apply(Date, arguments));
14400 UTCToday: function()
14402 var today = new Date();
14403 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14406 getDate: function() {
14407 var d = this.getUTCDate();
14408 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14411 getUTCDate: function() {
14415 setDate: function(d) {
14416 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14419 setUTCDate: function(d) {
14421 this.setValue(this.formatDate(this.date));
14424 onRender: function(ct, position)
14427 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14429 this.language = this.language || 'en';
14430 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14431 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14433 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14434 this.format = this.format || 'm/d/y';
14435 this.isInline = false;
14436 this.isInput = true;
14437 this.component = this.el.select('.add-on', true).first() || false;
14438 this.component = (this.component && this.component.length === 0) ? false : this.component;
14439 this.hasInput = this.component && this.inputEL().length;
14441 if (typeof(this.minViewMode === 'string')) {
14442 switch (this.minViewMode) {
14444 this.minViewMode = 1;
14447 this.minViewMode = 2;
14450 this.minViewMode = 0;
14455 if (typeof(this.viewMode === 'string')) {
14456 switch (this.viewMode) {
14469 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14471 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14473 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14475 this.picker().on('mousedown', this.onMousedown, this);
14476 this.picker().on('click', this.onClick, this);
14478 this.picker().addClass('datepicker-dropdown');
14480 this.startViewMode = this.viewMode;
14483 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14484 if(!this.calendarWeeks){
14489 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14490 v.attr('colspan', function(i, val){
14491 return parseInt(val) + 1;
14496 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14498 this.setStartDate(this.startDate);
14499 this.setEndDate(this.endDate);
14501 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14508 if(this.isInline) {
14513 picker : function()
14515 return this.pickerEl;
14516 // return this.el.select('.datepicker', true).first();
14519 fillDow: function()
14521 var dowCnt = this.weekStart;
14530 if(this.calendarWeeks){
14538 while (dowCnt < this.weekStart + 7) {
14542 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14546 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14549 fillMonths: function()
14552 var months = this.picker().select('>.datepicker-months td', true).first();
14554 months.dom.innerHTML = '';
14560 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14563 months.createChild(month);
14570 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;
14572 if (this.date < this.startDate) {
14573 this.viewDate = new Date(this.startDate);
14574 } else if (this.date > this.endDate) {
14575 this.viewDate = new Date(this.endDate);
14577 this.viewDate = new Date(this.date);
14585 var d = new Date(this.viewDate),
14586 year = d.getUTCFullYear(),
14587 month = d.getUTCMonth(),
14588 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14589 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14590 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14591 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14592 currentDate = this.date && this.date.valueOf(),
14593 today = this.UTCToday();
14595 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14597 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14599 // this.picker.select('>tfoot th.today').
14600 // .text(dates[this.language].today)
14601 // .toggle(this.todayBtn !== false);
14603 this.updateNavArrows();
14606 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14608 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14610 prevMonth.setUTCDate(day);
14612 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14614 var nextMonth = new Date(prevMonth);
14616 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14618 nextMonth = nextMonth.valueOf();
14620 var fillMonths = false;
14622 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14624 while(prevMonth.valueOf() < nextMonth) {
14627 if (prevMonth.getUTCDay() === this.weekStart) {
14629 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14637 if(this.calendarWeeks){
14638 // ISO 8601: First week contains first thursday.
14639 // ISO also states week starts on Monday, but we can be more abstract here.
14641 // Start of current week: based on weekstart/current date
14642 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14643 // Thursday of this week
14644 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14645 // First Thursday of year, year from thursday
14646 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14647 // Calendar week: ms between thursdays, div ms per day, div 7 days
14648 calWeek = (th - yth) / 864e5 / 7 + 1;
14650 fillMonths.cn.push({
14658 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14660 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14663 if (this.todayHighlight &&
14664 prevMonth.getUTCFullYear() == today.getFullYear() &&
14665 prevMonth.getUTCMonth() == today.getMonth() &&
14666 prevMonth.getUTCDate() == today.getDate()) {
14667 clsName += ' today';
14670 if (currentDate && prevMonth.valueOf() === currentDate) {
14671 clsName += ' active';
14674 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14675 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14676 clsName += ' disabled';
14679 fillMonths.cn.push({
14681 cls: 'day ' + clsName,
14682 html: prevMonth.getDate()
14685 prevMonth.setDate(prevMonth.getDate()+1);
14688 var currentYear = this.date && this.date.getUTCFullYear();
14689 var currentMonth = this.date && this.date.getUTCMonth();
14691 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14693 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14694 v.removeClass('active');
14696 if(currentYear === year && k === currentMonth){
14697 v.addClass('active');
14700 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14701 v.addClass('disabled');
14707 year = parseInt(year/10, 10) * 10;
14709 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14711 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14714 for (var i = -1; i < 11; i++) {
14715 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14717 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14725 showMode: function(dir)
14728 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14730 Roo.each(this.picker().select('>div',true).elements, function(v){
14731 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14734 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14739 if(this.isInline) return;
14741 this.picker().removeClass(['bottom', 'top']);
14743 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14745 * place to the top of element!
14749 this.picker().addClass('top');
14750 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14755 this.picker().addClass('bottom');
14757 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14760 parseDate : function(value)
14762 if(!value || value instanceof Date){
14765 var v = Date.parseDate(value, this.format);
14766 if (!v && this.useIso) {
14767 v = Date.parseDate(value, 'Y-m-d');
14769 if(!v && this.altFormats){
14770 if(!this.altFormatsArray){
14771 this.altFormatsArray = this.altFormats.split("|");
14773 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14774 v = Date.parseDate(value, this.altFormatsArray[i]);
14780 formatDate : function(date, fmt)
14782 return (!date || !(date instanceof Date)) ?
14783 date : date.dateFormat(fmt || this.format);
14786 onFocus : function()
14788 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14792 onBlur : function()
14794 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14796 var d = this.inputEl().getValue();
14805 this.picker().show();
14809 this.fireEvent('show', this, this.date);
14814 if(this.isInline) return;
14815 this.picker().hide();
14816 this.viewMode = this.startViewMode;
14819 this.fireEvent('hide', this, this.date);
14823 onMousedown: function(e)
14825 e.stopPropagation();
14826 e.preventDefault();
14831 Roo.bootstrap.DateField.superclass.keyup.call(this);
14835 setValue: function(v)
14837 var d = new Date(v).clearTime();
14839 if(isNaN(d.getTime())){
14840 this.date = this.viewDate = '';
14841 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14845 v = this.formatDate(d);
14847 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14849 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14853 this.fireEvent('select', this, this.date);
14857 getValue: function()
14859 return this.formatDate(this.date);
14862 fireKey: function(e)
14864 if (!this.picker().isVisible()){
14865 if (e.keyCode == 27) // allow escape to hide and re-show picker
14870 var dateChanged = false,
14872 newDate, newViewDate;
14877 e.preventDefault();
14881 if (!this.keyboardNavigation) break;
14882 dir = e.keyCode == 37 ? -1 : 1;
14885 newDate = this.moveYear(this.date, dir);
14886 newViewDate = this.moveYear(this.viewDate, dir);
14887 } else if (e.shiftKey){
14888 newDate = this.moveMonth(this.date, dir);
14889 newViewDate = this.moveMonth(this.viewDate, dir);
14891 newDate = new Date(this.date);
14892 newDate.setUTCDate(this.date.getUTCDate() + dir);
14893 newViewDate = new Date(this.viewDate);
14894 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14896 if (this.dateWithinRange(newDate)){
14897 this.date = newDate;
14898 this.viewDate = newViewDate;
14899 this.setValue(this.formatDate(this.date));
14901 e.preventDefault();
14902 dateChanged = true;
14907 if (!this.keyboardNavigation) break;
14908 dir = e.keyCode == 38 ? -1 : 1;
14910 newDate = this.moveYear(this.date, dir);
14911 newViewDate = this.moveYear(this.viewDate, dir);
14912 } else if (e.shiftKey){
14913 newDate = this.moveMonth(this.date, dir);
14914 newViewDate = this.moveMonth(this.viewDate, dir);
14916 newDate = new Date(this.date);
14917 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14918 newViewDate = new Date(this.viewDate);
14919 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14921 if (this.dateWithinRange(newDate)){
14922 this.date = newDate;
14923 this.viewDate = newViewDate;
14924 this.setValue(this.formatDate(this.date));
14926 e.preventDefault();
14927 dateChanged = true;
14931 this.setValue(this.formatDate(this.date));
14933 e.preventDefault();
14936 this.setValue(this.formatDate(this.date));
14950 onClick: function(e)
14952 e.stopPropagation();
14953 e.preventDefault();
14955 var target = e.getTarget();
14957 if(target.nodeName.toLowerCase() === 'i'){
14958 target = Roo.get(target).dom.parentNode;
14961 var nodeName = target.nodeName;
14962 var className = target.className;
14963 var html = target.innerHTML;
14965 switch(nodeName.toLowerCase()) {
14967 switch(className) {
14973 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14974 switch(this.viewMode){
14976 this.viewDate = this.moveMonth(this.viewDate, dir);
14980 this.viewDate = this.moveYear(this.viewDate, dir);
14986 var date = new Date();
14987 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14989 this.setValue(this.formatDate(this.date));
14996 if (className.indexOf('disabled') === -1) {
14997 this.viewDate.setUTCDate(1);
14998 if (className.indexOf('month') !== -1) {
14999 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15001 var year = parseInt(html, 10) || 0;
15002 this.viewDate.setUTCFullYear(year);
15011 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
15012 var day = parseInt(html, 10) || 1;
15013 var year = this.viewDate.getUTCFullYear(),
15014 month = this.viewDate.getUTCMonth();
15016 if (className.indexOf('old') !== -1) {
15023 } else if (className.indexOf('new') !== -1) {
15031 this.date = this.UTCDate(year, month, day,0,0,0,0);
15032 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15034 this.setValue(this.formatDate(this.date));
15041 setStartDate: function(startDate)
15043 this.startDate = startDate || -Infinity;
15044 if (this.startDate !== -Infinity) {
15045 this.startDate = this.parseDate(this.startDate);
15048 this.updateNavArrows();
15051 setEndDate: function(endDate)
15053 this.endDate = endDate || Infinity;
15054 if (this.endDate !== Infinity) {
15055 this.endDate = this.parseDate(this.endDate);
15058 this.updateNavArrows();
15061 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15063 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15064 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15065 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15067 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15068 return parseInt(d, 10);
15071 this.updateNavArrows();
15074 updateNavArrows: function()
15076 var d = new Date(this.viewDate),
15077 year = d.getUTCFullYear(),
15078 month = d.getUTCMonth();
15080 Roo.each(this.picker().select('.prev', true).elements, function(v){
15082 switch (this.viewMode) {
15085 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15091 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15098 Roo.each(this.picker().select('.next', true).elements, function(v){
15100 switch (this.viewMode) {
15103 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15109 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15117 moveMonth: function(date, dir)
15119 if (!dir) return date;
15120 var new_date = new Date(date.valueOf()),
15121 day = new_date.getUTCDate(),
15122 month = new_date.getUTCMonth(),
15123 mag = Math.abs(dir),
15125 dir = dir > 0 ? 1 : -1;
15128 // If going back one month, make sure month is not current month
15129 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15131 return new_date.getUTCMonth() == month;
15133 // If going forward one month, make sure month is as expected
15134 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15136 return new_date.getUTCMonth() != new_month;
15138 new_month = month + dir;
15139 new_date.setUTCMonth(new_month);
15140 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15141 if (new_month < 0 || new_month > 11)
15142 new_month = (new_month + 12) % 12;
15144 // For magnitudes >1, move one month at a time...
15145 for (var i=0; i<mag; i++)
15146 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15147 new_date = this.moveMonth(new_date, dir);
15148 // ...then reset the day, keeping it in the new month
15149 new_month = new_date.getUTCMonth();
15150 new_date.setUTCDate(day);
15152 return new_month != new_date.getUTCMonth();
15155 // Common date-resetting loop -- if date is beyond end of month, make it
15158 new_date.setUTCDate(--day);
15159 new_date.setUTCMonth(new_month);
15164 moveYear: function(date, dir)
15166 return this.moveMonth(date, dir*12);
15169 dateWithinRange: function(date)
15171 return date >= this.startDate && date <= this.endDate;
15177 this.picker().remove();
15182 Roo.apply(Roo.bootstrap.DateField, {
15193 html: '<i class="fa fa-arrow-left"/>'
15203 html: '<i class="fa fa-arrow-right"/>'
15245 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15246 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15247 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15248 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15249 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15262 navFnc: 'FullYear',
15267 navFnc: 'FullYear',
15272 Roo.apply(Roo.bootstrap.DateField, {
15276 cls: 'datepicker dropdown-menu',
15280 cls: 'datepicker-days',
15284 cls: 'table-condensed',
15286 Roo.bootstrap.DateField.head,
15290 Roo.bootstrap.DateField.footer
15297 cls: 'datepicker-months',
15301 cls: 'table-condensed',
15303 Roo.bootstrap.DateField.head,
15304 Roo.bootstrap.DateField.content,
15305 Roo.bootstrap.DateField.footer
15312 cls: 'datepicker-years',
15316 cls: 'table-condensed',
15318 Roo.bootstrap.DateField.head,
15319 Roo.bootstrap.DateField.content,
15320 Roo.bootstrap.DateField.footer
15339 * @class Roo.bootstrap.TimeField
15340 * @extends Roo.bootstrap.Input
15341 * Bootstrap DateField class
15345 * Create a new TimeField
15346 * @param {Object} config The config object
15349 Roo.bootstrap.TimeField = function(config){
15350 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15354 * Fires when this field show.
15355 * @param {Roo.bootstrap.DateField} this
15356 * @param {Mixed} date The date value
15361 * Fires when this field hide.
15362 * @param {Roo.bootstrap.DateField} this
15363 * @param {Mixed} date The date value
15368 * Fires when select a date.
15369 * @param {Roo.bootstrap.DateField} this
15370 * @param {Mixed} date The date value
15376 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15379 * @cfg {String} format
15380 * The default time format string which can be overriden for localization support. The format must be
15381 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15385 onRender: function(ct, position)
15388 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15390 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15392 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15394 this.pop = this.picker().select('>.datepicker-time',true).first();
15395 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15397 this.picker().on('mousedown', this.onMousedown, this);
15398 this.picker().on('click', this.onClick, this);
15400 this.picker().addClass('datepicker-dropdown');
15405 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15406 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15407 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15408 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15409 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15410 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15414 fireKey: function(e){
15415 if (!this.picker().isVisible()){
15416 if (e.keyCode == 27) // allow escape to hide and re-show picker
15421 e.preventDefault();
15429 this.onTogglePeriod();
15432 this.onIncrementMinutes();
15435 this.onDecrementMinutes();
15444 onClick: function(e) {
15445 e.stopPropagation();
15446 e.preventDefault();
15449 picker : function()
15451 return this.el.select('.datepicker', true).first();
15454 fillTime: function()
15456 var time = this.pop.select('tbody', true).first();
15458 time.dom.innerHTML = '';
15473 cls: 'hours-up glyphicon glyphicon-chevron-up'
15493 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15514 cls: 'timepicker-hour',
15529 cls: 'timepicker-minute',
15544 cls: 'btn btn-primary period',
15566 cls: 'hours-down glyphicon glyphicon-chevron-down'
15586 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15604 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15611 var hours = this.time.getHours();
15612 var minutes = this.time.getMinutes();
15625 hours = hours - 12;
15629 hours = '0' + hours;
15633 minutes = '0' + minutes;
15636 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15637 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15638 this.pop.select('button', true).first().dom.innerHTML = period;
15644 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15646 var cls = ['bottom'];
15648 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15655 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15660 this.picker().addClass(cls.join('-'));
15664 Roo.each(cls, function(c){
15666 _this.picker().setTop(_this.inputEl().getHeight());
15670 _this.picker().setTop(0 - _this.picker().getHeight());
15675 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15679 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15686 onFocus : function()
15688 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15692 onBlur : function()
15694 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15700 this.picker().show();
15705 this.fireEvent('show', this, this.date);
15710 this.picker().hide();
15713 this.fireEvent('hide', this, this.date);
15716 setTime : function()
15719 this.setValue(this.time.format(this.format));
15721 this.fireEvent('select', this, this.date);
15726 onMousedown: function(e){
15727 e.stopPropagation();
15728 e.preventDefault();
15731 onIncrementHours: function()
15733 Roo.log('onIncrementHours');
15734 this.time = this.time.add(Date.HOUR, 1);
15739 onDecrementHours: function()
15741 Roo.log('onDecrementHours');
15742 this.time = this.time.add(Date.HOUR, -1);
15746 onIncrementMinutes: function()
15748 Roo.log('onIncrementMinutes');
15749 this.time = this.time.add(Date.MINUTE, 1);
15753 onDecrementMinutes: function()
15755 Roo.log('onDecrementMinutes');
15756 this.time = this.time.add(Date.MINUTE, -1);
15760 onTogglePeriod: function()
15762 Roo.log('onTogglePeriod');
15763 this.time = this.time.add(Date.HOUR, 12);
15770 Roo.apply(Roo.bootstrap.TimeField, {
15800 cls: 'btn btn-info ok',
15812 Roo.apply(Roo.bootstrap.TimeField, {
15816 cls: 'datepicker dropdown-menu',
15820 cls: 'datepicker-time',
15824 cls: 'table-condensed',
15826 Roo.bootstrap.TimeField.content,
15827 Roo.bootstrap.TimeField.footer
15846 * @class Roo.bootstrap.CheckBox
15847 * @extends Roo.bootstrap.Input
15848 * Bootstrap CheckBox class
15850 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15851 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15852 * @cfg {String} boxLabel The text that appears beside the checkbox
15853 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15854 * @cfg {Boolean} checked initnal the element
15858 * Create a new CheckBox
15859 * @param {Object} config The config object
15862 Roo.bootstrap.CheckBox = function(config){
15863 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15868 * Fires when the element is checked or unchecked.
15869 * @param {Roo.bootstrap.CheckBox} this This input
15870 * @param {Boolean} checked The new checked value
15876 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15878 inputType: 'checkbox',
15885 getAutoCreate : function()
15887 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15893 cfg.cls = 'form-group checkbox' //input-group
15901 type : this.inputType,
15902 value : (!this.checked) ? this.valueOff : this.inputValue,
15903 cls : 'roo-checkbox', //'form-box',
15904 placeholder : this.placeholder || ''
15908 if (this.weight) { // Validity check?
15909 cfg.cls += " checkbox-" + this.weight;
15912 if (this.disabled) {
15913 input.disabled=true;
15917 input.checked = this.checked;
15921 input.name = this.name;
15925 input.cls += ' input-' + this.size;
15929 ['xs','sm','md','lg'].map(function(size){
15930 if (settings[size]) {
15931 cfg.cls += ' col-' + size + '-' + settings[size];
15937 var inputblock = input;
15942 if (this.before || this.after) {
15945 cls : 'input-group',
15949 inputblock.cn.push({
15951 cls : 'input-group-addon',
15955 inputblock.cn.push(input);
15957 inputblock.cn.push({
15959 cls : 'input-group-addon',
15966 if (align ==='left' && this.fieldLabel.length) {
15967 Roo.log("left and has label");
15973 cls : 'control-label col-md-' + this.labelWidth,
15974 html : this.fieldLabel
15978 cls : "col-md-" + (12 - this.labelWidth),
15985 } else if ( this.fieldLabel.length) {
15990 tag: this.boxLabel ? 'span' : 'label',
15992 cls: 'control-label box-input-label',
15993 //cls : 'input-group-addon',
15994 html : this.fieldLabel
16004 Roo.log(" no label && no align");
16005 cfg.cn = [ inputblock ] ;
16014 html: this.boxLabel
16026 * return the real input element.
16028 inputEl: function ()
16030 return this.el.select('input.roo-checkbox',true).first();
16035 return this.el.select('label.control-label',true).first();
16038 initEvents : function()
16040 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16042 this.inputEl().on('click', this.onClick, this);
16046 onClick : function()
16048 this.setChecked(!this.checked);
16051 setChecked : function(state,suppressEvent)
16053 this.checked = state;
16055 this.inputEl().dom.checked = state;
16057 if(suppressEvent !== true){
16058 this.fireEvent('check', this, state);
16061 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16065 setValue : function(v,suppressEvent)
16067 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16081 * @class Roo.bootstrap.Radio
16082 * @extends Roo.bootstrap.CheckBox
16083 * Bootstrap Radio class
16086 * Create a new Radio
16087 * @param {Object} config The config object
16090 Roo.bootstrap.Radio = function(config){
16091 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16095 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16097 inputType: 'radio',
16101 getAutoCreate : function()
16103 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16109 cfg.cls = 'form-group radio' //input-group
16114 type : this.inputType,
16115 value : (!this.checked) ? this.valueOff : this.inputValue,
16117 placeholder : this.placeholder || ''
16120 if (this.weight) { // Validity check?
16121 cfg.cls += " radio-" + this.weight;
16123 if (this.disabled) {
16124 input.disabled=true;
16128 input.checked = this.checked;
16132 input.name = this.name;
16136 input.cls += ' input-' + this.size;
16140 ['xs','sm','md','lg'].map(function(size){
16141 if (settings[size]) {
16142 cfg.cls += ' col-' + size + '-' + settings[size];
16146 var inputblock = input;
16148 if (this.before || this.after) {
16151 cls : 'input-group',
16155 inputblock.cn.push({
16157 cls : 'input-group-addon',
16161 inputblock.cn.push(input);
16163 inputblock.cn.push({
16165 cls : 'input-group-addon',
16172 if (align ==='left' && this.fieldLabel.length) {
16173 Roo.log("left and has label");
16179 cls : 'control-label col-md-' + this.labelWidth,
16180 html : this.fieldLabel
16184 cls : "col-md-" + (12 - this.labelWidth),
16191 } else if ( this.fieldLabel.length) {
16198 cls: 'control-label box-input-label',
16199 //cls : 'input-group-addon',
16200 html : this.fieldLabel
16210 Roo.log(" no label && no align");
16225 html: this.boxLabel
16232 inputEl: function ()
16234 return this.el.select('input.roo-radio',true).first();
16236 onClick : function()
16238 this.setChecked(true);
16241 setChecked : function(state,suppressEvent)
16244 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16245 v.dom.checked = false;
16249 this.checked = state;
16250 this.inputEl().dom.checked = state;
16252 if(suppressEvent !== true){
16253 this.fireEvent('check', this, state);
16256 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16260 getGroupValue : function()
16263 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16264 if(v.dom.checked == true){
16265 value = v.dom.value;
16273 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16274 * @return {Mixed} value The field value
16276 getValue : function(){
16277 return this.getGroupValue();
16283 //<script type="text/javascript">
16286 * Based Ext JS Library 1.1.1
16287 * Copyright(c) 2006-2007, Ext JS, LLC.
16293 * @class Roo.HtmlEditorCore
16294 * @extends Roo.Component
16295 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16297 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16300 Roo.HtmlEditorCore = function(config){
16303 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16306 * @event initialize
16307 * Fires when the editor is fully initialized (including the iframe)
16308 * @param {Roo.HtmlEditorCore} this
16313 * Fires when the editor is first receives the focus. Any insertion must wait
16314 * until after this event.
16315 * @param {Roo.HtmlEditorCore} this
16319 * @event beforesync
16320 * Fires before the textarea is updated with content from the editor iframe. Return false
16321 * to cancel the sync.
16322 * @param {Roo.HtmlEditorCore} this
16323 * @param {String} html
16327 * @event beforepush
16328 * Fires before the iframe editor is updated with content from the textarea. Return false
16329 * to cancel the push.
16330 * @param {Roo.HtmlEditorCore} this
16331 * @param {String} html
16336 * Fires when the textarea is updated with content from the editor iframe.
16337 * @param {Roo.HtmlEditorCore} this
16338 * @param {String} html
16343 * Fires when the iframe editor is updated with content from the textarea.
16344 * @param {Roo.HtmlEditorCore} this
16345 * @param {String} html
16350 * @event editorevent
16351 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16352 * @param {Roo.HtmlEditorCore} this
16360 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16364 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16370 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16375 * @cfg {Number} height (in pixels)
16379 * @cfg {Number} width (in pixels)
16384 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16387 stylesheets: false,
16392 // private properties
16393 validationEvent : false,
16395 initialized : false,
16397 sourceEditMode : false,
16398 onFocus : Roo.emptyFn,
16400 hideMode:'offsets',
16408 * Protected method that will not generally be called directly. It
16409 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16410 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16412 getDocMarkup : function(){
16415 Roo.log(this.stylesheets);
16417 // inherit styels from page...??
16418 if (this.stylesheets === false) {
16420 Roo.get(document.head).select('style').each(function(node) {
16421 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16424 Roo.get(document.head).select('link').each(function(node) {
16425 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16428 } else if (!this.stylesheets.length) {
16430 st = '<style type="text/css">' +
16431 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16434 Roo.each(this.stylesheets, function(s) {
16435 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16440 st += '<style type="text/css">' +
16441 'IMG { cursor: pointer } ' +
16445 return '<html><head>' + st +
16446 //<style type="text/css">' +
16447 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16449 ' </head><body class="roo-htmleditor-body"></body></html>';
16453 onRender : function(ct, position)
16456 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16457 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16460 this.el.dom.style.border = '0 none';
16461 this.el.dom.setAttribute('tabIndex', -1);
16462 this.el.addClass('x-hidden hide');
16466 if(Roo.isIE){ // fix IE 1px bogus margin
16467 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16471 this.frameId = Roo.id();
16475 var iframe = this.owner.wrap.createChild({
16477 cls: 'form-control', // bootstrap..
16479 name: this.frameId,
16480 frameBorder : 'no',
16481 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16486 this.iframe = iframe.dom;
16488 this.assignDocWin();
16490 this.doc.designMode = 'on';
16493 this.doc.write(this.getDocMarkup());
16497 var task = { // must defer to wait for browser to be ready
16499 //console.log("run task?" + this.doc.readyState);
16500 this.assignDocWin();
16501 if(this.doc.body || this.doc.readyState == 'complete'){
16503 this.doc.designMode="on";
16507 Roo.TaskMgr.stop(task);
16508 this.initEditor.defer(10, this);
16515 Roo.TaskMgr.start(task);
16522 onResize : function(w, h)
16524 Roo.log('resize: ' +w + ',' + h );
16525 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16529 if(typeof w == 'number'){
16531 this.iframe.style.width = w + 'px';
16533 if(typeof h == 'number'){
16535 this.iframe.style.height = h + 'px';
16537 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16544 * Toggles the editor between standard and source edit mode.
16545 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16547 toggleSourceEdit : function(sourceEditMode){
16549 this.sourceEditMode = sourceEditMode === true;
16551 if(this.sourceEditMode){
16553 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16556 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16557 //this.iframe.className = '';
16560 //this.setSize(this.owner.wrap.getSize());
16561 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16568 * Protected method that will not generally be called directly. If you need/want
16569 * custom HTML cleanup, this is the method you should override.
16570 * @param {String} html The HTML to be cleaned
16571 * return {String} The cleaned HTML
16573 cleanHtml : function(html){
16574 html = String(html);
16575 if(html.length > 5){
16576 if(Roo.isSafari){ // strip safari nonsense
16577 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16580 if(html == ' '){
16587 * HTML Editor -> Textarea
16588 * Protected method that will not generally be called directly. Syncs the contents
16589 * of the editor iframe with the textarea.
16591 syncValue : function(){
16592 if(this.initialized){
16593 var bd = (this.doc.body || this.doc.documentElement);
16594 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16595 var html = bd.innerHTML;
16597 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16598 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16600 html = '<div style="'+m[0]+'">' + html + '</div>';
16603 html = this.cleanHtml(html);
16604 // fix up the special chars.. normaly like back quotes in word...
16605 // however we do not want to do this with chinese..
16606 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16607 var cc = b.charCodeAt();
16609 (cc >= 0x4E00 && cc < 0xA000 ) ||
16610 (cc >= 0x3400 && cc < 0x4E00 ) ||
16611 (cc >= 0xf900 && cc < 0xfb00 )
16617 if(this.owner.fireEvent('beforesync', this, html) !== false){
16618 this.el.dom.value = html;
16619 this.owner.fireEvent('sync', this, html);
16625 * Protected method that will not generally be called directly. Pushes the value of the textarea
16626 * into the iframe editor.
16628 pushValue : function(){
16629 if(this.initialized){
16630 var v = this.el.dom.value.trim();
16632 // if(v.length < 1){
16636 if(this.owner.fireEvent('beforepush', this, v) !== false){
16637 var d = (this.doc.body || this.doc.documentElement);
16639 this.cleanUpPaste();
16640 this.el.dom.value = d.innerHTML;
16641 this.owner.fireEvent('push', this, v);
16647 deferFocus : function(){
16648 this.focus.defer(10, this);
16652 focus : function(){
16653 if(this.win && !this.sourceEditMode){
16660 assignDocWin: function()
16662 var iframe = this.iframe;
16665 this.doc = iframe.contentWindow.document;
16666 this.win = iframe.contentWindow;
16668 // if (!Roo.get(this.frameId)) {
16671 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16672 // this.win = Roo.get(this.frameId).dom.contentWindow;
16674 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16678 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16679 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16684 initEditor : function(){
16685 //console.log("INIT EDITOR");
16686 this.assignDocWin();
16690 this.doc.designMode="on";
16692 this.doc.write(this.getDocMarkup());
16695 var dbody = (this.doc.body || this.doc.documentElement);
16696 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16697 // this copies styles from the containing element into thsi one..
16698 // not sure why we need all of this..
16699 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16701 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16702 //ss['background-attachment'] = 'fixed'; // w3c
16703 dbody.bgProperties = 'fixed'; // ie
16704 //Roo.DomHelper.applyStyles(dbody, ss);
16705 Roo.EventManager.on(this.doc, {
16706 //'mousedown': this.onEditorEvent,
16707 'mouseup': this.onEditorEvent,
16708 'dblclick': this.onEditorEvent,
16709 'click': this.onEditorEvent,
16710 'keyup': this.onEditorEvent,
16715 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16717 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16718 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16720 this.initialized = true;
16722 this.owner.fireEvent('initialize', this);
16727 onDestroy : function(){
16733 //for (var i =0; i < this.toolbars.length;i++) {
16734 // // fixme - ask toolbars for heights?
16735 // this.toolbars[i].onDestroy();
16738 //this.wrap.dom.innerHTML = '';
16739 //this.wrap.remove();
16744 onFirstFocus : function(){
16746 this.assignDocWin();
16749 this.activated = true;
16752 if(Roo.isGecko){ // prevent silly gecko errors
16754 var s = this.win.getSelection();
16755 if(!s.focusNode || s.focusNode.nodeType != 3){
16756 var r = s.getRangeAt(0);
16757 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16762 this.execCmd('useCSS', true);
16763 this.execCmd('styleWithCSS', false);
16766 this.owner.fireEvent('activate', this);
16770 adjustFont: function(btn){
16771 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16772 //if(Roo.isSafari){ // safari
16775 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16776 if(Roo.isSafari){ // safari
16777 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16778 v = (v < 10) ? 10 : v;
16779 v = (v > 48) ? 48 : v;
16780 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16785 v = Math.max(1, v+adjust);
16787 this.execCmd('FontSize', v );
16790 onEditorEvent : function(e){
16791 this.owner.fireEvent('editorevent', this, e);
16792 // this.updateToolbar();
16793 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16796 insertTag : function(tg)
16798 // could be a bit smarter... -> wrap the current selected tRoo..
16799 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16801 range = this.createRange(this.getSelection());
16802 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16803 wrappingNode.appendChild(range.extractContents());
16804 range.insertNode(wrappingNode);
16811 this.execCmd("formatblock", tg);
16815 insertText : function(txt)
16819 var range = this.createRange();
16820 range.deleteContents();
16821 //alert(Sender.getAttribute('label'));
16823 range.insertNode(this.doc.createTextNode(txt));
16829 * Executes a Midas editor command on the editor document and performs necessary focus and
16830 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16831 * @param {String} cmd The Midas command
16832 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16834 relayCmd : function(cmd, value){
16836 this.execCmd(cmd, value);
16837 this.owner.fireEvent('editorevent', this);
16838 //this.updateToolbar();
16839 this.owner.deferFocus();
16843 * Executes a Midas editor command directly on the editor document.
16844 * For visual commands, you should use {@link #relayCmd} instead.
16845 * <b>This should only be called after the editor is initialized.</b>
16846 * @param {String} cmd The Midas command
16847 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16849 execCmd : function(cmd, value){
16850 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16857 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16859 * @param {String} text | dom node..
16861 insertAtCursor : function(text)
16866 if(!this.activated){
16872 var r = this.doc.selection.createRange();
16883 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16887 // from jquery ui (MIT licenced)
16889 var win = this.win;
16891 if (win.getSelection && win.getSelection().getRangeAt) {
16892 range = win.getSelection().getRangeAt(0);
16893 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16894 range.insertNode(node);
16895 } else if (win.document.selection && win.document.selection.createRange) {
16896 // no firefox support
16897 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16898 win.document.selection.createRange().pasteHTML(txt);
16900 // no firefox support
16901 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16902 this.execCmd('InsertHTML', txt);
16911 mozKeyPress : function(e){
16913 var c = e.getCharCode(), cmd;
16916 c = String.fromCharCode(c).toLowerCase();
16930 this.cleanUpPaste.defer(100, this);
16938 e.preventDefault();
16946 fixKeys : function(){ // load time branching for fastest keydown performance
16948 return function(e){
16949 var k = e.getKey(), r;
16952 r = this.doc.selection.createRange();
16955 r.pasteHTML('    ');
16962 r = this.doc.selection.createRange();
16964 var target = r.parentElement();
16965 if(!target || target.tagName.toLowerCase() != 'li'){
16967 r.pasteHTML('<br />');
16973 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16974 this.cleanUpPaste.defer(100, this);
16980 }else if(Roo.isOpera){
16981 return function(e){
16982 var k = e.getKey();
16986 this.execCmd('InsertHTML','    ');
16989 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16990 this.cleanUpPaste.defer(100, this);
16995 }else if(Roo.isSafari){
16996 return function(e){
16997 var k = e.getKey();
17001 this.execCmd('InsertText','\t');
17005 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17006 this.cleanUpPaste.defer(100, this);
17014 getAllAncestors: function()
17016 var p = this.getSelectedNode();
17019 a.push(p); // push blank onto stack..
17020 p = this.getParentElement();
17024 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17028 a.push(this.doc.body);
17032 lastSelNode : false,
17035 getSelection : function()
17037 this.assignDocWin();
17038 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17041 getSelectedNode: function()
17043 // this may only work on Gecko!!!
17045 // should we cache this!!!!
17050 var range = this.createRange(this.getSelection()).cloneRange();
17053 var parent = range.parentElement();
17055 var testRange = range.duplicate();
17056 testRange.moveToElementText(parent);
17057 if (testRange.inRange(range)) {
17060 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17063 parent = parent.parentElement;
17068 // is ancestor a text element.
17069 var ac = range.commonAncestorContainer;
17070 if (ac.nodeType == 3) {
17071 ac = ac.parentNode;
17074 var ar = ac.childNodes;
17077 var other_nodes = [];
17078 var has_other_nodes = false;
17079 for (var i=0;i<ar.length;i++) {
17080 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17083 // fullly contained node.
17085 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17090 // probably selected..
17091 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17092 other_nodes.push(ar[i]);
17096 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17101 has_other_nodes = true;
17103 if (!nodes.length && other_nodes.length) {
17104 nodes= other_nodes;
17106 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17112 createRange: function(sel)
17114 // this has strange effects when using with
17115 // top toolbar - not sure if it's a great idea.
17116 //this.editor.contentWindow.focus();
17117 if (typeof sel != "undefined") {
17119 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17121 return this.doc.createRange();
17124 return this.doc.createRange();
17127 getParentElement: function()
17130 this.assignDocWin();
17131 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17133 var range = this.createRange(sel);
17136 var p = range.commonAncestorContainer;
17137 while (p.nodeType == 3) { // text node
17148 * Range intersection.. the hard stuff...
17152 * [ -- selected range --- ]
17156 * if end is before start or hits it. fail.
17157 * if start is after end or hits it fail.
17159 * if either hits (but other is outside. - then it's not
17165 // @see http://www.thismuchiknow.co.uk/?p=64.
17166 rangeIntersectsNode : function(range, node)
17168 var nodeRange = node.ownerDocument.createRange();
17170 nodeRange.selectNode(node);
17172 nodeRange.selectNodeContents(node);
17175 var rangeStartRange = range.cloneRange();
17176 rangeStartRange.collapse(true);
17178 var rangeEndRange = range.cloneRange();
17179 rangeEndRange.collapse(false);
17181 var nodeStartRange = nodeRange.cloneRange();
17182 nodeStartRange.collapse(true);
17184 var nodeEndRange = nodeRange.cloneRange();
17185 nodeEndRange.collapse(false);
17187 return rangeStartRange.compareBoundaryPoints(
17188 Range.START_TO_START, nodeEndRange) == -1 &&
17189 rangeEndRange.compareBoundaryPoints(
17190 Range.START_TO_START, nodeStartRange) == 1;
17194 rangeCompareNode : function(range, node)
17196 var nodeRange = node.ownerDocument.createRange();
17198 nodeRange.selectNode(node);
17200 nodeRange.selectNodeContents(node);
17204 range.collapse(true);
17206 nodeRange.collapse(true);
17208 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17209 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17211 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17213 var nodeIsBefore = ss == 1;
17214 var nodeIsAfter = ee == -1;
17216 if (nodeIsBefore && nodeIsAfter)
17218 if (!nodeIsBefore && nodeIsAfter)
17219 return 1; //right trailed.
17221 if (nodeIsBefore && !nodeIsAfter)
17222 return 2; // left trailed.
17227 // private? - in a new class?
17228 cleanUpPaste : function()
17230 // cleans up the whole document..
17231 Roo.log('cleanuppaste');
17233 this.cleanUpChildren(this.doc.body);
17234 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17235 if (clean != this.doc.body.innerHTML) {
17236 this.doc.body.innerHTML = clean;
17241 cleanWordChars : function(input) {// change the chars to hex code
17242 var he = Roo.HtmlEditorCore;
17244 var output = input;
17245 Roo.each(he.swapCodes, function(sw) {
17246 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17248 output = output.replace(swapper, sw[1]);
17255 cleanUpChildren : function (n)
17257 if (!n.childNodes.length) {
17260 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17261 this.cleanUpChild(n.childNodes[i]);
17268 cleanUpChild : function (node)
17271 //console.log(node);
17272 if (node.nodeName == "#text") {
17273 // clean up silly Windows -- stuff?
17276 if (node.nodeName == "#comment") {
17277 node.parentNode.removeChild(node);
17278 // clean up silly Windows -- stuff?
17282 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17284 node.parentNode.removeChild(node);
17289 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17291 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17292 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17294 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17295 // remove_keep_children = true;
17298 if (remove_keep_children) {
17299 this.cleanUpChildren(node);
17300 // inserts everything just before this node...
17301 while (node.childNodes.length) {
17302 var cn = node.childNodes[0];
17303 node.removeChild(cn);
17304 node.parentNode.insertBefore(cn, node);
17306 node.parentNode.removeChild(node);
17310 if (!node.attributes || !node.attributes.length) {
17311 this.cleanUpChildren(node);
17315 function cleanAttr(n,v)
17318 if (v.match(/^\./) || v.match(/^\//)) {
17321 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17324 if (v.match(/^#/)) {
17327 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17328 node.removeAttribute(n);
17332 function cleanStyle(n,v)
17334 if (v.match(/expression/)) { //XSS?? should we even bother..
17335 node.removeAttribute(n);
17338 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17339 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17342 var parts = v.split(/;/);
17345 Roo.each(parts, function(p) {
17346 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17350 var l = p.split(':').shift().replace(/\s+/g,'');
17351 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17353 if ( cblack.indexOf(l) > -1) {
17354 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17355 //node.removeAttribute(n);
17359 // only allow 'c whitelisted system attributes'
17360 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17361 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17362 //node.removeAttribute(n);
17372 if (clean.length) {
17373 node.setAttribute(n, clean.join(';'));
17375 node.removeAttribute(n);
17381 for (var i = node.attributes.length-1; i > -1 ; i--) {
17382 var a = node.attributes[i];
17385 if (a.name.toLowerCase().substr(0,2)=='on') {
17386 node.removeAttribute(a.name);
17389 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17390 node.removeAttribute(a.name);
17393 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17394 cleanAttr(a.name,a.value); // fixme..
17397 if (a.name == 'style') {
17398 cleanStyle(a.name,a.value);
17401 /// clean up MS crap..
17402 // tecnically this should be a list of valid class'es..
17405 if (a.name == 'class') {
17406 if (a.value.match(/^Mso/)) {
17407 node.className = '';
17410 if (a.value.match(/body/)) {
17411 node.className = '';
17422 this.cleanUpChildren(node);
17427 * Clean up MS wordisms...
17429 cleanWord : function(node)
17432 var cleanWordChildren = function()
17434 if (!node.childNodes.length) {
17437 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17438 _t.cleanWord(node.childNodes[i]);
17444 this.cleanWord(this.doc.body);
17447 if (node.nodeName == "#text") {
17448 // clean up silly Windows -- stuff?
17451 if (node.nodeName == "#comment") {
17452 node.parentNode.removeChild(node);
17453 // clean up silly Windows -- stuff?
17457 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17458 node.parentNode.removeChild(node);
17462 // remove - but keep children..
17463 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17464 while (node.childNodes.length) {
17465 var cn = node.childNodes[0];
17466 node.removeChild(cn);
17467 node.parentNode.insertBefore(cn, node);
17469 node.parentNode.removeChild(node);
17470 cleanWordChildren();
17474 if (node.className.length) {
17476 var cn = node.className.split(/\W+/);
17478 Roo.each(cn, function(cls) {
17479 if (cls.match(/Mso[a-zA-Z]+/)) {
17484 node.className = cna.length ? cna.join(' ') : '';
17486 node.removeAttribute("class");
17490 if (node.hasAttribute("lang")) {
17491 node.removeAttribute("lang");
17494 if (node.hasAttribute("style")) {
17496 var styles = node.getAttribute("style").split(";");
17498 Roo.each(styles, function(s) {
17499 if (!s.match(/:/)) {
17502 var kv = s.split(":");
17503 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17506 // what ever is left... we allow.
17509 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17510 if (!nstyle.length) {
17511 node.removeAttribute('style');
17515 cleanWordChildren();
17519 domToHTML : function(currentElement, depth, nopadtext) {
17521 depth = depth || 0;
17522 nopadtext = nopadtext || false;
17524 if (!currentElement) {
17525 return this.domToHTML(this.doc.body);
17528 //Roo.log(currentElement);
17530 var allText = false;
17531 var nodeName = currentElement.nodeName;
17532 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17534 if (nodeName == '#text') {
17535 return currentElement.nodeValue;
17540 if (nodeName != 'BODY') {
17543 // Prints the node tagName, such as <A>, <IMG>, etc
17546 for(i = 0; i < currentElement.attributes.length;i++) {
17548 var aname = currentElement.attributes.item(i).name;
17549 if (!currentElement.attributes.item(i).value.length) {
17552 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17555 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17564 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17567 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17572 // Traverse the tree
17574 var currentElementChild = currentElement.childNodes.item(i);
17575 var allText = true;
17576 var innerHTML = '';
17578 while (currentElementChild) {
17579 // Formatting code (indent the tree so it looks nice on the screen)
17580 var nopad = nopadtext;
17581 if (lastnode == 'SPAN') {
17585 if (currentElementChild.nodeName == '#text') {
17586 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17587 if (!nopad && toadd.length > 80) {
17588 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17590 innerHTML += toadd;
17593 currentElementChild = currentElement.childNodes.item(i);
17599 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17601 // Recursively traverse the tree structure of the child node
17602 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17603 lastnode = currentElementChild.nodeName;
17605 currentElementChild=currentElement.childNodes.item(i);
17611 // The remaining code is mostly for formatting the tree
17612 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17617 ret+= "</"+tagName+">";
17623 // hide stuff that is not compatible
17637 * @event specialkey
17641 * @cfg {String} fieldClass @hide
17644 * @cfg {String} focusClass @hide
17647 * @cfg {String} autoCreate @hide
17650 * @cfg {String} inputType @hide
17653 * @cfg {String} invalidClass @hide
17656 * @cfg {String} invalidText @hide
17659 * @cfg {String} msgFx @hide
17662 * @cfg {String} validateOnBlur @hide
17666 Roo.HtmlEditorCore.white = [
17667 'area', 'br', 'img', 'input', 'hr', 'wbr',
17669 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17670 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17671 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17672 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17673 'table', 'ul', 'xmp',
17675 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17678 'dir', 'menu', 'ol', 'ul', 'dl',
17684 Roo.HtmlEditorCore.black = [
17685 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17687 'base', 'basefont', 'bgsound', 'blink', 'body',
17688 'frame', 'frameset', 'head', 'html', 'ilayer',
17689 'iframe', 'layer', 'link', 'meta', 'object',
17690 'script', 'style' ,'title', 'xml' // clean later..
17692 Roo.HtmlEditorCore.clean = [
17693 'script', 'style', 'title', 'xml'
17695 Roo.HtmlEditorCore.remove = [
17700 Roo.HtmlEditorCore.ablack = [
17704 Roo.HtmlEditorCore.aclean = [
17705 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17709 Roo.HtmlEditorCore.pwhite= [
17710 'http', 'https', 'mailto'
17713 // white listed style attributes.
17714 Roo.HtmlEditorCore.cwhite= [
17715 // 'text-align', /// default is to allow most things..
17721 // black listed style attributes.
17722 Roo.HtmlEditorCore.cblack= [
17723 // 'font-size' -- this can be set by the project
17727 Roo.HtmlEditorCore.swapCodes =[
17746 * @class Roo.bootstrap.HtmlEditor
17747 * @extends Roo.bootstrap.TextArea
17748 * Bootstrap HtmlEditor class
17751 * Create a new HtmlEditor
17752 * @param {Object} config The config object
17755 Roo.bootstrap.HtmlEditor = function(config){
17756 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17757 if (!this.toolbars) {
17758 this.toolbars = [];
17760 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17763 * @event initialize
17764 * Fires when the editor is fully initialized (including the iframe)
17765 * @param {HtmlEditor} this
17770 * Fires when the editor is first receives the focus. Any insertion must wait
17771 * until after this event.
17772 * @param {HtmlEditor} this
17776 * @event beforesync
17777 * Fires before the textarea is updated with content from the editor iframe. Return false
17778 * to cancel the sync.
17779 * @param {HtmlEditor} this
17780 * @param {String} html
17784 * @event beforepush
17785 * Fires before the iframe editor is updated with content from the textarea. Return false
17786 * to cancel the push.
17787 * @param {HtmlEditor} this
17788 * @param {String} html
17793 * Fires when the textarea is updated with content from the editor iframe.
17794 * @param {HtmlEditor} this
17795 * @param {String} html
17800 * Fires when the iframe editor is updated with content from the textarea.
17801 * @param {HtmlEditor} this
17802 * @param {String} html
17806 * @event editmodechange
17807 * Fires when the editor switches edit modes
17808 * @param {HtmlEditor} this
17809 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17811 editmodechange: true,
17813 * @event editorevent
17814 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17815 * @param {HtmlEditor} this
17819 * @event firstfocus
17820 * Fires when on first focus - needed by toolbars..
17821 * @param {HtmlEditor} this
17826 * Auto save the htmlEditor value as a file into Events
17827 * @param {HtmlEditor} this
17831 * @event savedpreview
17832 * preview the saved version of htmlEditor
17833 * @param {HtmlEditor} this
17840 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17844 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17849 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17854 * @cfg {Number} height (in pixels)
17858 * @cfg {Number} width (in pixels)
17863 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17866 stylesheets: false,
17871 // private properties
17872 validationEvent : false,
17874 initialized : false,
17877 onFocus : Roo.emptyFn,
17879 hideMode:'offsets',
17882 tbContainer : false,
17884 toolbarContainer :function() {
17885 return this.wrap.select('.x-html-editor-tb',true).first();
17889 * Protected method that will not generally be called directly. It
17890 * is called when the editor creates its toolbar. Override this method if you need to
17891 * add custom toolbar buttons.
17892 * @param {HtmlEditor} editor
17894 createToolbar : function(){
17896 Roo.log("create toolbars");
17898 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17899 this.toolbars[0].render(this.toolbarContainer());
17903 // if (!editor.toolbars || !editor.toolbars.length) {
17904 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17907 // for (var i =0 ; i < editor.toolbars.length;i++) {
17908 // editor.toolbars[i] = Roo.factory(
17909 // typeof(editor.toolbars[i]) == 'string' ?
17910 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17911 // Roo.bootstrap.HtmlEditor);
17912 // editor.toolbars[i].init(editor);
17918 onRender : function(ct, position)
17920 // Roo.log("Call onRender: " + this.xtype);
17922 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17924 this.wrap = this.inputEl().wrap({
17925 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17928 this.editorcore.onRender(ct, position);
17930 if (this.resizable) {
17931 this.resizeEl = new Roo.Resizable(this.wrap, {
17935 minHeight : this.height,
17936 height: this.height,
17937 handles : this.resizable,
17940 resize : function(r, w, h) {
17941 _t.onResize(w,h); // -something
17947 this.createToolbar(this);
17950 if(!this.width && this.resizable){
17951 this.setSize(this.wrap.getSize());
17953 if (this.resizeEl) {
17954 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17955 // should trigger onReize..
17961 onResize : function(w, h)
17963 Roo.log('resize: ' +w + ',' + h );
17964 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17968 if(this.inputEl() ){
17969 if(typeof w == 'number'){
17970 var aw = w - this.wrap.getFrameWidth('lr');
17971 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17974 if(typeof h == 'number'){
17975 var tbh = -11; // fixme it needs to tool bar size!
17976 for (var i =0; i < this.toolbars.length;i++) {
17977 // fixme - ask toolbars for heights?
17978 tbh += this.toolbars[i].el.getHeight();
17979 //if (this.toolbars[i].footer) {
17980 // tbh += this.toolbars[i].footer.el.getHeight();
17988 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17989 ah -= 5; // knock a few pixes off for look..
17990 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17994 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17995 this.editorcore.onResize(ew,eh);
18000 * Toggles the editor between standard and source edit mode.
18001 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18003 toggleSourceEdit : function(sourceEditMode)
18005 this.editorcore.toggleSourceEdit(sourceEditMode);
18007 if(this.editorcore.sourceEditMode){
18008 Roo.log('editor - showing textarea');
18011 // Roo.log(this.syncValue());
18013 this.inputEl().removeClass(['hide', 'x-hidden']);
18014 this.inputEl().dom.removeAttribute('tabIndex');
18015 this.inputEl().focus();
18017 Roo.log('editor - hiding textarea');
18019 // Roo.log(this.pushValue());
18022 this.inputEl().addClass(['hide', 'x-hidden']);
18023 this.inputEl().dom.setAttribute('tabIndex', -1);
18024 //this.deferFocus();
18027 if(this.resizable){
18028 this.setSize(this.wrap.getSize());
18031 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18034 // private (for BoxComponent)
18035 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18037 // private (for BoxComponent)
18038 getResizeEl : function(){
18042 // private (for BoxComponent)
18043 getPositionEl : function(){
18048 initEvents : function(){
18049 this.originalValue = this.getValue();
18053 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18056 // markInvalid : Roo.emptyFn,
18058 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18061 // clearInvalid : Roo.emptyFn,
18063 setValue : function(v){
18064 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18065 this.editorcore.pushValue();
18070 deferFocus : function(){
18071 this.focus.defer(10, this);
18075 focus : function(){
18076 this.editorcore.focus();
18082 onDestroy : function(){
18088 for (var i =0; i < this.toolbars.length;i++) {
18089 // fixme - ask toolbars for heights?
18090 this.toolbars[i].onDestroy();
18093 this.wrap.dom.innerHTML = '';
18094 this.wrap.remove();
18099 onFirstFocus : function(){
18100 //Roo.log("onFirstFocus");
18101 this.editorcore.onFirstFocus();
18102 for (var i =0; i < this.toolbars.length;i++) {
18103 this.toolbars[i].onFirstFocus();
18109 syncValue : function()
18111 this.editorcore.syncValue();
18114 pushValue : function()
18116 this.editorcore.pushValue();
18120 // hide stuff that is not compatible
18134 * @event specialkey
18138 * @cfg {String} fieldClass @hide
18141 * @cfg {String} focusClass @hide
18144 * @cfg {String} autoCreate @hide
18147 * @cfg {String} inputType @hide
18150 * @cfg {String} invalidClass @hide
18153 * @cfg {String} invalidText @hide
18156 * @cfg {String} msgFx @hide
18159 * @cfg {String} validateOnBlur @hide
18168 Roo.namespace('Roo.bootstrap.htmleditor');
18170 * @class Roo.bootstrap.HtmlEditorToolbar1
18175 new Roo.bootstrap.HtmlEditor({
18178 new Roo.bootstrap.HtmlEditorToolbar1({
18179 disable : { fonts: 1 , format: 1, ..., ... , ...],
18185 * @cfg {Object} disable List of elements to disable..
18186 * @cfg {Array} btns List of additional buttons.
18190 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18193 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18196 Roo.apply(this, config);
18198 // default disabled, based on 'good practice'..
18199 this.disable = this.disable || {};
18200 Roo.applyIf(this.disable, {
18203 specialElements : true
18205 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18207 this.editor = config.editor;
18208 this.editorcore = config.editor.editorcore;
18210 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18212 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18213 // dont call parent... till later.
18215 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18220 editorcore : false,
18225 "h1","h2","h3","h4","h5","h6",
18227 "abbr", "acronym", "address", "cite", "samp", "var",
18231 onRender : function(ct, position)
18233 // Roo.log("Call onRender: " + this.xtype);
18235 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18237 this.el.dom.style.marginBottom = '0';
18239 var editorcore = this.editorcore;
18240 var editor= this.editor;
18243 var btn = function(id,cmd , toggle, handler){
18245 var event = toggle ? 'toggle' : 'click';
18250 xns: Roo.bootstrap,
18253 enableToggle:toggle !== false,
18255 pressed : toggle ? false : null,
18258 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18259 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18268 xns: Roo.bootstrap,
18269 glyphicon : 'font',
18273 xns: Roo.bootstrap,
18277 Roo.each(this.formats, function(f) {
18278 style.menu.items.push({
18280 xns: Roo.bootstrap,
18281 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18286 editorcore.insertTag(this.tagname);
18293 children.push(style);
18296 btn('bold',false,true);
18297 btn('italic',false,true);
18298 btn('align-left', 'justifyleft',true);
18299 btn('align-center', 'justifycenter',true);
18300 btn('align-right' , 'justifyright',true);
18301 btn('link', false, false, function(btn) {
18302 //Roo.log("create link?");
18303 var url = prompt(this.createLinkText, this.defaultLinkValue);
18304 if(url && url != 'http:/'+'/'){
18305 this.editorcore.relayCmd('createlink', url);
18308 btn('list','insertunorderedlist',true);
18309 btn('pencil', false,true, function(btn){
18312 this.toggleSourceEdit(btn.pressed);
18318 xns: Roo.bootstrap,
18323 xns: Roo.bootstrap,
18328 cog.menu.items.push({
18330 xns: Roo.bootstrap,
18331 html : Clean styles,
18336 editorcore.insertTag(this.tagname);
18345 this.xtype = 'NavSimplebar';
18347 for(var i=0;i< children.length;i++) {
18349 this.buttons.add(this.addxtypeChild(children[i]));
18353 editor.on('editorevent', this.updateToolbar, this);
18355 onBtnClick : function(id)
18357 this.editorcore.relayCmd(id);
18358 this.editorcore.focus();
18362 * Protected method that will not generally be called directly. It triggers
18363 * a toolbar update by reading the markup state of the current selection in the editor.
18365 updateToolbar: function(){
18367 if(!this.editorcore.activated){
18368 this.editor.onFirstFocus(); // is this neeed?
18372 var btns = this.buttons;
18373 var doc = this.editorcore.doc;
18374 btns.get('bold').setActive(doc.queryCommandState('bold'));
18375 btns.get('italic').setActive(doc.queryCommandState('italic'));
18376 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18378 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18379 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18380 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18382 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18383 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18386 var ans = this.editorcore.getAllAncestors();
18387 if (this.formatCombo) {
18390 var store = this.formatCombo.store;
18391 this.formatCombo.setValue("");
18392 for (var i =0; i < ans.length;i++) {
18393 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18395 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18403 // hides menus... - so this cant be on a menu...
18404 Roo.bootstrap.MenuMgr.hideAll();
18406 Roo.bootstrap.MenuMgr.hideAll();
18407 //this.editorsyncValue();
18409 onFirstFocus: function() {
18410 this.buttons.each(function(item){
18414 toggleSourceEdit : function(sourceEditMode){
18417 if(sourceEditMode){
18418 Roo.log("disabling buttons");
18419 this.buttons.each( function(item){
18420 if(item.cmd != 'pencil'){
18426 Roo.log("enabling buttons");
18427 if(this.editorcore.initialized){
18428 this.buttons.each( function(item){
18434 Roo.log("calling toggole on editor");
18435 // tell the editor that it's been pressed..
18436 this.editor.toggleSourceEdit(sourceEditMode);
18446 * @class Roo.bootstrap.Table.AbstractSelectionModel
18447 * @extends Roo.util.Observable
18448 * Abstract base class for grid SelectionModels. It provides the interface that should be
18449 * implemented by descendant classes. This class should not be directly instantiated.
18452 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18453 this.locked = false;
18454 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18458 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18459 /** @ignore Called by the grid automatically. Do not call directly. */
18460 init : function(grid){
18466 * Locks the selections.
18469 this.locked = true;
18473 * Unlocks the selections.
18475 unlock : function(){
18476 this.locked = false;
18480 * Returns true if the selections are locked.
18481 * @return {Boolean}
18483 isLocked : function(){
18484 return this.locked;
18488 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18489 * @class Roo.bootstrap.Table.RowSelectionModel
18490 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18491 * It supports multiple selections and keyboard selection/navigation.
18493 * @param {Object} config
18496 Roo.bootstrap.Table.RowSelectionModel = function(config){
18497 Roo.apply(this, config);
18498 this.selections = new Roo.util.MixedCollection(false, function(o){
18503 this.lastActive = false;
18507 * @event selectionchange
18508 * Fires when the selection changes
18509 * @param {SelectionModel} this
18511 "selectionchange" : true,
18513 * @event afterselectionchange
18514 * Fires after the selection changes (eg. by key press or clicking)
18515 * @param {SelectionModel} this
18517 "afterselectionchange" : true,
18519 * @event beforerowselect
18520 * Fires when a row is selected being selected, return false to cancel.
18521 * @param {SelectionModel} this
18522 * @param {Number} rowIndex The selected index
18523 * @param {Boolean} keepExisting False if other selections will be cleared
18525 "beforerowselect" : true,
18528 * Fires when a row is selected.
18529 * @param {SelectionModel} this
18530 * @param {Number} rowIndex The selected index
18531 * @param {Roo.data.Record} r The record
18533 "rowselect" : true,
18535 * @event rowdeselect
18536 * Fires when a row is deselected.
18537 * @param {SelectionModel} this
18538 * @param {Number} rowIndex The selected index
18540 "rowdeselect" : true
18542 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18543 this.locked = false;
18546 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18548 * @cfg {Boolean} singleSelect
18549 * True to allow selection of only one row at a time (defaults to false)
18551 singleSelect : false,
18554 initEvents : function(){
18556 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18557 this.grid.on("mousedown", this.handleMouseDown, this);
18558 }else{ // allow click to work like normal
18559 this.grid.on("rowclick", this.handleDragableRowClick, this);
18562 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18563 "up" : function(e){
18565 this.selectPrevious(e.shiftKey);
18566 }else if(this.last !== false && this.lastActive !== false){
18567 var last = this.last;
18568 this.selectRange(this.last, this.lastActive-1);
18569 this.grid.getView().focusRow(this.lastActive);
18570 if(last !== false){
18574 this.selectFirstRow();
18576 this.fireEvent("afterselectionchange", this);
18578 "down" : function(e){
18580 this.selectNext(e.shiftKey);
18581 }else if(this.last !== false && this.lastActive !== false){
18582 var last = this.last;
18583 this.selectRange(this.last, this.lastActive+1);
18584 this.grid.getView().focusRow(this.lastActive);
18585 if(last !== false){
18589 this.selectFirstRow();
18591 this.fireEvent("afterselectionchange", this);
18596 var view = this.grid.view;
18597 view.on("refresh", this.onRefresh, this);
18598 view.on("rowupdated", this.onRowUpdated, this);
18599 view.on("rowremoved", this.onRemove, this);
18603 onRefresh : function(){
18604 var ds = this.grid.dataSource, i, v = this.grid.view;
18605 var s = this.selections;
18606 s.each(function(r){
18607 if((i = ds.indexOfId(r.id)) != -1){
18616 onRemove : function(v, index, r){
18617 this.selections.remove(r);
18621 onRowUpdated : function(v, index, r){
18622 if(this.isSelected(r)){
18623 v.onRowSelect(index);
18629 * @param {Array} records The records to select
18630 * @param {Boolean} keepExisting (optional) True to keep existing selections
18632 selectRecords : function(records, keepExisting){
18634 this.clearSelections();
18636 var ds = this.grid.dataSource;
18637 for(var i = 0, len = records.length; i < len; i++){
18638 this.selectRow(ds.indexOf(records[i]), true);
18643 * Gets the number of selected rows.
18646 getCount : function(){
18647 return this.selections.length;
18651 * Selects the first row in the grid.
18653 selectFirstRow : function(){
18658 * Select the last row.
18659 * @param {Boolean} keepExisting (optional) True to keep existing selections
18661 selectLastRow : function(keepExisting){
18662 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18666 * Selects the row immediately following the last selected row.
18667 * @param {Boolean} keepExisting (optional) True to keep existing selections
18669 selectNext : function(keepExisting){
18670 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18671 this.selectRow(this.last+1, keepExisting);
18672 this.grid.getView().focusRow(this.last);
18677 * Selects the row that precedes the last selected row.
18678 * @param {Boolean} keepExisting (optional) True to keep existing selections
18680 selectPrevious : function(keepExisting){
18682 this.selectRow(this.last-1, keepExisting);
18683 this.grid.getView().focusRow(this.last);
18688 * Returns the selected records
18689 * @return {Array} Array of selected records
18691 getSelections : function(){
18692 return [].concat(this.selections.items);
18696 * Returns the first selected record.
18699 getSelected : function(){
18700 return this.selections.itemAt(0);
18705 * Clears all selections.
18707 clearSelections : function(fast){
18708 if(this.locked) return;
18710 var ds = this.grid.dataSource;
18711 var s = this.selections;
18712 s.each(function(r){
18713 this.deselectRow(ds.indexOfId(r.id));
18717 this.selections.clear();
18724 * Selects all rows.
18726 selectAll : function(){
18727 if(this.locked) return;
18728 this.selections.clear();
18729 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18730 this.selectRow(i, true);
18735 * Returns True if there is a selection.
18736 * @return {Boolean}
18738 hasSelection : function(){
18739 return this.selections.length > 0;
18743 * Returns True if the specified row is selected.
18744 * @param {Number/Record} record The record or index of the record to check
18745 * @return {Boolean}
18747 isSelected : function(index){
18748 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18749 return (r && this.selections.key(r.id) ? true : false);
18753 * Returns True if the specified record id is selected.
18754 * @param {String} id The id of record to check
18755 * @return {Boolean}
18757 isIdSelected : function(id){
18758 return (this.selections.key(id) ? true : false);
18762 handleMouseDown : function(e, t){
18763 var view = this.grid.getView(), rowIndex;
18764 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18767 if(e.shiftKey && this.last !== false){
18768 var last = this.last;
18769 this.selectRange(last, rowIndex, e.ctrlKey);
18770 this.last = last; // reset the last
18771 view.focusRow(rowIndex);
18773 var isSelected = this.isSelected(rowIndex);
18774 if(e.button !== 0 && isSelected){
18775 view.focusRow(rowIndex);
18776 }else if(e.ctrlKey && isSelected){
18777 this.deselectRow(rowIndex);
18778 }else if(!isSelected){
18779 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18780 view.focusRow(rowIndex);
18783 this.fireEvent("afterselectionchange", this);
18786 handleDragableRowClick : function(grid, rowIndex, e)
18788 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18789 this.selectRow(rowIndex, false);
18790 grid.view.focusRow(rowIndex);
18791 this.fireEvent("afterselectionchange", this);
18796 * Selects multiple rows.
18797 * @param {Array} rows Array of the indexes of the row to select
18798 * @param {Boolean} keepExisting (optional) True to keep existing selections
18800 selectRows : function(rows, keepExisting){
18802 this.clearSelections();
18804 for(var i = 0, len = rows.length; i < len; i++){
18805 this.selectRow(rows[i], true);
18810 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18811 * @param {Number} startRow The index of the first row in the range
18812 * @param {Number} endRow The index of the last row in the range
18813 * @param {Boolean} keepExisting (optional) True to retain existing selections
18815 selectRange : function(startRow, endRow, keepExisting){
18816 if(this.locked) return;
18818 this.clearSelections();
18820 if(startRow <= endRow){
18821 for(var i = startRow; i <= endRow; i++){
18822 this.selectRow(i, true);
18825 for(var i = startRow; i >= endRow; i--){
18826 this.selectRow(i, true);
18832 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18833 * @param {Number} startRow The index of the first row in the range
18834 * @param {Number} endRow The index of the last row in the range
18836 deselectRange : function(startRow, endRow, preventViewNotify){
18837 if(this.locked) return;
18838 for(var i = startRow; i <= endRow; i++){
18839 this.deselectRow(i, preventViewNotify);
18845 * @param {Number} row The index of the row to select
18846 * @param {Boolean} keepExisting (optional) True to keep existing selections
18848 selectRow : function(index, keepExisting, preventViewNotify){
18849 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18850 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18851 if(!keepExisting || this.singleSelect){
18852 this.clearSelections();
18854 var r = this.grid.dataSource.getAt(index);
18855 this.selections.add(r);
18856 this.last = this.lastActive = index;
18857 if(!preventViewNotify){
18858 this.grid.getView().onRowSelect(index);
18860 this.fireEvent("rowselect", this, index, r);
18861 this.fireEvent("selectionchange", this);
18867 * @param {Number} row The index of the row to deselect
18869 deselectRow : function(index, preventViewNotify){
18870 if(this.locked) return;
18871 if(this.last == index){
18874 if(this.lastActive == index){
18875 this.lastActive = false;
18877 var r = this.grid.dataSource.getAt(index);
18878 this.selections.remove(r);
18879 if(!preventViewNotify){
18880 this.grid.getView().onRowDeselect(index);
18882 this.fireEvent("rowdeselect", this, index);
18883 this.fireEvent("selectionchange", this);
18887 restoreLast : function(){
18889 this.last = this._last;
18894 acceptsNav : function(row, col, cm){
18895 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18899 onEditorKey : function(field, e){
18900 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18905 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18907 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18909 }else if(k == e.ENTER && !e.ctrlKey){
18913 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18915 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18917 }else if(k == e.ESC){
18921 g.startEditing(newCell[0], newCell[1]);
18926 * Ext JS Library 1.1.1
18927 * Copyright(c) 2006-2007, Ext JS, LLC.
18929 * Originally Released Under LGPL - original licence link has changed is not relivant.
18932 * <script type="text/javascript">
18936 * @class Roo.bootstrap.PagingToolbar
18938 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18940 * Create a new PagingToolbar
18941 * @param {Object} config The config object
18943 Roo.bootstrap.PagingToolbar = function(config)
18945 // old args format still supported... - xtype is prefered..
18946 // created from xtype...
18947 var ds = config.dataSource;
18948 this.toolbarItems = [];
18949 if (config.items) {
18950 this.toolbarItems = config.items;
18951 // config.items = [];
18954 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18961 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18965 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18967 * @cfg {Roo.data.Store} dataSource
18968 * The underlying data store providing the paged data
18971 * @cfg {String/HTMLElement/Element} container
18972 * container The id or element that will contain the toolbar
18975 * @cfg {Boolean} displayInfo
18976 * True to display the displayMsg (defaults to false)
18979 * @cfg {Number} pageSize
18980 * The number of records to display per page (defaults to 20)
18984 * @cfg {String} displayMsg
18985 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18987 displayMsg : 'Displaying {0} - {1} of {2}',
18989 * @cfg {String} emptyMsg
18990 * The message to display when no records are found (defaults to "No data to display")
18992 emptyMsg : 'No data to display',
18994 * Customizable piece of the default paging text (defaults to "Page")
18997 beforePageText : "Page",
18999 * Customizable piece of the default paging text (defaults to "of %0")
19002 afterPageText : "of {0}",
19004 * Customizable piece of the default paging text (defaults to "First Page")
19007 firstText : "First Page",
19009 * Customizable piece of the default paging text (defaults to "Previous Page")
19012 prevText : "Previous Page",
19014 * Customizable piece of the default paging text (defaults to "Next Page")
19017 nextText : "Next Page",
19019 * Customizable piece of the default paging text (defaults to "Last Page")
19022 lastText : "Last Page",
19024 * Customizable piece of the default paging text (defaults to "Refresh")
19027 refreshText : "Refresh",
19031 onRender : function(ct, position)
19033 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19034 this.navgroup.parentId = this.id;
19035 this.navgroup.onRender(this.el, null);
19036 // add the buttons to the navgroup
19038 if(this.displayInfo){
19039 Roo.log(this.el.select('ul.navbar-nav',true).first());
19040 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19041 this.displayEl = this.el.select('.x-paging-info', true).first();
19042 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19043 // this.displayEl = navel.el.select('span',true).first();
19049 Roo.each(_this.buttons, function(e){
19050 Roo.factory(e).onRender(_this.el, null);
19054 Roo.each(_this.toolbarItems, function(e) {
19055 _this.navgroup.addItem(e);
19058 this.first = this.navgroup.addItem({
19059 tooltip: this.firstText,
19061 icon : 'fa fa-backward',
19063 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19066 this.prev = this.navgroup.addItem({
19067 tooltip: this.prevText,
19069 icon : 'fa fa-step-backward',
19071 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19073 //this.addSeparator();
19076 var field = this.navgroup.addItem( {
19078 cls : 'x-paging-position',
19080 html : this.beforePageText +
19081 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19082 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19085 this.field = field.el.select('input', true).first();
19086 this.field.on("keydown", this.onPagingKeydown, this);
19087 this.field.on("focus", function(){this.dom.select();});
19090 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19091 //this.field.setHeight(18);
19092 //this.addSeparator();
19093 this.next = this.navgroup.addItem({
19094 tooltip: this.nextText,
19096 html : ' <i class="fa fa-step-forward">',
19098 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19100 this.last = this.navgroup.addItem({
19101 tooltip: this.lastText,
19102 icon : 'fa fa-forward',
19105 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19107 //this.addSeparator();
19108 this.loading = this.navgroup.addItem({
19109 tooltip: this.refreshText,
19110 icon: 'fa fa-refresh',
19112 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19118 updateInfo : function(){
19119 if(this.displayEl){
19120 var count = this.ds.getCount();
19121 var msg = count == 0 ?
19125 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19127 this.displayEl.update(msg);
19132 onLoad : function(ds, r, o){
19133 this.cursor = o.params ? o.params.start : 0;
19134 var d = this.getPageData(),
19138 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19139 this.field.dom.value = ap;
19140 this.first.setDisabled(ap == 1);
19141 this.prev.setDisabled(ap == 1);
19142 this.next.setDisabled(ap == ps);
19143 this.last.setDisabled(ap == ps);
19144 this.loading.enable();
19149 getPageData : function(){
19150 var total = this.ds.getTotalCount();
19153 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19154 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19159 onLoadError : function(){
19160 this.loading.enable();
19164 onPagingKeydown : function(e){
19165 var k = e.getKey();
19166 var d = this.getPageData();
19168 var v = this.field.dom.value, pageNum;
19169 if(!v || isNaN(pageNum = parseInt(v, 10))){
19170 this.field.dom.value = d.activePage;
19173 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19174 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19177 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))
19179 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19180 this.field.dom.value = pageNum;
19181 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19184 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19186 var v = this.field.dom.value, pageNum;
19187 var increment = (e.shiftKey) ? 10 : 1;
19188 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19190 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19191 this.field.dom.value = d.activePage;
19194 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19196 this.field.dom.value = parseInt(v, 10) + increment;
19197 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19198 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19205 beforeLoad : function(){
19207 this.loading.disable();
19212 onClick : function(which){
19219 ds.load({params:{start: 0, limit: this.pageSize}});
19222 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19225 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19228 var total = ds.getTotalCount();
19229 var extra = total % this.pageSize;
19230 var lastStart = extra ? (total - extra) : total-this.pageSize;
19231 ds.load({params:{start: lastStart, limit: this.pageSize}});
19234 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19240 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19241 * @param {Roo.data.Store} store The data store to unbind
19243 unbind : function(ds){
19244 ds.un("beforeload", this.beforeLoad, this);
19245 ds.un("load", this.onLoad, this);
19246 ds.un("loadexception", this.onLoadError, this);
19247 ds.un("remove", this.updateInfo, this);
19248 ds.un("add", this.updateInfo, this);
19249 this.ds = undefined;
19253 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19254 * @param {Roo.data.Store} store The data store to bind
19256 bind : function(ds){
19257 ds.on("beforeload", this.beforeLoad, this);
19258 ds.on("load", this.onLoad, this);
19259 ds.on("loadexception", this.onLoadError, this);
19260 ds.on("remove", this.updateInfo, this);
19261 ds.on("add", this.updateInfo, this);
19272 * @class Roo.bootstrap.MessageBar
19273 * @extends Roo.bootstrap.Component
19274 * Bootstrap MessageBar class
19275 * @cfg {String} html contents of the MessageBar
19276 * @cfg {String} weight (info | success | warning | danger) default info
19277 * @cfg {String} beforeClass insert the bar before the given class
19278 * @cfg {Boolean} closable (true | false) default false
19279 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19282 * Create a new Element
19283 * @param {Object} config The config object
19286 Roo.bootstrap.MessageBar = function(config){
19287 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19290 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19296 beforeClass: 'bootstrap-sticky-wrap',
19298 getAutoCreate : function(){
19302 cls: 'alert alert-dismissable alert-' + this.weight,
19307 html: this.html || ''
19313 cfg.cls += ' alert-messages-fixed';
19327 onRender : function(ct, position)
19329 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19332 var cfg = Roo.apply({}, this.getAutoCreate());
19336 cfg.cls += ' ' + this.cls;
19339 cfg.style = this.style;
19341 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19343 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19346 this.el.select('>button.close').on('click', this.hide, this);
19352 if (!this.rendered) {
19358 this.fireEvent('show', this);
19364 if (!this.rendered) {
19370 this.fireEvent('hide', this);
19373 update : function()
19375 // var e = this.el.dom.firstChild;
19377 // if(this.closable){
19378 // e = e.nextSibling;
19381 // e.data = this.html || '';
19383 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19399 * @class Roo.bootstrap.Graph
19400 * @extends Roo.bootstrap.Component
19401 * Bootstrap Graph class
19405 @cfg {String} graphtype bar | vbar | pie
19406 @cfg {number} g_x coodinator | centre x (pie)
19407 @cfg {number} g_y coodinator | centre y (pie)
19408 @cfg {number} g_r radius (pie)
19409 @cfg {number} g_height height of the chart (respected by all elements in the set)
19410 @cfg {number} g_width width of the chart (respected by all elements in the set)
19411 @cfg {Object} title The title of the chart
19414 -opts (object) options for the chart
19416 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19417 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19419 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.
19420 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19422 o stretch (boolean)
19424 -opts (object) options for the pie
19427 o startAngle (number)
19428 o endAngle (number)
19432 * Create a new Input
19433 * @param {Object} config The config object
19436 Roo.bootstrap.Graph = function(config){
19437 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19443 * The img click event for the img.
19444 * @param {Roo.EventObject} e
19450 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19461 //g_colors: this.colors,
19468 getAutoCreate : function(){
19479 onRender : function(ct,position){
19480 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19481 this.raphael = Raphael(this.el.dom);
19483 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19484 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19485 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19486 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19488 r.text(160, 10, "Single Series Chart").attr(txtattr);
19489 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19490 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19491 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19493 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19494 r.barchart(330, 10, 300, 220, data1);
19495 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19496 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19499 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19500 // r.barchart(30, 30, 560, 250, xdata, {
19501 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19502 // axis : "0 0 1 1",
19503 // axisxlabels : xdata
19504 // //yvalues : cols,
19507 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19509 // this.load(null,xdata,{
19510 // axis : "0 0 1 1",
19511 // axisxlabels : xdata
19516 load : function(graphtype,xdata,opts){
19517 this.raphael.clear();
19519 graphtype = this.graphtype;
19524 var r = this.raphael,
19525 fin = function () {
19526 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19528 fout = function () {
19529 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19531 pfin = function() {
19532 this.sector.stop();
19533 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19536 this.label[0].stop();
19537 this.label[0].attr({ r: 7.5 });
19538 this.label[1].attr({ "font-weight": 800 });
19541 pfout = function() {
19542 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19545 this.label[0].animate({ r: 5 }, 500, "bounce");
19546 this.label[1].attr({ "font-weight": 400 });
19552 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19555 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19558 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19559 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19561 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19568 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19573 setTitle: function(o)
19578 initEvents: function() {
19581 this.el.on('click', this.onClick, this);
19585 onClick : function(e)
19587 Roo.log('img onclick');
19588 this.fireEvent('click', this, e);
19600 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19603 * @class Roo.bootstrap.dash.NumberBox
19604 * @extends Roo.bootstrap.Component
19605 * Bootstrap NumberBox class
19606 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19607 * @cfg {String} headline Box headline
19608 * @cfg {String} content Box content
19609 * @cfg {String} icon Box icon
19610 * @cfg {String} footer Footer text
19611 * @cfg {String} fhref Footer href
19614 * Create a new NumberBox
19615 * @param {Object} config The config object
19619 Roo.bootstrap.dash.NumberBox = function(config){
19620 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19624 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19634 getAutoCreate : function(){
19638 cls : 'small-box bg-' + this.bgcolor,
19646 cls : 'roo-headline',
19647 html : this.headline
19651 cls : 'roo-content',
19652 html : this.content
19666 cls : 'ion ' + this.icon
19675 cls : 'small-box-footer',
19676 href : this.fhref || '#',
19680 cfg.cn.push(footer);
19687 onRender : function(ct,position){
19688 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19695 setHeadline: function (value)
19697 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19700 setFooter: function (value, href)
19702 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19705 this.el.select('a.small-box-footer',true).first().attr('href', href);
19710 setContent: function (value)
19712 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19715 initEvents: function()
19729 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19732 * @class Roo.bootstrap.dash.TabBox
19733 * @extends Roo.bootstrap.Component
19734 * Bootstrap TabBox class
19735 * @cfg {String} title Title of the TabBox
19736 * @cfg {String} icon Icon of the TabBox
19737 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19740 * Create a new TabBox
19741 * @param {Object} config The config object
19745 Roo.bootstrap.dash.TabBox = function(config){
19746 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19751 * When a pane is added
19752 * @param {Roo.bootstrap.dash.TabPane} pane
19759 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19765 getChildContainer : function()
19767 return this.el.select('.tab-content', true).first();
19770 getAutoCreate : function(){
19774 cls: 'pull-left header',
19782 cls: 'fa ' + this.icon
19789 cls: 'nav-tabs-custom',
19793 cls: 'nav nav-tabs pull-right',
19800 cls: 'tab-content no-padding',
19808 initEvents : function()
19810 //Roo.log('add add pane handler');
19811 this.on('addpane', this.onAddPane, this);
19814 * Updates the box title
19815 * @param {String} html to set the title to.
19817 setTitle : function(value)
19819 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19821 onAddPane : function(pane)
19823 //Roo.log('addpane');
19825 // tabs are rendere left to right..
19826 if(!this.showtabs){
19830 var ctr = this.el.select('.nav-tabs', true).first();
19833 var existing = ctr.select('.nav-tab',true);
19834 var qty = existing.getCount();;
19837 var tab = ctr.createChild({
19839 cls : 'nav-tab' + (qty ? '' : ' active'),
19847 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19850 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19852 pane.el.addClass('active');
19857 onTabClick : function(ev,un,ob,pane)
19859 //Roo.log('tab - prev default');
19860 ev.preventDefault();
19863 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19864 pane.tab.addClass('active');
19865 //Roo.log(pane.title);
19866 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19867 // technically we should have a deactivate event.. but maybe add later.
19868 // and it should not de-activate the selected tab...
19870 pane.el.addClass('active');
19871 pane.fireEvent('activate');
19886 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19888 * @class Roo.bootstrap.TabPane
19889 * @extends Roo.bootstrap.Component
19890 * Bootstrap TabPane class
19891 * @cfg {Boolean} active (false | true) Default false
19892 * @cfg {String} title title of panel
19896 * Create a new TabPane
19897 * @param {Object} config The config object
19900 Roo.bootstrap.dash.TabPane = function(config){
19901 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19907 * When a pane is activated
19908 * @param {Roo.bootstrap.dash.TabPane} pane
19915 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19920 // the tabBox that this is attached to.
19923 getAutoCreate : function()
19931 cfg.cls += ' active';
19936 initEvents : function()
19938 //Roo.log('trigger add pane handler');
19939 this.parent().fireEvent('addpane', this)
19943 * Updates the tab title
19944 * @param {String} html to set the title to.
19946 setTitle: function(str)
19952 this.tab.select('a', true).first().dom.innerHTML = str;
19969 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19972 * @class Roo.bootstrap.menu.Menu
19973 * @extends Roo.bootstrap.Component
19974 * Bootstrap Menu class - container for Menu
19975 * @cfg {String} html Text of the menu
19976 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19977 * @cfg {String} icon Font awesome icon
19978 * @cfg {String} pos Menu align to (top | bottom) default bottom
19982 * Create a new Menu
19983 * @param {Object} config The config object
19987 Roo.bootstrap.menu.Menu = function(config){
19988 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19992 * @event beforeshow
19993 * Fires before this menu is displayed
19994 * @param {Roo.bootstrap.menu.Menu} this
19998 * @event beforehide
19999 * Fires before this menu is hidden
20000 * @param {Roo.bootstrap.menu.Menu} this
20005 * Fires after this menu is displayed
20006 * @param {Roo.bootstrap.menu.Menu} this
20011 * Fires after this menu is hidden
20012 * @param {Roo.bootstrap.menu.Menu} this
20017 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20018 * @param {Roo.bootstrap.menu.Menu} this
20019 * @param {Roo.EventObject} e
20026 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20030 weight : 'default',
20035 getChildContainer : function() {
20036 if(this.isSubMenu){
20040 return this.el.select('ul.dropdown-menu', true).first();
20043 getAutoCreate : function()
20048 cls : 'roo-menu-text',
20056 cls : 'fa ' + this.icon
20067 cls : 'dropdown-button btn btn-' + this.weight,
20072 cls : 'dropdown-toggle btn btn-' + this.weight,
20082 cls : 'dropdown-menu'
20088 if(this.pos == 'top'){
20089 cfg.cls += ' dropup';
20092 if(this.isSubMenu){
20095 cls : 'dropdown-menu'
20102 onRender : function(ct, position)
20104 this.isSubMenu = ct.hasClass('dropdown-submenu');
20106 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20109 initEvents : function()
20111 if(this.isSubMenu){
20115 this.hidden = true;
20117 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20118 this.triggerEl.on('click', this.onTriggerPress, this);
20120 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20121 this.buttonEl.on('click', this.onClick, this);
20127 if(this.isSubMenu){
20131 return this.el.select('ul.dropdown-menu', true).first();
20134 onClick : function(e)
20136 this.fireEvent("click", this, e);
20139 onTriggerPress : function(e)
20141 if (this.isVisible()) {
20148 isVisible : function(){
20149 return !this.hidden;
20154 this.fireEvent("beforeshow", this);
20156 this.hidden = false;
20157 this.el.addClass('open');
20159 Roo.get(document).on("mouseup", this.onMouseUp, this);
20161 this.fireEvent("show", this);
20168 this.fireEvent("beforehide", this);
20170 this.hidden = true;
20171 this.el.removeClass('open');
20173 Roo.get(document).un("mouseup", this.onMouseUp);
20175 this.fireEvent("hide", this);
20178 onMouseUp : function()
20192 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20195 * @class Roo.bootstrap.menu.Item
20196 * @extends Roo.bootstrap.Component
20197 * Bootstrap MenuItem class
20198 * @cfg {Boolean} submenu (true | false) default false
20199 * @cfg {String} html text of the item
20200 * @cfg {String} href the link
20201 * @cfg {Boolean} disable (true | false) default false
20202 * @cfg {Boolean} preventDefault (true | false) default true
20203 * @cfg {String} icon Font awesome icon
20204 * @cfg {String} pos Submenu align to (left | right) default right
20208 * Create a new Item
20209 * @param {Object} config The config object
20213 Roo.bootstrap.menu.Item = function(config){
20214 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20218 * Fires when the mouse is hovering over this menu
20219 * @param {Roo.bootstrap.menu.Item} this
20220 * @param {Roo.EventObject} e
20225 * Fires when the mouse exits this menu
20226 * @param {Roo.bootstrap.menu.Item} this
20227 * @param {Roo.EventObject} e
20233 * The raw click event for the entire grid.
20234 * @param {Roo.EventObject} e
20240 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20245 preventDefault: true,
20250 getAutoCreate : function()
20255 cls : 'roo-menu-item-text',
20263 cls : 'fa ' + this.icon
20272 href : this.href || '#',
20279 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20283 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20285 if(this.pos == 'left'){
20286 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20293 initEvents : function()
20295 this.el.on('mouseover', this.onMouseOver, this);
20296 this.el.on('mouseout', this.onMouseOut, this);
20298 this.el.select('a', true).first().on('click', this.onClick, this);
20302 onClick : function(e)
20304 if(this.preventDefault){
20305 e.preventDefault();
20308 this.fireEvent("click", this, e);
20311 onMouseOver : function(e)
20313 if(this.submenu && this.pos == 'left'){
20314 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20317 this.fireEvent("mouseover", this, e);
20320 onMouseOut : function(e)
20322 this.fireEvent("mouseout", this, e);
20334 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20337 * @class Roo.bootstrap.menu.Separator
20338 * @extends Roo.bootstrap.Component
20339 * Bootstrap Separator class
20342 * Create a new Separator
20343 * @param {Object} config The config object
20347 Roo.bootstrap.menu.Separator = function(config){
20348 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20351 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20353 getAutoCreate : function(){