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);
11650 this.restrictHeight();
11654 this.tickItems = Roo.apply([], this.item);
11657 this.cancelBtn.show();
11658 this.trigger.hide();
11662 Roo.get(document).on('mousedown', this.collapseIf, this);
11663 Roo.get(document).on('mousewheel', this.collapseIf, this);
11664 if (!this.editable) {
11665 Roo.get(document).on('keydown', this.listKeyPress, this);
11668 this.fireEvent('expand', this);
11672 // Implements the default empty TriggerField.onTriggerClick function
11673 onTriggerClick : function(e)
11675 Roo.log('trigger click');
11677 if(this.disabled || !this.triggerList){
11682 this.loadNext = false;
11684 if(this.isExpanded()){
11686 if (!this.blockFocus) {
11687 this.inputEl().focus();
11691 this.hasFocus = true;
11692 if(this.triggerAction == 'all') {
11693 this.doQuery(this.allQuery, true);
11695 this.doQuery(this.getRawValue());
11697 if (!this.blockFocus) {
11698 this.inputEl().focus();
11703 onTickableTriggerClick : function(e)
11710 this.loadNext = false;
11711 this.hasFocus = true;
11713 if(this.triggerAction == 'all') {
11714 this.doQuery(this.allQuery, true);
11716 this.doQuery(this.getRawValue());
11720 onSearchFieldClick : function(e)
11722 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11727 this.loadNext = false;
11728 this.hasFocus = true;
11730 if(this.triggerAction == 'all') {
11731 this.doQuery(this.allQuery, true);
11733 this.doQuery(this.getRawValue());
11737 listKeyPress : function(e)
11739 //Roo.log('listkeypress');
11740 // scroll to first matching element based on key pres..
11741 if (e.isSpecialKey()) {
11744 var k = String.fromCharCode(e.getKey()).toUpperCase();
11747 var csel = this.view.getSelectedNodes();
11748 var cselitem = false;
11750 var ix = this.view.indexOf(csel[0]);
11751 cselitem = this.store.getAt(ix);
11752 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11758 this.store.each(function(v) {
11760 // start at existing selection.
11761 if (cselitem.id == v.id) {
11767 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11768 match = this.store.indexOf(v);
11774 if (match === false) {
11775 return true; // no more action?
11778 this.view.select(match);
11779 var sn = Roo.get(this.view.getSelectedNodes()[0])
11780 //sn.scrollIntoView(sn.dom.parentNode, false);
11783 onViewScroll : function(e, t){
11785 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){
11789 this.hasQuery = true;
11791 this.loading = this.list.select('.loading', true).first();
11793 if(this.loading === null){
11794 this.list.createChild({
11796 cls: 'loading select2-more-results select2-active',
11797 html: 'Loading more results...'
11800 this.loading = this.list.select('.loading', true).first();
11802 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11804 this.loading.hide();
11807 this.loading.show();
11812 this.loadNext = true;
11814 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11819 addItem : function(o)
11821 var dv = ''; // display value
11823 if (this.displayField) {
11824 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11826 // this is an error condition!!!
11827 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11834 var choice = this.choices.createChild({
11836 cls: 'select2-search-choice',
11845 cls: 'select2-search-choice-close',
11850 }, this.searchField);
11852 var close = choice.select('a.select2-search-choice-close', true).first()
11854 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11862 this.inputEl().dom.value = '';
11866 onRemoveItem : function(e, _self, o)
11868 e.preventDefault();
11869 var index = this.item.indexOf(o.data) * 1;
11872 Roo.log('not this item?!');
11876 this.item.splice(index, 1);
11881 this.fireEvent('remove', this, e);
11885 syncValue : function()
11887 if(!this.item.length){
11894 Roo.each(this.item, function(i){
11895 if(_this.valueField){
11896 value.push(i[_this.valueField]);
11903 this.value = value.join(',');
11905 if(this.hiddenField){
11906 this.hiddenField.dom.value = this.value;
11910 clearItem : function()
11912 if(!this.multiple){
11918 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11925 inputEl: function ()
11928 return this.searchField;
11930 return this.el.select('input.form-control',true).first();
11934 onTickableFooterButtonClick : function(e, btn, el)
11936 e.preventDefault();
11938 if(btn && btn.name == 'cancel'){
11939 this.tickItems = Roo.apply([], this.item);
11948 Roo.each(this.tickItems, function(o){
11959 * @cfg {Boolean} grow
11963 * @cfg {Number} growMin
11967 * @cfg {Number} growMax
11977 * Ext JS Library 1.1.1
11978 * Copyright(c) 2006-2007, Ext JS, LLC.
11980 * Originally Released Under LGPL - original licence link has changed is not relivant.
11983 * <script type="text/javascript">
11988 * @extends Roo.util.Observable
11989 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11990 * This class also supports single and multi selection modes. <br>
11991 * Create a data model bound view:
11993 var store = new Roo.data.Store(...);
11995 var view = new Roo.View({
11997 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11999 singleSelect: true,
12000 selectedClass: "ydataview-selected",
12004 // listen for node click?
12005 view.on("click", function(vw, index, node, e){
12006 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12010 dataModel.load("foobar.xml");
12012 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12014 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12015 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12017 * Note: old style constructor is still suported (container, template, config)
12020 * Create a new View
12021 * @param {Object} config The config object
12024 Roo.View = function(config, depreciated_tpl, depreciated_config){
12026 this.parent = false;
12028 if (typeof(depreciated_tpl) == 'undefined') {
12029 // new way.. - universal constructor.
12030 Roo.apply(this, config);
12031 this.el = Roo.get(this.el);
12034 this.el = Roo.get(config);
12035 this.tpl = depreciated_tpl;
12036 Roo.apply(this, depreciated_config);
12038 this.wrapEl = this.el.wrap().wrap();
12039 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12042 if(typeof(this.tpl) == "string"){
12043 this.tpl = new Roo.Template(this.tpl);
12045 // support xtype ctors..
12046 this.tpl = new Roo.factory(this.tpl, Roo);
12050 this.tpl.compile();
12055 * @event beforeclick
12056 * Fires before a click is processed. Returns false to cancel the default action.
12057 * @param {Roo.View} this
12058 * @param {Number} index The index of the target node
12059 * @param {HTMLElement} node The target node
12060 * @param {Roo.EventObject} e The raw event object
12062 "beforeclick" : true,
12065 * Fires when a template node is clicked.
12066 * @param {Roo.View} this
12067 * @param {Number} index The index of the target node
12068 * @param {HTMLElement} node The target node
12069 * @param {Roo.EventObject} e The raw event object
12074 * Fires when a template node is double clicked.
12075 * @param {Roo.View} this
12076 * @param {Number} index The index of the target node
12077 * @param {HTMLElement} node The target node
12078 * @param {Roo.EventObject} e The raw event object
12082 * @event contextmenu
12083 * Fires when a template node is right clicked.
12084 * @param {Roo.View} this
12085 * @param {Number} index The index of the target node
12086 * @param {HTMLElement} node The target node
12087 * @param {Roo.EventObject} e The raw event object
12089 "contextmenu" : true,
12091 * @event selectionchange
12092 * Fires when the selected nodes change.
12093 * @param {Roo.View} this
12094 * @param {Array} selections Array of the selected nodes
12096 "selectionchange" : true,
12099 * @event beforeselect
12100 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12101 * @param {Roo.View} this
12102 * @param {HTMLElement} node The node to be selected
12103 * @param {Array} selections Array of currently selected nodes
12105 "beforeselect" : true,
12107 * @event preparedata
12108 * Fires on every row to render, to allow you to change the data.
12109 * @param {Roo.View} this
12110 * @param {Object} data to be rendered (change this)
12112 "preparedata" : true
12120 "click": this.onClick,
12121 "dblclick": this.onDblClick,
12122 "contextmenu": this.onContextMenu,
12126 this.selections = [];
12128 this.cmp = new Roo.CompositeElementLite([]);
12130 this.store = Roo.factory(this.store, Roo.data);
12131 this.setStore(this.store, true);
12134 if ( this.footer && this.footer.xtype) {
12136 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12138 this.footer.dataSource = this.store
12139 this.footer.container = fctr;
12140 this.footer = Roo.factory(this.footer, Roo);
12141 fctr.insertFirst(this.el);
12143 // this is a bit insane - as the paging toolbar seems to detach the el..
12144 // dom.parentNode.parentNode.parentNode
12145 // they get detached?
12149 Roo.View.superclass.constructor.call(this);
12154 Roo.extend(Roo.View, Roo.util.Observable, {
12157 * @cfg {Roo.data.Store} store Data store to load data from.
12162 * @cfg {String|Roo.Element} el The container element.
12167 * @cfg {String|Roo.Template} tpl The template used by this View
12171 * @cfg {String} dataName the named area of the template to use as the data area
12172 * Works with domtemplates roo-name="name"
12176 * @cfg {String} selectedClass The css class to add to selected nodes
12178 selectedClass : "x-view-selected",
12180 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12185 * @cfg {String} text to display on mask (default Loading)
12189 * @cfg {Boolean} multiSelect Allow multiple selection
12191 multiSelect : false,
12193 * @cfg {Boolean} singleSelect Allow single selection
12195 singleSelect: false,
12198 * @cfg {Boolean} toggleSelect - selecting
12200 toggleSelect : false,
12203 * @cfg {Boolean} tickable - selecting
12208 * Returns the element this view is bound to.
12209 * @return {Roo.Element}
12211 getEl : function(){
12212 return this.wrapEl;
12218 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12220 refresh : function(){
12221 Roo.log('refresh');
12224 // if we are using something like 'domtemplate', then
12225 // the what gets used is:
12226 // t.applySubtemplate(NAME, data, wrapping data..)
12227 // the outer template then get' applied with
12228 // the store 'extra data'
12229 // and the body get's added to the
12230 // roo-name="data" node?
12231 // <span class='roo-tpl-{name}'></span> ?????
12235 this.clearSelections();
12236 this.el.update("");
12238 var records = this.store.getRange();
12239 if(records.length < 1) {
12241 // is this valid?? = should it render a template??
12243 this.el.update(this.emptyText);
12247 if (this.dataName) {
12248 this.el.update(t.apply(this.store.meta)); //????
12249 el = this.el.child('.roo-tpl-' + this.dataName);
12252 for(var i = 0, len = records.length; i < len; i++){
12253 var data = this.prepareData(records[i].data, i, records[i]);
12254 this.fireEvent("preparedata", this, data, i, records[i]);
12256 var d = Roo.apply({}, data);
12259 Roo.apply(d, {'roo-id' : Roo.id()});
12263 Roo.each(this.parent.item, function(item){
12264 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12267 Roo.apply(d, {'roo-data-checked' : 'checked'});
12271 html[html.length] = Roo.util.Format.trim(
12273 t.applySubtemplate(this.dataName, d, this.store.meta) :
12280 el.update(html.join(""));
12281 this.nodes = el.dom.childNodes;
12282 this.updateIndexes(0);
12287 * Function to override to reformat the data that is sent to
12288 * the template for each node.
12289 * DEPRICATED - use the preparedata event handler.
12290 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12291 * a JSON object for an UpdateManager bound view).
12293 prepareData : function(data, index, record)
12295 this.fireEvent("preparedata", this, data, index, record);
12299 onUpdate : function(ds, record){
12300 Roo.log('on update');
12301 this.clearSelections();
12302 var index = this.store.indexOf(record);
12303 var n = this.nodes[index];
12304 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12305 n.parentNode.removeChild(n);
12306 this.updateIndexes(index, index);
12312 onAdd : function(ds, records, index)
12314 Roo.log(['on Add', ds, records, index] );
12315 this.clearSelections();
12316 if(this.nodes.length == 0){
12320 var n = this.nodes[index];
12321 for(var i = 0, len = records.length; i < len; i++){
12322 var d = this.prepareData(records[i].data, i, records[i]);
12324 this.tpl.insertBefore(n, d);
12327 this.tpl.append(this.el, d);
12330 this.updateIndexes(index);
12333 onRemove : function(ds, record, index){
12334 Roo.log('onRemove');
12335 this.clearSelections();
12336 var el = this.dataName ?
12337 this.el.child('.roo-tpl-' + this.dataName) :
12340 el.dom.removeChild(this.nodes[index]);
12341 this.updateIndexes(index);
12345 * Refresh an individual node.
12346 * @param {Number} index
12348 refreshNode : function(index){
12349 this.onUpdate(this.store, this.store.getAt(index));
12352 updateIndexes : function(startIndex, endIndex){
12353 var ns = this.nodes;
12354 startIndex = startIndex || 0;
12355 endIndex = endIndex || ns.length - 1;
12356 for(var i = startIndex; i <= endIndex; i++){
12357 ns[i].nodeIndex = i;
12362 * Changes the data store this view uses and refresh the view.
12363 * @param {Store} store
12365 setStore : function(store, initial){
12366 if(!initial && this.store){
12367 this.store.un("datachanged", this.refresh);
12368 this.store.un("add", this.onAdd);
12369 this.store.un("remove", this.onRemove);
12370 this.store.un("update", this.onUpdate);
12371 this.store.un("clear", this.refresh);
12372 this.store.un("beforeload", this.onBeforeLoad);
12373 this.store.un("load", this.onLoad);
12374 this.store.un("loadexception", this.onLoad);
12378 store.on("datachanged", this.refresh, this);
12379 store.on("add", this.onAdd, this);
12380 store.on("remove", this.onRemove, this);
12381 store.on("update", this.onUpdate, this);
12382 store.on("clear", this.refresh, this);
12383 store.on("beforeload", this.onBeforeLoad, this);
12384 store.on("load", this.onLoad, this);
12385 store.on("loadexception", this.onLoad, this);
12393 * onbeforeLoad - masks the loading area.
12396 onBeforeLoad : function(store,opts)
12398 Roo.log('onBeforeLoad');
12400 this.el.update("");
12402 this.el.mask(this.mask ? this.mask : "Loading" );
12404 onLoad : function ()
12411 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12412 * @param {HTMLElement} node
12413 * @return {HTMLElement} The template node
12415 findItemFromChild : function(node){
12416 var el = this.dataName ?
12417 this.el.child('.roo-tpl-' + this.dataName,true) :
12420 if(!node || node.parentNode == el){
12423 var p = node.parentNode;
12424 while(p && p != el){
12425 if(p.parentNode == el){
12434 onClick : function(e){
12435 var item = this.findItemFromChild(e.getTarget());
12437 var index = this.indexOf(item);
12438 if(this.onItemClick(item, index, e) !== false){
12439 this.fireEvent("click", this, index, item, e);
12442 this.clearSelections();
12447 onContextMenu : function(e){
12448 var item = this.findItemFromChild(e.getTarget());
12450 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12455 onDblClick : function(e){
12456 var item = this.findItemFromChild(e.getTarget());
12458 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12462 onItemClick : function(item, index, e)
12464 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12467 if (this.toggleSelect) {
12468 var m = this.isSelected(item) ? 'unselect' : 'select';
12471 _t[m](item, true, false);
12474 if(this.multiSelect || this.singleSelect){
12475 if(this.multiSelect && e.shiftKey && this.lastSelection){
12476 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12478 this.select(item, this.multiSelect && e.ctrlKey);
12479 this.lastSelection = item;
12482 if(!this.tickable){
12483 e.preventDefault();
12491 * Get the number of selected nodes.
12494 getSelectionCount : function(){
12495 return this.selections.length;
12499 * Get the currently selected nodes.
12500 * @return {Array} An array of HTMLElements
12502 getSelectedNodes : function(){
12503 return this.selections;
12507 * Get the indexes of the selected nodes.
12510 getSelectedIndexes : function(){
12511 var indexes = [], s = this.selections;
12512 for(var i = 0, len = s.length; i < len; i++){
12513 indexes.push(s[i].nodeIndex);
12519 * Clear all selections
12520 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12522 clearSelections : function(suppressEvent){
12523 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12524 this.cmp.elements = this.selections;
12525 this.cmp.removeClass(this.selectedClass);
12526 this.selections = [];
12527 if(!suppressEvent){
12528 this.fireEvent("selectionchange", this, this.selections);
12534 * Returns true if the passed node is selected
12535 * @param {HTMLElement/Number} node The node or node index
12536 * @return {Boolean}
12538 isSelected : function(node){
12539 var s = this.selections;
12543 node = this.getNode(node);
12544 return s.indexOf(node) !== -1;
12549 * @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
12550 * @param {Boolean} keepExisting (optional) true to keep existing selections
12551 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12553 select : function(nodeInfo, keepExisting, suppressEvent){
12554 if(nodeInfo instanceof Array){
12556 this.clearSelections(true);
12558 for(var i = 0, len = nodeInfo.length; i < len; i++){
12559 this.select(nodeInfo[i], true, true);
12563 var node = this.getNode(nodeInfo);
12564 if(!node || this.isSelected(node)){
12565 return; // already selected.
12568 this.clearSelections(true);
12570 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12571 Roo.fly(node).addClass(this.selectedClass);
12572 this.selections.push(node);
12573 if(!suppressEvent){
12574 this.fireEvent("selectionchange", this, this.selections);
12582 * @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
12583 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12584 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12586 unselect : function(nodeInfo, keepExisting, suppressEvent)
12588 if(nodeInfo instanceof Array){
12589 Roo.each(this.selections, function(s) {
12590 this.unselect(s, nodeInfo);
12594 var node = this.getNode(nodeInfo);
12595 if(!node || !this.isSelected(node)){
12596 Roo.log("not selected");
12597 return; // not selected.
12601 Roo.each(this.selections, function(s) {
12603 Roo.fly(node).removeClass(this.selectedClass);
12610 this.selections= ns;
12611 this.fireEvent("selectionchange", this, this.selections);
12615 * Gets a template node.
12616 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12617 * @return {HTMLElement} The node or null if it wasn't found
12619 getNode : function(nodeInfo){
12620 if(typeof nodeInfo == "string"){
12621 return document.getElementById(nodeInfo);
12622 }else if(typeof nodeInfo == "number"){
12623 return this.nodes[nodeInfo];
12629 * Gets a range template nodes.
12630 * @param {Number} startIndex
12631 * @param {Number} endIndex
12632 * @return {Array} An array of nodes
12634 getNodes : function(start, end){
12635 var ns = this.nodes;
12636 start = start || 0;
12637 end = typeof end == "undefined" ? ns.length - 1 : end;
12640 for(var i = start; i <= end; i++){
12644 for(var i = start; i >= end; i--){
12652 * Finds the index of the passed node
12653 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12654 * @return {Number} The index of the node or -1
12656 indexOf : function(node){
12657 node = this.getNode(node);
12658 if(typeof node.nodeIndex == "number"){
12659 return node.nodeIndex;
12661 var ns = this.nodes;
12662 for(var i = 0, len = ns.length; i < len; i++){
12673 * based on jquery fullcalendar
12677 Roo.bootstrap = Roo.bootstrap || {};
12679 * @class Roo.bootstrap.Calendar
12680 * @extends Roo.bootstrap.Component
12681 * Bootstrap Calendar class
12682 * @cfg {Boolean} loadMask (true|false) default false
12683 * @cfg {Object} header generate the user specific header of the calendar, default false
12686 * Create a new Container
12687 * @param {Object} config The config object
12692 Roo.bootstrap.Calendar = function(config){
12693 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12697 * Fires when a date is selected
12698 * @param {DatePicker} this
12699 * @param {Date} date The selected date
12703 * @event monthchange
12704 * Fires when the displayed month changes
12705 * @param {DatePicker} this
12706 * @param {Date} date The selected month
12708 'monthchange': true,
12710 * @event evententer
12711 * Fires when mouse over an event
12712 * @param {Calendar} this
12713 * @param {event} Event
12715 'evententer': true,
12717 * @event eventleave
12718 * Fires when the mouse leaves an
12719 * @param {Calendar} this
12722 'eventleave': true,
12724 * @event eventclick
12725 * Fires when the mouse click an
12726 * @param {Calendar} this
12735 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12738 * @cfg {Number} startDay
12739 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12747 getAutoCreate : function(){
12750 var fc_button = function(name, corner, style, content ) {
12751 return Roo.apply({},{
12753 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12755 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12758 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12769 style : 'width:100%',
12776 cls : 'fc-header-left',
12778 fc_button('prev', 'left', 'arrow', '‹' ),
12779 fc_button('next', 'right', 'arrow', '›' ),
12780 { tag: 'span', cls: 'fc-header-space' },
12781 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12789 cls : 'fc-header-center',
12793 cls: 'fc-header-title',
12796 html : 'month / year'
12804 cls : 'fc-header-right',
12806 /* fc_button('month', 'left', '', 'month' ),
12807 fc_button('week', '', '', 'week' ),
12808 fc_button('day', 'right', '', 'day' )
12820 header = this.header;
12823 var cal_heads = function() {
12825 // fixme - handle this.
12827 for (var i =0; i < Date.dayNames.length; i++) {
12828 var d = Date.dayNames[i];
12831 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12832 html : d.substring(0,3)
12836 ret[0].cls += ' fc-first';
12837 ret[6].cls += ' fc-last';
12840 var cal_cell = function(n) {
12843 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12848 cls: 'fc-day-number',
12852 cls: 'fc-day-content',
12856 style: 'position: relative;' // height: 17px;
12868 var cal_rows = function() {
12871 for (var r = 0; r < 6; r++) {
12878 for (var i =0; i < Date.dayNames.length; i++) {
12879 var d = Date.dayNames[i];
12880 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12883 row.cn[0].cls+=' fc-first';
12884 row.cn[0].cn[0].style = 'min-height:90px';
12885 row.cn[6].cls+=' fc-last';
12889 ret[0].cls += ' fc-first';
12890 ret[4].cls += ' fc-prev-last';
12891 ret[5].cls += ' fc-last';
12898 cls: 'fc-border-separate',
12899 style : 'width:100%',
12907 cls : 'fc-first fc-last',
12925 cls : 'fc-content',
12926 style : "position: relative;",
12929 cls : 'fc-view fc-view-month fc-grid',
12930 style : 'position: relative',
12931 unselectable : 'on',
12934 cls : 'fc-event-container',
12935 style : 'position:absolute;z-index:8;top:0;left:0;'
12953 initEvents : function()
12956 throw "can not find store for calendar";
12962 style: "text-align:center",
12966 style: "background-color:white;width:50%;margin:250 auto",
12970 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12981 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12983 var size = this.el.select('.fc-content', true).first().getSize();
12984 this.maskEl.setSize(size.width, size.height);
12985 this.maskEl.enableDisplayMode("block");
12986 if(!this.loadMask){
12987 this.maskEl.hide();
12990 this.store = Roo.factory(this.store, Roo.data);
12991 this.store.on('load', this.onLoad, this);
12992 this.store.on('beforeload', this.onBeforeLoad, this);
12996 this.cells = this.el.select('.fc-day',true);
12997 //Roo.log(this.cells);
12998 this.textNodes = this.el.query('.fc-day-number');
12999 this.cells.addClassOnOver('fc-state-hover');
13001 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13002 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13003 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13004 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13006 this.on('monthchange', this.onMonthChange, this);
13008 this.update(new Date().clearTime());
13011 resize : function() {
13012 var sz = this.el.getSize();
13014 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13015 this.el.select('.fc-day-content div',true).setHeight(34);
13020 showPrevMonth : function(e){
13021 this.update(this.activeDate.add("mo", -1));
13023 showToday : function(e){
13024 this.update(new Date().clearTime());
13027 showNextMonth : function(e){
13028 this.update(this.activeDate.add("mo", 1));
13032 showPrevYear : function(){
13033 this.update(this.activeDate.add("y", -1));
13037 showNextYear : function(){
13038 this.update(this.activeDate.add("y", 1));
13043 update : function(date)
13045 var vd = this.activeDate;
13046 this.activeDate = date;
13047 // if(vd && this.el){
13048 // var t = date.getTime();
13049 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13050 // Roo.log('using add remove');
13052 // this.fireEvent('monthchange', this, date);
13054 // this.cells.removeClass("fc-state-highlight");
13055 // this.cells.each(function(c){
13056 // if(c.dateValue == t){
13057 // c.addClass("fc-state-highlight");
13058 // setTimeout(function(){
13059 // try{c.dom.firstChild.focus();}catch(e){}
13069 var days = date.getDaysInMonth();
13071 var firstOfMonth = date.getFirstDateOfMonth();
13072 var startingPos = firstOfMonth.getDay()-this.startDay;
13074 if(startingPos < this.startDay){
13078 var pm = date.add(Date.MONTH, -1);
13079 var prevStart = pm.getDaysInMonth()-startingPos;
13081 this.cells = this.el.select('.fc-day',true);
13082 this.textNodes = this.el.query('.fc-day-number');
13083 this.cells.addClassOnOver('fc-state-hover');
13085 var cells = this.cells.elements;
13086 var textEls = this.textNodes;
13088 Roo.each(cells, function(cell){
13089 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13092 days += startingPos;
13094 // convert everything to numbers so it's fast
13095 var day = 86400000;
13096 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13099 //Roo.log(prevStart);
13101 var today = new Date().clearTime().getTime();
13102 var sel = date.clearTime().getTime();
13103 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13104 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13105 var ddMatch = this.disabledDatesRE;
13106 var ddText = this.disabledDatesText;
13107 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13108 var ddaysText = this.disabledDaysText;
13109 var format = this.format;
13111 var setCellClass = function(cal, cell){
13115 //Roo.log('set Cell Class');
13117 var t = d.getTime();
13121 cell.dateValue = t;
13123 cell.className += " fc-today";
13124 cell.className += " fc-state-highlight";
13125 cell.title = cal.todayText;
13128 // disable highlight in other month..
13129 //cell.className += " fc-state-highlight";
13134 cell.className = " fc-state-disabled";
13135 cell.title = cal.minText;
13139 cell.className = " fc-state-disabled";
13140 cell.title = cal.maxText;
13144 if(ddays.indexOf(d.getDay()) != -1){
13145 cell.title = ddaysText;
13146 cell.className = " fc-state-disabled";
13149 if(ddMatch && format){
13150 var fvalue = d.dateFormat(format);
13151 if(ddMatch.test(fvalue)){
13152 cell.title = ddText.replace("%0", fvalue);
13153 cell.className = " fc-state-disabled";
13157 if (!cell.initialClassName) {
13158 cell.initialClassName = cell.dom.className;
13161 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13166 for(; i < startingPos; i++) {
13167 textEls[i].innerHTML = (++prevStart);
13168 d.setDate(d.getDate()+1);
13170 cells[i].className = "fc-past fc-other-month";
13171 setCellClass(this, cells[i]);
13176 for(; i < days; i++){
13177 intDay = i - startingPos + 1;
13178 textEls[i].innerHTML = (intDay);
13179 d.setDate(d.getDate()+1);
13181 cells[i].className = ''; // "x-date-active";
13182 setCellClass(this, cells[i]);
13186 for(; i < 42; i++) {
13187 textEls[i].innerHTML = (++extraDays);
13188 d.setDate(d.getDate()+1);
13190 cells[i].className = "fc-future fc-other-month";
13191 setCellClass(this, cells[i]);
13194 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13196 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13198 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13199 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13201 if(totalRows != 6){
13202 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13203 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13206 this.fireEvent('monthchange', this, date);
13210 if(!this.internalRender){
13211 var main = this.el.dom.firstChild;
13212 var w = main.offsetWidth;
13213 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13214 Roo.fly(main).setWidth(w);
13215 this.internalRender = true;
13216 // opera does not respect the auto grow header center column
13217 // then, after it gets a width opera refuses to recalculate
13218 // without a second pass
13219 if(Roo.isOpera && !this.secondPass){
13220 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13221 this.secondPass = true;
13222 this.update.defer(10, this, [date]);
13229 findCell : function(dt) {
13230 dt = dt.clearTime().getTime();
13232 this.cells.each(function(c){
13233 //Roo.log("check " +c.dateValue + '?=' + dt);
13234 if(c.dateValue == dt){
13244 findCells : function(ev) {
13245 var s = ev.start.clone().clearTime().getTime();
13247 var e= ev.end.clone().clearTime().getTime();
13250 this.cells.each(function(c){
13251 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13253 if(c.dateValue > e){
13256 if(c.dateValue < s){
13265 // findBestRow: function(cells)
13269 // for (var i =0 ; i < cells.length;i++) {
13270 // ret = Math.max(cells[i].rows || 0,ret);
13277 addItem : function(ev)
13279 // look for vertical location slot in
13280 var cells = this.findCells(ev);
13282 // ev.row = this.findBestRow(cells);
13284 // work out the location.
13288 for(var i =0; i < cells.length; i++) {
13290 cells[i].row = cells[0].row;
13293 cells[i].row = cells[i].row + 1;
13303 if (crow.start.getY() == cells[i].getY()) {
13305 crow.end = cells[i];
13322 cells[0].events.push(ev);
13324 this.calevents.push(ev);
13327 clearEvents: function() {
13329 if(!this.calevents){
13333 Roo.each(this.cells.elements, function(c){
13339 Roo.each(this.calevents, function(e) {
13340 Roo.each(e.els, function(el) {
13341 el.un('mouseenter' ,this.onEventEnter, this);
13342 el.un('mouseleave' ,this.onEventLeave, this);
13347 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13353 renderEvents: function()
13357 this.cells.each(function(c) {
13366 if(c.row != c.events.length){
13367 r = 4 - (4 - (c.row - c.events.length));
13370 c.events = ev.slice(0, r);
13371 c.more = ev.slice(r);
13373 if(c.more.length && c.more.length == 1){
13374 c.events.push(c.more.pop());
13377 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13381 this.cells.each(function(c) {
13383 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13386 for (var e = 0; e < c.events.length; e++){
13387 var ev = c.events[e];
13388 var rows = ev.rows;
13390 for(var i = 0; i < rows.length; i++) {
13392 // how many rows should it span..
13395 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13396 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13398 unselectable : "on",
13401 cls: 'fc-event-inner',
13405 // cls: 'fc-event-time',
13406 // html : cells.length > 1 ? '' : ev.time
13410 cls: 'fc-event-title',
13411 html : String.format('{0}', ev.title)
13418 cls: 'ui-resizable-handle ui-resizable-e',
13419 html : '  '
13426 cfg.cls += ' fc-event-start';
13428 if ((i+1) == rows.length) {
13429 cfg.cls += ' fc-event-end';
13432 var ctr = _this.el.select('.fc-event-container',true).first();
13433 var cg = ctr.createChild(cfg);
13435 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13436 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13438 var r = (c.more.length) ? 1 : 0;
13439 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13440 cg.setWidth(ebox.right - sbox.x -2);
13442 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13443 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13444 cg.on('click', _this.onEventClick, _this, ev);
13455 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13456 style : 'position: absolute',
13457 unselectable : "on",
13460 cls: 'fc-event-inner',
13464 cls: 'fc-event-title',
13472 cls: 'ui-resizable-handle ui-resizable-e',
13473 html : '  '
13479 var ctr = _this.el.select('.fc-event-container',true).first();
13480 var cg = ctr.createChild(cfg);
13482 var sbox = c.select('.fc-day-content',true).first().getBox();
13483 var ebox = c.select('.fc-day-content',true).first().getBox();
13485 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13486 cg.setWidth(ebox.right - sbox.x -2);
13488 cg.on('click', _this.onMoreEventClick, _this, c.more);
13498 onEventEnter: function (e, el,event,d) {
13499 this.fireEvent('evententer', this, el, event);
13502 onEventLeave: function (e, el,event,d) {
13503 this.fireEvent('eventleave', this, el, event);
13506 onEventClick: function (e, el,event,d) {
13507 this.fireEvent('eventclick', this, el, event);
13510 onMonthChange: function () {
13514 onMoreEventClick: function(e, el, more)
13518 this.calpopover.placement = 'right';
13519 this.calpopover.setTitle('More');
13521 this.calpopover.setContent('');
13523 var ctr = this.calpopover.el.select('.popover-content', true).first();
13525 Roo.each(more, function(m){
13527 cls : 'fc-event-hori fc-event-draggable',
13530 var cg = ctr.createChild(cfg);
13532 cg.on('click', _this.onEventClick, _this, m);
13535 this.calpopover.show(el);
13540 onLoad: function ()
13542 this.calevents = [];
13545 if(this.store.getCount() > 0){
13546 this.store.data.each(function(d){
13549 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13550 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13551 time : d.data.start_time,
13552 title : d.data.title,
13553 description : d.data.description,
13554 venue : d.data.venue
13559 this.renderEvents();
13561 if(this.calevents.length && this.loadMask){
13562 this.maskEl.hide();
13566 onBeforeLoad: function()
13568 this.clearEvents();
13570 this.maskEl.show();
13584 * @class Roo.bootstrap.Popover
13585 * @extends Roo.bootstrap.Component
13586 * Bootstrap Popover class
13587 * @cfg {String} html contents of the popover (or false to use children..)
13588 * @cfg {String} title of popover (or false to hide)
13589 * @cfg {String} placement how it is placed
13590 * @cfg {String} trigger click || hover (or false to trigger manually)
13591 * @cfg {String} over what (parent or false to trigger manually.)
13594 * Create a new Popover
13595 * @param {Object} config The config object
13598 Roo.bootstrap.Popover = function(config){
13599 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13602 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13604 title: 'Fill in a title',
13607 placement : 'right',
13608 trigger : 'hover', // hover
13612 can_build_overlaid : false,
13614 getChildContainer : function()
13616 return this.el.select('.popover-content',true).first();
13619 getAutoCreate : function(){
13620 Roo.log('make popover?');
13622 cls : 'popover roo-dynamic',
13623 style: 'display:block',
13629 cls : 'popover-inner',
13633 cls: 'popover-title',
13637 cls : 'popover-content',
13648 setTitle: function(str)
13650 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13652 setContent: function(str)
13654 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13656 // as it get's added to the bottom of the page.
13657 onRender : function(ct, position)
13659 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13661 var cfg = Roo.apply({}, this.getAutoCreate());
13665 cfg.cls += ' ' + this.cls;
13668 cfg.style = this.style;
13670 Roo.log("adding to ")
13671 this.el = Roo.get(document.body).createChild(cfg, position);
13677 initEvents : function()
13679 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13680 this.el.enableDisplayMode('block');
13682 if (this.over === false) {
13685 if (this.triggers === false) {
13688 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13689 var triggers = this.trigger ? this.trigger.split(' ') : [];
13690 Roo.each(triggers, function(trigger) {
13692 if (trigger == 'click') {
13693 on_el.on('click', this.toggle, this);
13694 } else if (trigger != 'manual') {
13695 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13696 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13698 on_el.on(eventIn ,this.enter, this);
13699 on_el.on(eventOut, this.leave, this);
13710 toggle : function () {
13711 this.hoverState == 'in' ? this.leave() : this.enter();
13714 enter : function () {
13717 clearTimeout(this.timeout);
13719 this.hoverState = 'in'
13721 if (!this.delay || !this.delay.show) {
13726 this.timeout = setTimeout(function () {
13727 if (_t.hoverState == 'in') {
13730 }, this.delay.show)
13732 leave : function() {
13733 clearTimeout(this.timeout);
13735 this.hoverState = 'out'
13737 if (!this.delay || !this.delay.hide) {
13742 this.timeout = setTimeout(function () {
13743 if (_t.hoverState == 'out') {
13746 }, this.delay.hide)
13749 show : function (on_el)
13752 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13755 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13756 if (this.html !== false) {
13757 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13759 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13760 if (!this.title.length) {
13761 this.el.select('.popover-title',true).hide();
13764 var placement = typeof this.placement == 'function' ?
13765 this.placement.call(this, this.el, on_el) :
13768 var autoToken = /\s?auto?\s?/i;
13769 var autoPlace = autoToken.test(placement);
13771 placement = placement.replace(autoToken, '') || 'top';
13775 //this.el.setXY([0,0]);
13777 this.el.dom.style.display='block';
13778 this.el.addClass(placement);
13780 //this.el.appendTo(on_el);
13782 var p = this.getPosition();
13783 var box = this.el.getBox();
13788 var align = Roo.bootstrap.Popover.alignment[placement]
13789 this.el.alignTo(on_el, align[0],align[1]);
13790 //var arrow = this.el.select('.arrow',true).first();
13791 //arrow.set(align[2],
13793 this.el.addClass('in');
13794 this.hoverState = null;
13796 if (this.el.hasClass('fade')) {
13803 this.el.setXY([0,0]);
13804 this.el.removeClass('in');
13811 Roo.bootstrap.Popover.alignment = {
13812 'left' : ['r-l', [-10,0], 'right'],
13813 'right' : ['l-r', [10,0], 'left'],
13814 'bottom' : ['t-b', [0,10], 'top'],
13815 'top' : [ 'b-t', [0,-10], 'bottom']
13826 * @class Roo.bootstrap.Progress
13827 * @extends Roo.bootstrap.Component
13828 * Bootstrap Progress class
13829 * @cfg {Boolean} striped striped of the progress bar
13830 * @cfg {Boolean} active animated of the progress bar
13834 * Create a new Progress
13835 * @param {Object} config The config object
13838 Roo.bootstrap.Progress = function(config){
13839 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13842 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13847 getAutoCreate : function(){
13855 cfg.cls += ' progress-striped';
13859 cfg.cls += ' active';
13878 * @class Roo.bootstrap.ProgressBar
13879 * @extends Roo.bootstrap.Component
13880 * Bootstrap ProgressBar class
13881 * @cfg {Number} aria_valuenow aria-value now
13882 * @cfg {Number} aria_valuemin aria-value min
13883 * @cfg {Number} aria_valuemax aria-value max
13884 * @cfg {String} label label for the progress bar
13885 * @cfg {String} panel (success | info | warning | danger )
13886 * @cfg {String} role role of the progress bar
13887 * @cfg {String} sr_only text
13891 * Create a new ProgressBar
13892 * @param {Object} config The config object
13895 Roo.bootstrap.ProgressBar = function(config){
13896 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13899 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13903 aria_valuemax : 100,
13909 getAutoCreate : function()
13914 cls: 'progress-bar',
13915 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13927 cfg.role = this.role;
13930 if(this.aria_valuenow){
13931 cfg['aria-valuenow'] = this.aria_valuenow;
13934 if(this.aria_valuemin){
13935 cfg['aria-valuemin'] = this.aria_valuemin;
13938 if(this.aria_valuemax){
13939 cfg['aria-valuemax'] = this.aria_valuemax;
13942 if(this.label && !this.sr_only){
13943 cfg.html = this.label;
13947 cfg.cls += ' progress-bar-' + this.panel;
13953 update : function(aria_valuenow)
13955 this.aria_valuenow = aria_valuenow;
13957 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13972 * @class Roo.bootstrap.TabGroup
13973 * @extends Roo.bootstrap.Column
13974 * Bootstrap Column class
13975 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13976 * @cfg {Boolean} carousel true to make the group behave like a carousel
13979 * Create a new TabGroup
13980 * @param {Object} config The config object
13983 Roo.bootstrap.TabGroup = function(config){
13984 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13986 this.navId = Roo.id();
13989 Roo.bootstrap.TabGroup.register(this);
13993 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13996 transition : false,
13998 getAutoCreate : function()
14000 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14002 cfg.cls += ' tab-content';
14004 if (this.carousel) {
14005 cfg.cls += ' carousel slide';
14007 cls : 'carousel-inner'
14014 getChildContainer : function()
14016 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14020 * register a Navigation item
14021 * @param {Roo.bootstrap.NavItem} the navitem to add
14023 register : function(item)
14025 this.tabs.push( item);
14026 item.navId = this.navId; // not really needed..
14030 getActivePanel : function()
14033 Roo.each(this.tabs, function(t) {
14043 getPanelByName : function(n)
14046 Roo.each(this.tabs, function(t) {
14047 if (t.tabId == n) {
14055 indexOfPanel : function(p)
14058 Roo.each(this.tabs, function(t,i) {
14059 if (t.tabId == p.tabId) {
14068 * show a specific panel
14069 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14070 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14072 showPanel : function (pan)
14075 if (typeof(pan) == 'number') {
14076 pan = this.tabs[pan];
14078 if (typeof(pan) == 'string') {
14079 pan = this.getPanelByName(pan);
14081 if (pan.tabId == this.getActivePanel().tabId) {
14084 var cur = this.getActivePanel();
14086 if (false === cur.fireEvent('beforedeactivate')) {
14090 if (this.carousel) {
14091 this.transition = true;
14092 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14093 var lr = dir == 'next' ? 'left' : 'right';
14094 pan.el.addClass(dir); // or prev
14095 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14096 cur.el.addClass(lr); // or right
14097 pan.el.addClass(lr);
14100 cur.el.on('transitionend', function() {
14101 Roo.log("trans end?");
14103 pan.el.removeClass([lr,dir]);
14104 pan.setActive(true);
14106 cur.el.removeClass([lr]);
14107 cur.setActive(false);
14109 _this.transition = false;
14111 }, this, { single: true } );
14115 cur.setActive(false);
14116 pan.setActive(true);
14120 showPanelNext : function()
14122 var i = this.indexOfPanel(this.getActivePanel());
14123 if (i > this.tabs.length) {
14126 this.showPanel(this.tabs[i+1]);
14128 showPanelPrev : function()
14130 var i = this.indexOfPanel(this.getActivePanel());
14134 this.showPanel(this.tabs[i-1]);
14145 Roo.apply(Roo.bootstrap.TabGroup, {
14149 * register a Navigation Group
14150 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14152 register : function(navgrp)
14154 this.groups[navgrp.navId] = navgrp;
14158 * fetch a Navigation Group based on the navigation ID
14159 * if one does not exist , it will get created.
14160 * @param {string} the navgroup to add
14161 * @returns {Roo.bootstrap.NavGroup} the navgroup
14163 get: function(navId) {
14164 if (typeof(this.groups[navId]) == 'undefined') {
14165 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14167 return this.groups[navId] ;
14182 * @class Roo.bootstrap.TabPanel
14183 * @extends Roo.bootstrap.Component
14184 * Bootstrap TabPanel class
14185 * @cfg {Boolean} active panel active
14186 * @cfg {String} html panel content
14187 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14188 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14192 * Create a new TabPanel
14193 * @param {Object} config The config object
14196 Roo.bootstrap.TabPanel = function(config){
14197 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14201 * Fires when the active status changes
14202 * @param {Roo.bootstrap.TabPanel} this
14203 * @param {Boolean} state the new state
14208 * @event beforedeactivate
14209 * Fires before a tab is de-activated - can be used to do validation on a form.
14210 * @param {Roo.bootstrap.TabPanel} this
14211 * @return {Boolean} false if there is an error
14214 'beforedeactivate': true
14217 this.tabId = this.tabId || Roo.id();
14221 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14228 getAutoCreate : function(){
14231 // item is needed for carousel - not sure if it has any effect otherwise
14232 cls: 'tab-pane item',
14233 html: this.html || ''
14237 cfg.cls += ' active';
14241 cfg.tabId = this.tabId;
14248 initEvents: function()
14250 Roo.log('-------- init events on tab panel ---------');
14252 var p = this.parent();
14253 this.navId = this.navId || p.navId;
14255 if (typeof(this.navId) != 'undefined') {
14256 // not really needed.. but just in case.. parent should be a NavGroup.
14257 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14258 Roo.log(['register', tg, this]);
14264 onRender : function(ct, position)
14266 // Roo.log("Call onRender: " + this.xtype);
14268 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14276 setActive: function(state)
14278 Roo.log("panel - set active " + this.tabId + "=" + state);
14280 this.active = state;
14282 this.el.removeClass('active');
14284 } else if (!this.el.hasClass('active')) {
14285 this.el.addClass('active');
14287 this.fireEvent('changed', this, state);
14304 * @class Roo.bootstrap.DateField
14305 * @extends Roo.bootstrap.Input
14306 * Bootstrap DateField class
14307 * @cfg {Number} weekStart default 0
14308 * @cfg {Number} weekStart default 0
14309 * @cfg {Number} viewMode default empty, (months|years)
14310 * @cfg {Number} minViewMode default empty, (months|years)
14311 * @cfg {Number} startDate default -Infinity
14312 * @cfg {Number} endDate default Infinity
14313 * @cfg {Boolean} todayHighlight default false
14314 * @cfg {Boolean} todayBtn default false
14315 * @cfg {Boolean} calendarWeeks default false
14316 * @cfg {Object} daysOfWeekDisabled default empty
14318 * @cfg {Boolean} keyboardNavigation default true
14319 * @cfg {String} language default en
14322 * Create a new DateField
14323 * @param {Object} config The config object
14326 Roo.bootstrap.DateField = function(config){
14327 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14331 * Fires when this field show.
14332 * @param {Roo.bootstrap.DateField} this
14333 * @param {Mixed} date The date value
14338 * Fires when this field hide.
14339 * @param {Roo.bootstrap.DateField} this
14340 * @param {Mixed} date The date value
14345 * Fires when select a date.
14346 * @param {Roo.bootstrap.DateField} this
14347 * @param {Mixed} date The date value
14353 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14356 * @cfg {String} format
14357 * The default date format string which can be overriden for localization support. The format must be
14358 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14362 * @cfg {String} altFormats
14363 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14364 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14366 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14374 todayHighlight : false,
14380 keyboardNavigation: true,
14382 calendarWeeks: false,
14384 startDate: -Infinity,
14388 daysOfWeekDisabled: [],
14392 UTCDate: function()
14394 return new Date(Date.UTC.apply(Date, arguments));
14397 UTCToday: function()
14399 var today = new Date();
14400 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14403 getDate: function() {
14404 var d = this.getUTCDate();
14405 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14408 getUTCDate: function() {
14412 setDate: function(d) {
14413 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14416 setUTCDate: function(d) {
14418 this.setValue(this.formatDate(this.date));
14421 onRender: function(ct, position)
14424 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14426 this.language = this.language || 'en';
14427 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14428 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14430 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14431 this.format = this.format || 'm/d/y';
14432 this.isInline = false;
14433 this.isInput = true;
14434 this.component = this.el.select('.add-on', true).first() || false;
14435 this.component = (this.component && this.component.length === 0) ? false : this.component;
14436 this.hasInput = this.component && this.inputEL().length;
14438 if (typeof(this.minViewMode === 'string')) {
14439 switch (this.minViewMode) {
14441 this.minViewMode = 1;
14444 this.minViewMode = 2;
14447 this.minViewMode = 0;
14452 if (typeof(this.viewMode === 'string')) {
14453 switch (this.viewMode) {
14466 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14468 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14470 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14472 this.picker().on('mousedown', this.onMousedown, this);
14473 this.picker().on('click', this.onClick, this);
14475 this.picker().addClass('datepicker-dropdown');
14477 this.startViewMode = this.viewMode;
14480 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14481 if(!this.calendarWeeks){
14486 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14487 v.attr('colspan', function(i, val){
14488 return parseInt(val) + 1;
14493 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14495 this.setStartDate(this.startDate);
14496 this.setEndDate(this.endDate);
14498 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14505 if(this.isInline) {
14510 picker : function()
14512 return this.pickerEl;
14513 // return this.el.select('.datepicker', true).first();
14516 fillDow: function()
14518 var dowCnt = this.weekStart;
14527 if(this.calendarWeeks){
14535 while (dowCnt < this.weekStart + 7) {
14539 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14543 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14546 fillMonths: function()
14549 var months = this.picker().select('>.datepicker-months td', true).first();
14551 months.dom.innerHTML = '';
14557 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14560 months.createChild(month);
14567 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;
14569 if (this.date < this.startDate) {
14570 this.viewDate = new Date(this.startDate);
14571 } else if (this.date > this.endDate) {
14572 this.viewDate = new Date(this.endDate);
14574 this.viewDate = new Date(this.date);
14582 var d = new Date(this.viewDate),
14583 year = d.getUTCFullYear(),
14584 month = d.getUTCMonth(),
14585 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14586 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14587 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14588 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14589 currentDate = this.date && this.date.valueOf(),
14590 today = this.UTCToday();
14592 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14594 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14596 // this.picker.select('>tfoot th.today').
14597 // .text(dates[this.language].today)
14598 // .toggle(this.todayBtn !== false);
14600 this.updateNavArrows();
14603 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14605 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14607 prevMonth.setUTCDate(day);
14609 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14611 var nextMonth = new Date(prevMonth);
14613 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14615 nextMonth = nextMonth.valueOf();
14617 var fillMonths = false;
14619 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14621 while(prevMonth.valueOf() < nextMonth) {
14624 if (prevMonth.getUTCDay() === this.weekStart) {
14626 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14634 if(this.calendarWeeks){
14635 // ISO 8601: First week contains first thursday.
14636 // ISO also states week starts on Monday, but we can be more abstract here.
14638 // Start of current week: based on weekstart/current date
14639 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14640 // Thursday of this week
14641 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14642 // First Thursday of year, year from thursday
14643 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14644 // Calendar week: ms between thursdays, div ms per day, div 7 days
14645 calWeek = (th - yth) / 864e5 / 7 + 1;
14647 fillMonths.cn.push({
14655 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14657 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14660 if (this.todayHighlight &&
14661 prevMonth.getUTCFullYear() == today.getFullYear() &&
14662 prevMonth.getUTCMonth() == today.getMonth() &&
14663 prevMonth.getUTCDate() == today.getDate()) {
14664 clsName += ' today';
14667 if (currentDate && prevMonth.valueOf() === currentDate) {
14668 clsName += ' active';
14671 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14672 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14673 clsName += ' disabled';
14676 fillMonths.cn.push({
14678 cls: 'day ' + clsName,
14679 html: prevMonth.getDate()
14682 prevMonth.setDate(prevMonth.getDate()+1);
14685 var currentYear = this.date && this.date.getUTCFullYear();
14686 var currentMonth = this.date && this.date.getUTCMonth();
14688 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14690 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14691 v.removeClass('active');
14693 if(currentYear === year && k === currentMonth){
14694 v.addClass('active');
14697 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14698 v.addClass('disabled');
14704 year = parseInt(year/10, 10) * 10;
14706 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14708 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14711 for (var i = -1; i < 11; i++) {
14712 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14714 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14722 showMode: function(dir)
14725 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14727 Roo.each(this.picker().select('>div',true).elements, function(v){
14728 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14731 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14736 if(this.isInline) return;
14738 this.picker().removeClass(['bottom', 'top']);
14740 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14742 * place to the top of element!
14746 this.picker().addClass('top');
14747 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14752 this.picker().addClass('bottom');
14754 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14757 parseDate : function(value)
14759 if(!value || value instanceof Date){
14762 var v = Date.parseDate(value, this.format);
14763 if (!v && this.useIso) {
14764 v = Date.parseDate(value, 'Y-m-d');
14766 if(!v && this.altFormats){
14767 if(!this.altFormatsArray){
14768 this.altFormatsArray = this.altFormats.split("|");
14770 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14771 v = Date.parseDate(value, this.altFormatsArray[i]);
14777 formatDate : function(date, fmt)
14779 return (!date || !(date instanceof Date)) ?
14780 date : date.dateFormat(fmt || this.format);
14783 onFocus : function()
14785 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14789 onBlur : function()
14791 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14793 var d = this.inputEl().getValue();
14802 this.picker().show();
14806 this.fireEvent('show', this, this.date);
14811 if(this.isInline) return;
14812 this.picker().hide();
14813 this.viewMode = this.startViewMode;
14816 this.fireEvent('hide', this, this.date);
14820 onMousedown: function(e)
14822 e.stopPropagation();
14823 e.preventDefault();
14828 Roo.bootstrap.DateField.superclass.keyup.call(this);
14832 setValue: function(v)
14834 var d = new Date(v).clearTime();
14836 if(isNaN(d.getTime())){
14837 this.date = this.viewDate = '';
14838 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14842 v = this.formatDate(d);
14844 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14846 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14850 this.fireEvent('select', this, this.date);
14854 getValue: function()
14856 return this.formatDate(this.date);
14859 fireKey: function(e)
14861 if (!this.picker().isVisible()){
14862 if (e.keyCode == 27) // allow escape to hide and re-show picker
14867 var dateChanged = false,
14869 newDate, newViewDate;
14874 e.preventDefault();
14878 if (!this.keyboardNavigation) break;
14879 dir = e.keyCode == 37 ? -1 : 1;
14882 newDate = this.moveYear(this.date, dir);
14883 newViewDate = this.moveYear(this.viewDate, dir);
14884 } else if (e.shiftKey){
14885 newDate = this.moveMonth(this.date, dir);
14886 newViewDate = this.moveMonth(this.viewDate, dir);
14888 newDate = new Date(this.date);
14889 newDate.setUTCDate(this.date.getUTCDate() + dir);
14890 newViewDate = new Date(this.viewDate);
14891 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14893 if (this.dateWithinRange(newDate)){
14894 this.date = newDate;
14895 this.viewDate = newViewDate;
14896 this.setValue(this.formatDate(this.date));
14898 e.preventDefault();
14899 dateChanged = true;
14904 if (!this.keyboardNavigation) break;
14905 dir = e.keyCode == 38 ? -1 : 1;
14907 newDate = this.moveYear(this.date, dir);
14908 newViewDate = this.moveYear(this.viewDate, dir);
14909 } else if (e.shiftKey){
14910 newDate = this.moveMonth(this.date, dir);
14911 newViewDate = this.moveMonth(this.viewDate, dir);
14913 newDate = new Date(this.date);
14914 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14915 newViewDate = new Date(this.viewDate);
14916 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14918 if (this.dateWithinRange(newDate)){
14919 this.date = newDate;
14920 this.viewDate = newViewDate;
14921 this.setValue(this.formatDate(this.date));
14923 e.preventDefault();
14924 dateChanged = true;
14928 this.setValue(this.formatDate(this.date));
14930 e.preventDefault();
14933 this.setValue(this.formatDate(this.date));
14947 onClick: function(e)
14949 e.stopPropagation();
14950 e.preventDefault();
14952 var target = e.getTarget();
14954 if(target.nodeName.toLowerCase() === 'i'){
14955 target = Roo.get(target).dom.parentNode;
14958 var nodeName = target.nodeName;
14959 var className = target.className;
14960 var html = target.innerHTML;
14962 switch(nodeName.toLowerCase()) {
14964 switch(className) {
14970 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14971 switch(this.viewMode){
14973 this.viewDate = this.moveMonth(this.viewDate, dir);
14977 this.viewDate = this.moveYear(this.viewDate, dir);
14983 var date = new Date();
14984 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14986 this.setValue(this.formatDate(this.date));
14993 if (className.indexOf('disabled') === -1) {
14994 this.viewDate.setUTCDate(1);
14995 if (className.indexOf('month') !== -1) {
14996 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14998 var year = parseInt(html, 10) || 0;
14999 this.viewDate.setUTCFullYear(year);
15008 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
15009 var day = parseInt(html, 10) || 1;
15010 var year = this.viewDate.getUTCFullYear(),
15011 month = this.viewDate.getUTCMonth();
15013 if (className.indexOf('old') !== -1) {
15020 } else if (className.indexOf('new') !== -1) {
15028 this.date = this.UTCDate(year, month, day,0,0,0,0);
15029 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15031 this.setValue(this.formatDate(this.date));
15038 setStartDate: function(startDate)
15040 this.startDate = startDate || -Infinity;
15041 if (this.startDate !== -Infinity) {
15042 this.startDate = this.parseDate(this.startDate);
15045 this.updateNavArrows();
15048 setEndDate: function(endDate)
15050 this.endDate = endDate || Infinity;
15051 if (this.endDate !== Infinity) {
15052 this.endDate = this.parseDate(this.endDate);
15055 this.updateNavArrows();
15058 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15060 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15061 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15062 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15064 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15065 return parseInt(d, 10);
15068 this.updateNavArrows();
15071 updateNavArrows: function()
15073 var d = new Date(this.viewDate),
15074 year = d.getUTCFullYear(),
15075 month = d.getUTCMonth();
15077 Roo.each(this.picker().select('.prev', true).elements, function(v){
15079 switch (this.viewMode) {
15082 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15088 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15095 Roo.each(this.picker().select('.next', true).elements, function(v){
15097 switch (this.viewMode) {
15100 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15106 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15114 moveMonth: function(date, dir)
15116 if (!dir) return date;
15117 var new_date = new Date(date.valueOf()),
15118 day = new_date.getUTCDate(),
15119 month = new_date.getUTCMonth(),
15120 mag = Math.abs(dir),
15122 dir = dir > 0 ? 1 : -1;
15125 // If going back one month, make sure month is not current month
15126 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15128 return new_date.getUTCMonth() == month;
15130 // If going forward one month, make sure month is as expected
15131 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15133 return new_date.getUTCMonth() != new_month;
15135 new_month = month + dir;
15136 new_date.setUTCMonth(new_month);
15137 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15138 if (new_month < 0 || new_month > 11)
15139 new_month = (new_month + 12) % 12;
15141 // For magnitudes >1, move one month at a time...
15142 for (var i=0; i<mag; i++)
15143 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15144 new_date = this.moveMonth(new_date, dir);
15145 // ...then reset the day, keeping it in the new month
15146 new_month = new_date.getUTCMonth();
15147 new_date.setUTCDate(day);
15149 return new_month != new_date.getUTCMonth();
15152 // Common date-resetting loop -- if date is beyond end of month, make it
15155 new_date.setUTCDate(--day);
15156 new_date.setUTCMonth(new_month);
15161 moveYear: function(date, dir)
15163 return this.moveMonth(date, dir*12);
15166 dateWithinRange: function(date)
15168 return date >= this.startDate && date <= this.endDate;
15174 this.picker().remove();
15179 Roo.apply(Roo.bootstrap.DateField, {
15190 html: '<i class="fa fa-arrow-left"/>'
15200 html: '<i class="fa fa-arrow-right"/>'
15242 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15243 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15244 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15245 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15246 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15259 navFnc: 'FullYear',
15264 navFnc: 'FullYear',
15269 Roo.apply(Roo.bootstrap.DateField, {
15273 cls: 'datepicker dropdown-menu',
15277 cls: 'datepicker-days',
15281 cls: 'table-condensed',
15283 Roo.bootstrap.DateField.head,
15287 Roo.bootstrap.DateField.footer
15294 cls: 'datepicker-months',
15298 cls: 'table-condensed',
15300 Roo.bootstrap.DateField.head,
15301 Roo.bootstrap.DateField.content,
15302 Roo.bootstrap.DateField.footer
15309 cls: 'datepicker-years',
15313 cls: 'table-condensed',
15315 Roo.bootstrap.DateField.head,
15316 Roo.bootstrap.DateField.content,
15317 Roo.bootstrap.DateField.footer
15336 * @class Roo.bootstrap.TimeField
15337 * @extends Roo.bootstrap.Input
15338 * Bootstrap DateField class
15342 * Create a new TimeField
15343 * @param {Object} config The config object
15346 Roo.bootstrap.TimeField = function(config){
15347 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15351 * Fires when this field show.
15352 * @param {Roo.bootstrap.DateField} this
15353 * @param {Mixed} date The date value
15358 * Fires when this field hide.
15359 * @param {Roo.bootstrap.DateField} this
15360 * @param {Mixed} date The date value
15365 * Fires when select a date.
15366 * @param {Roo.bootstrap.DateField} this
15367 * @param {Mixed} date The date value
15373 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15376 * @cfg {String} format
15377 * The default time format string which can be overriden for localization support. The format must be
15378 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15382 onRender: function(ct, position)
15385 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15387 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15389 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15391 this.pop = this.picker().select('>.datepicker-time',true).first();
15392 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15394 this.picker().on('mousedown', this.onMousedown, this);
15395 this.picker().on('click', this.onClick, this);
15397 this.picker().addClass('datepicker-dropdown');
15402 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15403 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15404 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15405 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15406 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15407 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15411 fireKey: function(e){
15412 if (!this.picker().isVisible()){
15413 if (e.keyCode == 27) // allow escape to hide and re-show picker
15418 e.preventDefault();
15426 this.onTogglePeriod();
15429 this.onIncrementMinutes();
15432 this.onDecrementMinutes();
15441 onClick: function(e) {
15442 e.stopPropagation();
15443 e.preventDefault();
15446 picker : function()
15448 return this.el.select('.datepicker', true).first();
15451 fillTime: function()
15453 var time = this.pop.select('tbody', true).first();
15455 time.dom.innerHTML = '';
15470 cls: 'hours-up glyphicon glyphicon-chevron-up'
15490 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15511 cls: 'timepicker-hour',
15526 cls: 'timepicker-minute',
15541 cls: 'btn btn-primary period',
15563 cls: 'hours-down glyphicon glyphicon-chevron-down'
15583 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15601 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15608 var hours = this.time.getHours();
15609 var minutes = this.time.getMinutes();
15622 hours = hours - 12;
15626 hours = '0' + hours;
15630 minutes = '0' + minutes;
15633 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15634 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15635 this.pop.select('button', true).first().dom.innerHTML = period;
15641 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15643 var cls = ['bottom'];
15645 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15652 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15657 this.picker().addClass(cls.join('-'));
15661 Roo.each(cls, function(c){
15663 _this.picker().setTop(_this.inputEl().getHeight());
15667 _this.picker().setTop(0 - _this.picker().getHeight());
15672 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15676 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15683 onFocus : function()
15685 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15689 onBlur : function()
15691 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15697 this.picker().show();
15702 this.fireEvent('show', this, this.date);
15707 this.picker().hide();
15710 this.fireEvent('hide', this, this.date);
15713 setTime : function()
15716 this.setValue(this.time.format(this.format));
15718 this.fireEvent('select', this, this.date);
15723 onMousedown: function(e){
15724 e.stopPropagation();
15725 e.preventDefault();
15728 onIncrementHours: function()
15730 Roo.log('onIncrementHours');
15731 this.time = this.time.add(Date.HOUR, 1);
15736 onDecrementHours: function()
15738 Roo.log('onDecrementHours');
15739 this.time = this.time.add(Date.HOUR, -1);
15743 onIncrementMinutes: function()
15745 Roo.log('onIncrementMinutes');
15746 this.time = this.time.add(Date.MINUTE, 1);
15750 onDecrementMinutes: function()
15752 Roo.log('onDecrementMinutes');
15753 this.time = this.time.add(Date.MINUTE, -1);
15757 onTogglePeriod: function()
15759 Roo.log('onTogglePeriod');
15760 this.time = this.time.add(Date.HOUR, 12);
15767 Roo.apply(Roo.bootstrap.TimeField, {
15797 cls: 'btn btn-info ok',
15809 Roo.apply(Roo.bootstrap.TimeField, {
15813 cls: 'datepicker dropdown-menu',
15817 cls: 'datepicker-time',
15821 cls: 'table-condensed',
15823 Roo.bootstrap.TimeField.content,
15824 Roo.bootstrap.TimeField.footer
15843 * @class Roo.bootstrap.CheckBox
15844 * @extends Roo.bootstrap.Input
15845 * Bootstrap CheckBox class
15847 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15848 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15849 * @cfg {String} boxLabel The text that appears beside the checkbox
15850 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15851 * @cfg {Boolean} checked initnal the element
15855 * Create a new CheckBox
15856 * @param {Object} config The config object
15859 Roo.bootstrap.CheckBox = function(config){
15860 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15865 * Fires when the element is checked or unchecked.
15866 * @param {Roo.bootstrap.CheckBox} this This input
15867 * @param {Boolean} checked The new checked value
15873 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15875 inputType: 'checkbox',
15882 getAutoCreate : function()
15884 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15890 cfg.cls = 'form-group checkbox' //input-group
15898 type : this.inputType,
15899 value : (!this.checked) ? this.valueOff : this.inputValue,
15900 cls : 'roo-checkbox', //'form-box',
15901 placeholder : this.placeholder || ''
15905 if (this.weight) { // Validity check?
15906 cfg.cls += " checkbox-" + this.weight;
15909 if (this.disabled) {
15910 input.disabled=true;
15914 input.checked = this.checked;
15918 input.name = this.name;
15922 input.cls += ' input-' + this.size;
15926 ['xs','sm','md','lg'].map(function(size){
15927 if (settings[size]) {
15928 cfg.cls += ' col-' + size + '-' + settings[size];
15934 var inputblock = input;
15939 if (this.before || this.after) {
15942 cls : 'input-group',
15946 inputblock.cn.push({
15948 cls : 'input-group-addon',
15952 inputblock.cn.push(input);
15954 inputblock.cn.push({
15956 cls : 'input-group-addon',
15963 if (align ==='left' && this.fieldLabel.length) {
15964 Roo.log("left and has label");
15970 cls : 'control-label col-md-' + this.labelWidth,
15971 html : this.fieldLabel
15975 cls : "col-md-" + (12 - this.labelWidth),
15982 } else if ( this.fieldLabel.length) {
15987 tag: this.boxLabel ? 'span' : 'label',
15989 cls: 'control-label box-input-label',
15990 //cls : 'input-group-addon',
15991 html : this.fieldLabel
16001 Roo.log(" no label && no align");
16002 cfg.cn = [ inputblock ] ;
16011 html: this.boxLabel
16023 * return the real input element.
16025 inputEl: function ()
16027 return this.el.select('input.roo-checkbox',true).first();
16032 return this.el.select('label.control-label',true).first();
16035 initEvents : function()
16037 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16039 this.inputEl().on('click', this.onClick, this);
16043 onClick : function()
16045 this.setChecked(!this.checked);
16048 setChecked : function(state,suppressEvent)
16050 this.checked = state;
16052 this.inputEl().dom.checked = state;
16054 if(suppressEvent !== true){
16055 this.fireEvent('check', this, state);
16058 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16062 setValue : function(v,suppressEvent)
16064 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16078 * @class Roo.bootstrap.Radio
16079 * @extends Roo.bootstrap.CheckBox
16080 * Bootstrap Radio class
16083 * Create a new Radio
16084 * @param {Object} config The config object
16087 Roo.bootstrap.Radio = function(config){
16088 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16092 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16094 inputType: 'radio',
16098 getAutoCreate : function()
16100 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16106 cfg.cls = 'form-group radio' //input-group
16111 type : this.inputType,
16112 value : (!this.checked) ? this.valueOff : this.inputValue,
16114 placeholder : this.placeholder || ''
16117 if (this.weight) { // Validity check?
16118 cfg.cls += " radio-" + this.weight;
16120 if (this.disabled) {
16121 input.disabled=true;
16125 input.checked = this.checked;
16129 input.name = this.name;
16133 input.cls += ' input-' + this.size;
16137 ['xs','sm','md','lg'].map(function(size){
16138 if (settings[size]) {
16139 cfg.cls += ' col-' + size + '-' + settings[size];
16143 var inputblock = input;
16145 if (this.before || this.after) {
16148 cls : 'input-group',
16152 inputblock.cn.push({
16154 cls : 'input-group-addon',
16158 inputblock.cn.push(input);
16160 inputblock.cn.push({
16162 cls : 'input-group-addon',
16169 if (align ==='left' && this.fieldLabel.length) {
16170 Roo.log("left and has label");
16176 cls : 'control-label col-md-' + this.labelWidth,
16177 html : this.fieldLabel
16181 cls : "col-md-" + (12 - this.labelWidth),
16188 } else if ( this.fieldLabel.length) {
16195 cls: 'control-label box-input-label',
16196 //cls : 'input-group-addon',
16197 html : this.fieldLabel
16207 Roo.log(" no label && no align");
16222 html: this.boxLabel
16229 inputEl: function ()
16231 return this.el.select('input.roo-radio',true).first();
16233 onClick : function()
16235 this.setChecked(true);
16238 setChecked : function(state,suppressEvent)
16241 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16242 v.dom.checked = false;
16246 this.checked = state;
16247 this.inputEl().dom.checked = state;
16249 if(suppressEvent !== true){
16250 this.fireEvent('check', this, state);
16253 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16257 getGroupValue : function()
16260 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16261 if(v.dom.checked == true){
16262 value = v.dom.value;
16270 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16271 * @return {Mixed} value The field value
16273 getValue : function(){
16274 return this.getGroupValue();
16280 //<script type="text/javascript">
16283 * Based Ext JS Library 1.1.1
16284 * Copyright(c) 2006-2007, Ext JS, LLC.
16290 * @class Roo.HtmlEditorCore
16291 * @extends Roo.Component
16292 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16294 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16297 Roo.HtmlEditorCore = function(config){
16300 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16305 * @event initialize
16306 * Fires when the editor is fully initialized (including the iframe)
16307 * @param {Roo.HtmlEditorCore} this
16312 * Fires when the editor is first receives the focus. Any insertion must wait
16313 * until after this event.
16314 * @param {Roo.HtmlEditorCore} this
16318 * @event beforesync
16319 * Fires before the textarea is updated with content from the editor iframe. Return false
16320 * to cancel the sync.
16321 * @param {Roo.HtmlEditorCore} this
16322 * @param {String} html
16326 * @event beforepush
16327 * Fires before the iframe editor is updated with content from the textarea. Return false
16328 * to cancel the push.
16329 * @param {Roo.HtmlEditorCore} this
16330 * @param {String} html
16335 * Fires when the textarea is updated with content from the editor iframe.
16336 * @param {Roo.HtmlEditorCore} this
16337 * @param {String} html
16342 * Fires when the iframe editor is updated with content from the textarea.
16343 * @param {Roo.HtmlEditorCore} this
16344 * @param {String} html
16349 * @event editorevent
16350 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16351 * @param {Roo.HtmlEditorCore} this
16356 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16358 // defaults : white / black...
16359 this.applyBlacklists();
16366 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16370 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16376 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16381 * @cfg {Number} height (in pixels)
16385 * @cfg {Number} width (in pixels)
16390 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16393 stylesheets: false,
16398 // private properties
16399 validationEvent : false,
16401 initialized : false,
16403 sourceEditMode : false,
16404 onFocus : Roo.emptyFn,
16406 hideMode:'offsets',
16410 // blacklist + whitelisted elements..
16417 * Protected method that will not generally be called directly. It
16418 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16419 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16421 getDocMarkup : function(){
16424 Roo.log(this.stylesheets);
16426 // inherit styels from page...??
16427 if (this.stylesheets === false) {
16429 Roo.get(document.head).select('style').each(function(node) {
16430 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16433 Roo.get(document.head).select('link').each(function(node) {
16434 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16437 } else if (!this.stylesheets.length) {
16439 st = '<style type="text/css">' +
16440 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16443 Roo.each(this.stylesheets, function(s) {
16444 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16449 st += '<style type="text/css">' +
16450 'IMG { cursor: pointer } ' +
16454 return '<html><head>' + st +
16455 //<style type="text/css">' +
16456 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16458 ' </head><body class="roo-htmleditor-body"></body></html>';
16462 onRender : function(ct, position)
16465 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16466 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16469 this.el.dom.style.border = '0 none';
16470 this.el.dom.setAttribute('tabIndex', -1);
16471 this.el.addClass('x-hidden hide');
16475 if(Roo.isIE){ // fix IE 1px bogus margin
16476 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16480 this.frameId = Roo.id();
16484 var iframe = this.owner.wrap.createChild({
16486 cls: 'form-control', // bootstrap..
16488 name: this.frameId,
16489 frameBorder : 'no',
16490 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16495 this.iframe = iframe.dom;
16497 this.assignDocWin();
16499 this.doc.designMode = 'on';
16502 this.doc.write(this.getDocMarkup());
16506 var task = { // must defer to wait for browser to be ready
16508 //console.log("run task?" + this.doc.readyState);
16509 this.assignDocWin();
16510 if(this.doc.body || this.doc.readyState == 'complete'){
16512 this.doc.designMode="on";
16516 Roo.TaskMgr.stop(task);
16517 this.initEditor.defer(10, this);
16524 Roo.TaskMgr.start(task);
16531 onResize : function(w, h)
16533 Roo.log('resize: ' +w + ',' + h );
16534 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16538 if(typeof w == 'number'){
16540 this.iframe.style.width = w + 'px';
16542 if(typeof h == 'number'){
16544 this.iframe.style.height = h + 'px';
16546 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16553 * Toggles the editor between standard and source edit mode.
16554 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16556 toggleSourceEdit : function(sourceEditMode){
16558 this.sourceEditMode = sourceEditMode === true;
16560 if(this.sourceEditMode){
16562 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16565 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16566 //this.iframe.className = '';
16569 //this.setSize(this.owner.wrap.getSize());
16570 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16577 * Protected method that will not generally be called directly. If you need/want
16578 * custom HTML cleanup, this is the method you should override.
16579 * @param {String} html The HTML to be cleaned
16580 * return {String} The cleaned HTML
16582 cleanHtml : function(html){
16583 html = String(html);
16584 if(html.length > 5){
16585 if(Roo.isSafari){ // strip safari nonsense
16586 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16589 if(html == ' '){
16596 * HTML Editor -> Textarea
16597 * Protected method that will not generally be called directly. Syncs the contents
16598 * of the editor iframe with the textarea.
16600 syncValue : function(){
16601 if(this.initialized){
16602 var bd = (this.doc.body || this.doc.documentElement);
16603 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16604 var html = bd.innerHTML;
16606 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16607 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16609 html = '<div style="'+m[0]+'">' + html + '</div>';
16612 html = this.cleanHtml(html);
16613 // fix up the special chars.. normaly like back quotes in word...
16614 // however we do not want to do this with chinese..
16615 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16616 var cc = b.charCodeAt();
16618 (cc >= 0x4E00 && cc < 0xA000 ) ||
16619 (cc >= 0x3400 && cc < 0x4E00 ) ||
16620 (cc >= 0xf900 && cc < 0xfb00 )
16626 if(this.owner.fireEvent('beforesync', this, html) !== false){
16627 this.el.dom.value = html;
16628 this.owner.fireEvent('sync', this, html);
16634 * Protected method that will not generally be called directly. Pushes the value of the textarea
16635 * into the iframe editor.
16637 pushValue : function(){
16638 if(this.initialized){
16639 var v = this.el.dom.value.trim();
16641 // if(v.length < 1){
16645 if(this.owner.fireEvent('beforepush', this, v) !== false){
16646 var d = (this.doc.body || this.doc.documentElement);
16648 this.cleanUpPaste();
16649 this.el.dom.value = d.innerHTML;
16650 this.owner.fireEvent('push', this, v);
16656 deferFocus : function(){
16657 this.focus.defer(10, this);
16661 focus : function(){
16662 if(this.win && !this.sourceEditMode){
16669 assignDocWin: function()
16671 var iframe = this.iframe;
16674 this.doc = iframe.contentWindow.document;
16675 this.win = iframe.contentWindow;
16677 // if (!Roo.get(this.frameId)) {
16680 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16681 // this.win = Roo.get(this.frameId).dom.contentWindow;
16683 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16687 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16688 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16693 initEditor : function(){
16694 //console.log("INIT EDITOR");
16695 this.assignDocWin();
16699 this.doc.designMode="on";
16701 this.doc.write(this.getDocMarkup());
16704 var dbody = (this.doc.body || this.doc.documentElement);
16705 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16706 // this copies styles from the containing element into thsi one..
16707 // not sure why we need all of this..
16708 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16710 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16711 //ss['background-attachment'] = 'fixed'; // w3c
16712 dbody.bgProperties = 'fixed'; // ie
16713 //Roo.DomHelper.applyStyles(dbody, ss);
16714 Roo.EventManager.on(this.doc, {
16715 //'mousedown': this.onEditorEvent,
16716 'mouseup': this.onEditorEvent,
16717 'dblclick': this.onEditorEvent,
16718 'click': this.onEditorEvent,
16719 'keyup': this.onEditorEvent,
16724 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16726 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16727 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16729 this.initialized = true;
16731 this.owner.fireEvent('initialize', this);
16736 onDestroy : function(){
16742 //for (var i =0; i < this.toolbars.length;i++) {
16743 // // fixme - ask toolbars for heights?
16744 // this.toolbars[i].onDestroy();
16747 //this.wrap.dom.innerHTML = '';
16748 //this.wrap.remove();
16753 onFirstFocus : function(){
16755 this.assignDocWin();
16758 this.activated = true;
16761 if(Roo.isGecko){ // prevent silly gecko errors
16763 var s = this.win.getSelection();
16764 if(!s.focusNode || s.focusNode.nodeType != 3){
16765 var r = s.getRangeAt(0);
16766 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16771 this.execCmd('useCSS', true);
16772 this.execCmd('styleWithCSS', false);
16775 this.owner.fireEvent('activate', this);
16779 adjustFont: function(btn){
16780 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16781 //if(Roo.isSafari){ // safari
16784 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16785 if(Roo.isSafari){ // safari
16786 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16787 v = (v < 10) ? 10 : v;
16788 v = (v > 48) ? 48 : v;
16789 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16794 v = Math.max(1, v+adjust);
16796 this.execCmd('FontSize', v );
16799 onEditorEvent : function(e){
16800 this.owner.fireEvent('editorevent', this, e);
16801 // this.updateToolbar();
16802 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16805 insertTag : function(tg)
16807 // could be a bit smarter... -> wrap the current selected tRoo..
16808 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16810 range = this.createRange(this.getSelection());
16811 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16812 wrappingNode.appendChild(range.extractContents());
16813 range.insertNode(wrappingNode);
16820 this.execCmd("formatblock", tg);
16824 insertText : function(txt)
16828 var range = this.createRange();
16829 range.deleteContents();
16830 //alert(Sender.getAttribute('label'));
16832 range.insertNode(this.doc.createTextNode(txt));
16838 * Executes a Midas editor command on the editor document and performs necessary focus and
16839 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16840 * @param {String} cmd The Midas command
16841 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16843 relayCmd : function(cmd, value){
16845 this.execCmd(cmd, value);
16846 this.owner.fireEvent('editorevent', this);
16847 //this.updateToolbar();
16848 this.owner.deferFocus();
16852 * Executes a Midas editor command directly on the editor document.
16853 * For visual commands, you should use {@link #relayCmd} instead.
16854 * <b>This should only be called after the editor is initialized.</b>
16855 * @param {String} cmd The Midas command
16856 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16858 execCmd : function(cmd, value){
16859 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16866 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16868 * @param {String} text | dom node..
16870 insertAtCursor : function(text)
16875 if(!this.activated){
16881 var r = this.doc.selection.createRange();
16892 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16896 // from jquery ui (MIT licenced)
16898 var win = this.win;
16900 if (win.getSelection && win.getSelection().getRangeAt) {
16901 range = win.getSelection().getRangeAt(0);
16902 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16903 range.insertNode(node);
16904 } else if (win.document.selection && win.document.selection.createRange) {
16905 // no firefox support
16906 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16907 win.document.selection.createRange().pasteHTML(txt);
16909 // no firefox support
16910 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16911 this.execCmd('InsertHTML', txt);
16920 mozKeyPress : function(e){
16922 var c = e.getCharCode(), cmd;
16925 c = String.fromCharCode(c).toLowerCase();
16939 this.cleanUpPaste.defer(100, this);
16947 e.preventDefault();
16955 fixKeys : function(){ // load time branching for fastest keydown performance
16957 return function(e){
16958 var k = e.getKey(), r;
16961 r = this.doc.selection.createRange();
16964 r.pasteHTML('    ');
16971 r = this.doc.selection.createRange();
16973 var target = r.parentElement();
16974 if(!target || target.tagName.toLowerCase() != 'li'){
16976 r.pasteHTML('<br />');
16982 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16983 this.cleanUpPaste.defer(100, this);
16989 }else if(Roo.isOpera){
16990 return function(e){
16991 var k = e.getKey();
16995 this.execCmd('InsertHTML','    ');
16998 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16999 this.cleanUpPaste.defer(100, this);
17004 }else if(Roo.isSafari){
17005 return function(e){
17006 var k = e.getKey();
17010 this.execCmd('InsertText','\t');
17014 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17015 this.cleanUpPaste.defer(100, this);
17023 getAllAncestors: function()
17025 var p = this.getSelectedNode();
17028 a.push(p); // push blank onto stack..
17029 p = this.getParentElement();
17033 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17037 a.push(this.doc.body);
17041 lastSelNode : false,
17044 getSelection : function()
17046 this.assignDocWin();
17047 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17050 getSelectedNode: function()
17052 // this may only work on Gecko!!!
17054 // should we cache this!!!!
17059 var range = this.createRange(this.getSelection()).cloneRange();
17062 var parent = range.parentElement();
17064 var testRange = range.duplicate();
17065 testRange.moveToElementText(parent);
17066 if (testRange.inRange(range)) {
17069 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17072 parent = parent.parentElement;
17077 // is ancestor a text element.
17078 var ac = range.commonAncestorContainer;
17079 if (ac.nodeType == 3) {
17080 ac = ac.parentNode;
17083 var ar = ac.childNodes;
17086 var other_nodes = [];
17087 var has_other_nodes = false;
17088 for (var i=0;i<ar.length;i++) {
17089 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17092 // fullly contained node.
17094 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17099 // probably selected..
17100 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17101 other_nodes.push(ar[i]);
17105 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17110 has_other_nodes = true;
17112 if (!nodes.length && other_nodes.length) {
17113 nodes= other_nodes;
17115 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17121 createRange: function(sel)
17123 // this has strange effects when using with
17124 // top toolbar - not sure if it's a great idea.
17125 //this.editor.contentWindow.focus();
17126 if (typeof sel != "undefined") {
17128 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17130 return this.doc.createRange();
17133 return this.doc.createRange();
17136 getParentElement: function()
17139 this.assignDocWin();
17140 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17142 var range = this.createRange(sel);
17145 var p = range.commonAncestorContainer;
17146 while (p.nodeType == 3) { // text node
17157 * Range intersection.. the hard stuff...
17161 * [ -- selected range --- ]
17165 * if end is before start or hits it. fail.
17166 * if start is after end or hits it fail.
17168 * if either hits (but other is outside. - then it's not
17174 // @see http://www.thismuchiknow.co.uk/?p=64.
17175 rangeIntersectsNode : function(range, node)
17177 var nodeRange = node.ownerDocument.createRange();
17179 nodeRange.selectNode(node);
17181 nodeRange.selectNodeContents(node);
17184 var rangeStartRange = range.cloneRange();
17185 rangeStartRange.collapse(true);
17187 var rangeEndRange = range.cloneRange();
17188 rangeEndRange.collapse(false);
17190 var nodeStartRange = nodeRange.cloneRange();
17191 nodeStartRange.collapse(true);
17193 var nodeEndRange = nodeRange.cloneRange();
17194 nodeEndRange.collapse(false);
17196 return rangeStartRange.compareBoundaryPoints(
17197 Range.START_TO_START, nodeEndRange) == -1 &&
17198 rangeEndRange.compareBoundaryPoints(
17199 Range.START_TO_START, nodeStartRange) == 1;
17203 rangeCompareNode : function(range, node)
17205 var nodeRange = node.ownerDocument.createRange();
17207 nodeRange.selectNode(node);
17209 nodeRange.selectNodeContents(node);
17213 range.collapse(true);
17215 nodeRange.collapse(true);
17217 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17218 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17220 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17222 var nodeIsBefore = ss == 1;
17223 var nodeIsAfter = ee == -1;
17225 if (nodeIsBefore && nodeIsAfter)
17227 if (!nodeIsBefore && nodeIsAfter)
17228 return 1; //right trailed.
17230 if (nodeIsBefore && !nodeIsAfter)
17231 return 2; // left trailed.
17236 // private? - in a new class?
17237 cleanUpPaste : function()
17239 // cleans up the whole document..
17240 Roo.log('cleanuppaste');
17242 this.cleanUpChildren(this.doc.body);
17243 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17244 if (clean != this.doc.body.innerHTML) {
17245 this.doc.body.innerHTML = clean;
17250 cleanWordChars : function(input) {// change the chars to hex code
17251 var he = Roo.HtmlEditorCore;
17253 var output = input;
17254 Roo.each(he.swapCodes, function(sw) {
17255 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17257 output = output.replace(swapper, sw[1]);
17264 cleanUpChildren : function (n)
17266 if (!n.childNodes.length) {
17269 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17270 this.cleanUpChild(n.childNodes[i]);
17277 cleanUpChild : function (node)
17280 //console.log(node);
17281 if (node.nodeName == "#text") {
17282 // clean up silly Windows -- stuff?
17285 if (node.nodeName == "#comment") {
17286 node.parentNode.removeChild(node);
17287 // clean up silly Windows -- stuff?
17290 var lcname = node.tagName.toLowerCase();
17291 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17292 // whitelist of tags..
17294 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17296 node.parentNode.removeChild(node);
17301 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17303 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17304 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17306 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17307 // remove_keep_children = true;
17310 if (remove_keep_children) {
17311 this.cleanUpChildren(node);
17312 // inserts everything just before this node...
17313 while (node.childNodes.length) {
17314 var cn = node.childNodes[0];
17315 node.removeChild(cn);
17316 node.parentNode.insertBefore(cn, node);
17318 node.parentNode.removeChild(node);
17322 if (!node.attributes || !node.attributes.length) {
17323 this.cleanUpChildren(node);
17327 function cleanAttr(n,v)
17330 if (v.match(/^\./) || v.match(/^\//)) {
17333 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17336 if (v.match(/^#/)) {
17339 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17340 node.removeAttribute(n);
17344 function cleanStyle(n,v)
17346 if (v.match(/expression/)) { //XSS?? should we even bother..
17347 node.removeAttribute(n);
17350 var cwhite = this.cwhite;
17351 var cblack = this.cblack;
17354 var parts = v.split(/;/);
17357 Roo.each(parts, function(p) {
17358 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17362 var l = p.split(':').shift().replace(/\s+/g,'');
17363 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17365 if ( cblack.indexOf(l) > -1) {
17366 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17367 //node.removeAttribute(n);
17371 // only allow 'c whitelisted system attributes'
17372 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17373 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17374 //node.removeAttribute(n);
17384 if (clean.length) {
17385 node.setAttribute(n, clean.join(';'));
17387 node.removeAttribute(n);
17393 for (var i = node.attributes.length-1; i > -1 ; i--) {
17394 var a = node.attributes[i];
17397 if (a.name.toLowerCase().substr(0,2)=='on') {
17398 node.removeAttribute(a.name);
17401 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17402 node.removeAttribute(a.name);
17405 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17406 cleanAttr(a.name,a.value); // fixme..
17409 if (a.name == 'style') {
17410 cleanStyle(a.name,a.value);
17413 /// clean up MS crap..
17414 // tecnically this should be a list of valid class'es..
17417 if (a.name == 'class') {
17418 if (a.value.match(/^Mso/)) {
17419 node.className = '';
17422 if (a.value.match(/body/)) {
17423 node.className = '';
17434 this.cleanUpChildren(node);
17439 * Clean up MS wordisms...
17441 cleanWord : function(node)
17444 var cleanWordChildren = function()
17446 if (!node.childNodes.length) {
17449 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17450 _t.cleanWord(node.childNodes[i]);
17456 this.cleanWord(this.doc.body);
17459 if (node.nodeName == "#text") {
17460 // clean up silly Windows -- stuff?
17463 if (node.nodeName == "#comment") {
17464 node.parentNode.removeChild(node);
17465 // clean up silly Windows -- stuff?
17469 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17470 node.parentNode.removeChild(node);
17474 // remove - but keep children..
17475 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17476 while (node.childNodes.length) {
17477 var cn = node.childNodes[0];
17478 node.removeChild(cn);
17479 node.parentNode.insertBefore(cn, node);
17481 node.parentNode.removeChild(node);
17482 cleanWordChildren();
17486 if (node.className.length) {
17488 var cn = node.className.split(/\W+/);
17490 Roo.each(cn, function(cls) {
17491 if (cls.match(/Mso[a-zA-Z]+/)) {
17496 node.className = cna.length ? cna.join(' ') : '';
17498 node.removeAttribute("class");
17502 if (node.hasAttribute("lang")) {
17503 node.removeAttribute("lang");
17506 if (node.hasAttribute("style")) {
17508 var styles = node.getAttribute("style").split(";");
17510 Roo.each(styles, function(s) {
17511 if (!s.match(/:/)) {
17514 var kv = s.split(":");
17515 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17518 // what ever is left... we allow.
17521 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17522 if (!nstyle.length) {
17523 node.removeAttribute('style');
17527 cleanWordChildren();
17531 domToHTML : function(currentElement, depth, nopadtext) {
17533 depth = depth || 0;
17534 nopadtext = nopadtext || false;
17536 if (!currentElement) {
17537 return this.domToHTML(this.doc.body);
17540 //Roo.log(currentElement);
17542 var allText = false;
17543 var nodeName = currentElement.nodeName;
17544 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17546 if (nodeName == '#text') {
17547 return currentElement.nodeValue;
17552 if (nodeName != 'BODY') {
17555 // Prints the node tagName, such as <A>, <IMG>, etc
17558 for(i = 0; i < currentElement.attributes.length;i++) {
17560 var aname = currentElement.attributes.item(i).name;
17561 if (!currentElement.attributes.item(i).value.length) {
17564 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17567 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17576 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17579 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17584 // Traverse the tree
17586 var currentElementChild = currentElement.childNodes.item(i);
17587 var allText = true;
17588 var innerHTML = '';
17590 while (currentElementChild) {
17591 // Formatting code (indent the tree so it looks nice on the screen)
17592 var nopad = nopadtext;
17593 if (lastnode == 'SPAN') {
17597 if (currentElementChild.nodeName == '#text') {
17598 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17599 if (!nopad && toadd.length > 80) {
17600 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17602 innerHTML += toadd;
17605 currentElementChild = currentElement.childNodes.item(i);
17611 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17613 // Recursively traverse the tree structure of the child node
17614 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17615 lastnode = currentElementChild.nodeName;
17617 currentElementChild=currentElement.childNodes.item(i);
17623 // The remaining code is mostly for formatting the tree
17624 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17629 ret+= "</"+tagName+">";
17635 applyBlacklists : function()
17637 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17638 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17642 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17643 if (b.indexOf(tag) > -1) {
17646 this.white.push(tag);
17650 Roo.each(w, function(tag) {
17651 if (b.indexOf(tag) > -1) {
17654 if (this.white.indexOf(tag) > -1) {
17657 this.white.push(tag);
17662 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17663 if (w.indexOf(tag) > -1) {
17666 this.black.push(tag);
17670 Roo.each(b, function(tag) {
17671 if (w.indexOf(tag) > -1) {
17674 if (this.black.indexOf(tag) > -1) {
17677 this.black.push(tag);
17682 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17683 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17687 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17688 if (b.indexOf(tag) > -1) {
17691 this.cwhite.push(tag);
17695 Roo.each(w, function(tag) {
17696 if (b.indexOf(tag) > -1) {
17699 if (this.cwhite.indexOf(tag) > -1) {
17702 this.cwhite.push(tag);
17707 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17708 if (w.indexOf(tag) > -1) {
17711 this.cblack.push(tag);
17715 Roo.each(b, function(tag) {
17716 if (w.indexOf(tag) > -1) {
17719 if (this.cblack.indexOf(tag) > -1) {
17722 this.cblack.push(tag);
17727 // hide stuff that is not compatible
17741 * @event specialkey
17745 * @cfg {String} fieldClass @hide
17748 * @cfg {String} focusClass @hide
17751 * @cfg {String} autoCreate @hide
17754 * @cfg {String} inputType @hide
17757 * @cfg {String} invalidClass @hide
17760 * @cfg {String} invalidText @hide
17763 * @cfg {String} msgFx @hide
17766 * @cfg {String} validateOnBlur @hide
17770 Roo.HtmlEditorCore.white = [
17771 'area', 'br', 'img', 'input', 'hr', 'wbr',
17773 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17774 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17775 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17776 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17777 'table', 'ul', 'xmp',
17779 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17782 'dir', 'menu', 'ol', 'ul', 'dl',
17788 Roo.HtmlEditorCore.black = [
17789 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17791 'base', 'basefont', 'bgsound', 'blink', 'body',
17792 'frame', 'frameset', 'head', 'html', 'ilayer',
17793 'iframe', 'layer', 'link', 'meta', 'object',
17794 'script', 'style' ,'title', 'xml' // clean later..
17796 Roo.HtmlEditorCore.clean = [
17797 'script', 'style', 'title', 'xml'
17799 Roo.HtmlEditorCore.remove = [
17804 Roo.HtmlEditorCore.ablack = [
17808 Roo.HtmlEditorCore.aclean = [
17809 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17813 Roo.HtmlEditorCore.pwhite= [
17814 'http', 'https', 'mailto'
17817 // white listed style attributes.
17818 Roo.HtmlEditorCore.cwhite= [
17819 // 'text-align', /// default is to allow most things..
17825 // black listed style attributes.
17826 Roo.HtmlEditorCore.cblack= [
17827 // 'font-size' -- this can be set by the project
17831 Roo.HtmlEditorCore.swapCodes =[
17850 * @class Roo.bootstrap.HtmlEditor
17851 * @extends Roo.bootstrap.TextArea
17852 * Bootstrap HtmlEditor class
17855 * Create a new HtmlEditor
17856 * @param {Object} config The config object
17859 Roo.bootstrap.HtmlEditor = function(config){
17860 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17861 if (!this.toolbars) {
17862 this.toolbars = [];
17864 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17867 * @event initialize
17868 * Fires when the editor is fully initialized (including the iframe)
17869 * @param {HtmlEditor} this
17874 * Fires when the editor is first receives the focus. Any insertion must wait
17875 * until after this event.
17876 * @param {HtmlEditor} this
17880 * @event beforesync
17881 * Fires before the textarea is updated with content from the editor iframe. Return false
17882 * to cancel the sync.
17883 * @param {HtmlEditor} this
17884 * @param {String} html
17888 * @event beforepush
17889 * Fires before the iframe editor is updated with content from the textarea. Return false
17890 * to cancel the push.
17891 * @param {HtmlEditor} this
17892 * @param {String} html
17897 * Fires when the textarea is updated with content from the editor iframe.
17898 * @param {HtmlEditor} this
17899 * @param {String} html
17904 * Fires when the iframe editor is updated with content from the textarea.
17905 * @param {HtmlEditor} this
17906 * @param {String} html
17910 * @event editmodechange
17911 * Fires when the editor switches edit modes
17912 * @param {HtmlEditor} this
17913 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17915 editmodechange: true,
17917 * @event editorevent
17918 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17919 * @param {HtmlEditor} this
17923 * @event firstfocus
17924 * Fires when on first focus - needed by toolbars..
17925 * @param {HtmlEditor} this
17930 * Auto save the htmlEditor value as a file into Events
17931 * @param {HtmlEditor} this
17935 * @event savedpreview
17936 * preview the saved version of htmlEditor
17937 * @param {HtmlEditor} this
17944 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17948 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17953 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17958 * @cfg {Number} height (in pixels)
17962 * @cfg {Number} width (in pixels)
17967 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17970 stylesheets: false,
17975 // private properties
17976 validationEvent : false,
17978 initialized : false,
17981 onFocus : Roo.emptyFn,
17983 hideMode:'offsets',
17986 tbContainer : false,
17988 toolbarContainer :function() {
17989 return this.wrap.select('.x-html-editor-tb',true).first();
17993 * Protected method that will not generally be called directly. It
17994 * is called when the editor creates its toolbar. Override this method if you need to
17995 * add custom toolbar buttons.
17996 * @param {HtmlEditor} editor
17998 createToolbar : function(){
18000 Roo.log("create toolbars");
18002 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18003 this.toolbars[0].render(this.toolbarContainer());
18007 // if (!editor.toolbars || !editor.toolbars.length) {
18008 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18011 // for (var i =0 ; i < editor.toolbars.length;i++) {
18012 // editor.toolbars[i] = Roo.factory(
18013 // typeof(editor.toolbars[i]) == 'string' ?
18014 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18015 // Roo.bootstrap.HtmlEditor);
18016 // editor.toolbars[i].init(editor);
18022 onRender : function(ct, position)
18024 // Roo.log("Call onRender: " + this.xtype);
18026 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18028 this.wrap = this.inputEl().wrap({
18029 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18032 this.editorcore.onRender(ct, position);
18034 if (this.resizable) {
18035 this.resizeEl = new Roo.Resizable(this.wrap, {
18039 minHeight : this.height,
18040 height: this.height,
18041 handles : this.resizable,
18044 resize : function(r, w, h) {
18045 _t.onResize(w,h); // -something
18051 this.createToolbar(this);
18054 if(!this.width && this.resizable){
18055 this.setSize(this.wrap.getSize());
18057 if (this.resizeEl) {
18058 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18059 // should trigger onReize..
18065 onResize : function(w, h)
18067 Roo.log('resize: ' +w + ',' + h );
18068 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18072 if(this.inputEl() ){
18073 if(typeof w == 'number'){
18074 var aw = w - this.wrap.getFrameWidth('lr');
18075 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18078 if(typeof h == 'number'){
18079 var tbh = -11; // fixme it needs to tool bar size!
18080 for (var i =0; i < this.toolbars.length;i++) {
18081 // fixme - ask toolbars for heights?
18082 tbh += this.toolbars[i].el.getHeight();
18083 //if (this.toolbars[i].footer) {
18084 // tbh += this.toolbars[i].footer.el.getHeight();
18092 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18093 ah -= 5; // knock a few pixes off for look..
18094 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18098 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18099 this.editorcore.onResize(ew,eh);
18104 * Toggles the editor between standard and source edit mode.
18105 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18107 toggleSourceEdit : function(sourceEditMode)
18109 this.editorcore.toggleSourceEdit(sourceEditMode);
18111 if(this.editorcore.sourceEditMode){
18112 Roo.log('editor - showing textarea');
18115 // Roo.log(this.syncValue());
18117 this.inputEl().removeClass(['hide', 'x-hidden']);
18118 this.inputEl().dom.removeAttribute('tabIndex');
18119 this.inputEl().focus();
18121 Roo.log('editor - hiding textarea');
18123 // Roo.log(this.pushValue());
18126 this.inputEl().addClass(['hide', 'x-hidden']);
18127 this.inputEl().dom.setAttribute('tabIndex', -1);
18128 //this.deferFocus();
18131 if(this.resizable){
18132 this.setSize(this.wrap.getSize());
18135 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18138 // private (for BoxComponent)
18139 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18141 // private (for BoxComponent)
18142 getResizeEl : function(){
18146 // private (for BoxComponent)
18147 getPositionEl : function(){
18152 initEvents : function(){
18153 this.originalValue = this.getValue();
18157 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18160 // markInvalid : Roo.emptyFn,
18162 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18165 // clearInvalid : Roo.emptyFn,
18167 setValue : function(v){
18168 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18169 this.editorcore.pushValue();
18174 deferFocus : function(){
18175 this.focus.defer(10, this);
18179 focus : function(){
18180 this.editorcore.focus();
18186 onDestroy : function(){
18192 for (var i =0; i < this.toolbars.length;i++) {
18193 // fixme - ask toolbars for heights?
18194 this.toolbars[i].onDestroy();
18197 this.wrap.dom.innerHTML = '';
18198 this.wrap.remove();
18203 onFirstFocus : function(){
18204 //Roo.log("onFirstFocus");
18205 this.editorcore.onFirstFocus();
18206 for (var i =0; i < this.toolbars.length;i++) {
18207 this.toolbars[i].onFirstFocus();
18213 syncValue : function()
18215 this.editorcore.syncValue();
18218 pushValue : function()
18220 this.editorcore.pushValue();
18224 // hide stuff that is not compatible
18238 * @event specialkey
18242 * @cfg {String} fieldClass @hide
18245 * @cfg {String} focusClass @hide
18248 * @cfg {String} autoCreate @hide
18251 * @cfg {String} inputType @hide
18254 * @cfg {String} invalidClass @hide
18257 * @cfg {String} invalidText @hide
18260 * @cfg {String} msgFx @hide
18263 * @cfg {String} validateOnBlur @hide
18272 Roo.namespace('Roo.bootstrap.htmleditor');
18274 * @class Roo.bootstrap.HtmlEditorToolbar1
18279 new Roo.bootstrap.HtmlEditor({
18282 new Roo.bootstrap.HtmlEditorToolbar1({
18283 disable : { fonts: 1 , format: 1, ..., ... , ...],
18289 * @cfg {Object} disable List of elements to disable..
18290 * @cfg {Array} btns List of additional buttons.
18294 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18297 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18300 Roo.apply(this, config);
18302 // default disabled, based on 'good practice'..
18303 this.disable = this.disable || {};
18304 Roo.applyIf(this.disable, {
18307 specialElements : true
18309 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18311 this.editor = config.editor;
18312 this.editorcore = config.editor.editorcore;
18314 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18316 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18317 // dont call parent... till later.
18319 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18324 editorcore : false,
18329 "h1","h2","h3","h4","h5","h6",
18331 "abbr", "acronym", "address", "cite", "samp", "var",
18335 onRender : function(ct, position)
18337 // Roo.log("Call onRender: " + this.xtype);
18339 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18341 this.el.dom.style.marginBottom = '0';
18343 var editorcore = this.editorcore;
18344 var editor= this.editor;
18347 var btn = function(id,cmd , toggle, handler){
18349 var event = toggle ? 'toggle' : 'click';
18354 xns: Roo.bootstrap,
18357 enableToggle:toggle !== false,
18359 pressed : toggle ? false : null,
18362 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18363 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18372 xns: Roo.bootstrap,
18373 glyphicon : 'font',
18377 xns: Roo.bootstrap,
18381 Roo.each(this.formats, function(f) {
18382 style.menu.items.push({
18384 xns: Roo.bootstrap,
18385 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18390 editorcore.insertTag(this.tagname);
18397 children.push(style);
18400 btn('bold',false,true);
18401 btn('italic',false,true);
18402 btn('align-left', 'justifyleft',true);
18403 btn('align-center', 'justifycenter',true);
18404 btn('align-right' , 'justifyright',true);
18405 btn('link', false, false, function(btn) {
18406 //Roo.log("create link?");
18407 var url = prompt(this.createLinkText, this.defaultLinkValue);
18408 if(url && url != 'http:/'+'/'){
18409 this.editorcore.relayCmd('createlink', url);
18412 btn('list','insertunorderedlist',true);
18413 btn('pencil', false,true, function(btn){
18416 this.toggleSourceEdit(btn.pressed);
18422 xns: Roo.bootstrap,
18427 xns: Roo.bootstrap,
18432 cog.menu.items.push({
18434 xns: Roo.bootstrap,
18435 html : Clean styles,
18440 editorcore.insertTag(this.tagname);
18449 this.xtype = 'NavSimplebar';
18451 for(var i=0;i< children.length;i++) {
18453 this.buttons.add(this.addxtypeChild(children[i]));
18457 editor.on('editorevent', this.updateToolbar, this);
18459 onBtnClick : function(id)
18461 this.editorcore.relayCmd(id);
18462 this.editorcore.focus();
18466 * Protected method that will not generally be called directly. It triggers
18467 * a toolbar update by reading the markup state of the current selection in the editor.
18469 updateToolbar: function(){
18471 if(!this.editorcore.activated){
18472 this.editor.onFirstFocus(); // is this neeed?
18476 var btns = this.buttons;
18477 var doc = this.editorcore.doc;
18478 btns.get('bold').setActive(doc.queryCommandState('bold'));
18479 btns.get('italic').setActive(doc.queryCommandState('italic'));
18480 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18482 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18483 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18484 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18486 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18487 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18490 var ans = this.editorcore.getAllAncestors();
18491 if (this.formatCombo) {
18494 var store = this.formatCombo.store;
18495 this.formatCombo.setValue("");
18496 for (var i =0; i < ans.length;i++) {
18497 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18499 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18507 // hides menus... - so this cant be on a menu...
18508 Roo.bootstrap.MenuMgr.hideAll();
18510 Roo.bootstrap.MenuMgr.hideAll();
18511 //this.editorsyncValue();
18513 onFirstFocus: function() {
18514 this.buttons.each(function(item){
18518 toggleSourceEdit : function(sourceEditMode){
18521 if(sourceEditMode){
18522 Roo.log("disabling buttons");
18523 this.buttons.each( function(item){
18524 if(item.cmd != 'pencil'){
18530 Roo.log("enabling buttons");
18531 if(this.editorcore.initialized){
18532 this.buttons.each( function(item){
18538 Roo.log("calling toggole on editor");
18539 // tell the editor that it's been pressed..
18540 this.editor.toggleSourceEdit(sourceEditMode);
18550 * @class Roo.bootstrap.Table.AbstractSelectionModel
18551 * @extends Roo.util.Observable
18552 * Abstract base class for grid SelectionModels. It provides the interface that should be
18553 * implemented by descendant classes. This class should not be directly instantiated.
18556 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18557 this.locked = false;
18558 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18562 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18563 /** @ignore Called by the grid automatically. Do not call directly. */
18564 init : function(grid){
18570 * Locks the selections.
18573 this.locked = true;
18577 * Unlocks the selections.
18579 unlock : function(){
18580 this.locked = false;
18584 * Returns true if the selections are locked.
18585 * @return {Boolean}
18587 isLocked : function(){
18588 return this.locked;
18592 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18593 * @class Roo.bootstrap.Table.RowSelectionModel
18594 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18595 * It supports multiple selections and keyboard selection/navigation.
18597 * @param {Object} config
18600 Roo.bootstrap.Table.RowSelectionModel = function(config){
18601 Roo.apply(this, config);
18602 this.selections = new Roo.util.MixedCollection(false, function(o){
18607 this.lastActive = false;
18611 * @event selectionchange
18612 * Fires when the selection changes
18613 * @param {SelectionModel} this
18615 "selectionchange" : true,
18617 * @event afterselectionchange
18618 * Fires after the selection changes (eg. by key press or clicking)
18619 * @param {SelectionModel} this
18621 "afterselectionchange" : true,
18623 * @event beforerowselect
18624 * Fires when a row is selected being selected, return false to cancel.
18625 * @param {SelectionModel} this
18626 * @param {Number} rowIndex The selected index
18627 * @param {Boolean} keepExisting False if other selections will be cleared
18629 "beforerowselect" : true,
18632 * Fires when a row is selected.
18633 * @param {SelectionModel} this
18634 * @param {Number} rowIndex The selected index
18635 * @param {Roo.data.Record} r The record
18637 "rowselect" : true,
18639 * @event rowdeselect
18640 * Fires when a row is deselected.
18641 * @param {SelectionModel} this
18642 * @param {Number} rowIndex The selected index
18644 "rowdeselect" : true
18646 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18647 this.locked = false;
18650 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18652 * @cfg {Boolean} singleSelect
18653 * True to allow selection of only one row at a time (defaults to false)
18655 singleSelect : false,
18658 initEvents : function(){
18660 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18661 this.grid.on("mousedown", this.handleMouseDown, this);
18662 }else{ // allow click to work like normal
18663 this.grid.on("rowclick", this.handleDragableRowClick, this);
18666 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18667 "up" : function(e){
18669 this.selectPrevious(e.shiftKey);
18670 }else if(this.last !== false && this.lastActive !== false){
18671 var last = this.last;
18672 this.selectRange(this.last, this.lastActive-1);
18673 this.grid.getView().focusRow(this.lastActive);
18674 if(last !== false){
18678 this.selectFirstRow();
18680 this.fireEvent("afterselectionchange", this);
18682 "down" : function(e){
18684 this.selectNext(e.shiftKey);
18685 }else if(this.last !== false && this.lastActive !== false){
18686 var last = this.last;
18687 this.selectRange(this.last, this.lastActive+1);
18688 this.grid.getView().focusRow(this.lastActive);
18689 if(last !== false){
18693 this.selectFirstRow();
18695 this.fireEvent("afterselectionchange", this);
18700 var view = this.grid.view;
18701 view.on("refresh", this.onRefresh, this);
18702 view.on("rowupdated", this.onRowUpdated, this);
18703 view.on("rowremoved", this.onRemove, this);
18707 onRefresh : function(){
18708 var ds = this.grid.dataSource, i, v = this.grid.view;
18709 var s = this.selections;
18710 s.each(function(r){
18711 if((i = ds.indexOfId(r.id)) != -1){
18720 onRemove : function(v, index, r){
18721 this.selections.remove(r);
18725 onRowUpdated : function(v, index, r){
18726 if(this.isSelected(r)){
18727 v.onRowSelect(index);
18733 * @param {Array} records The records to select
18734 * @param {Boolean} keepExisting (optional) True to keep existing selections
18736 selectRecords : function(records, keepExisting){
18738 this.clearSelections();
18740 var ds = this.grid.dataSource;
18741 for(var i = 0, len = records.length; i < len; i++){
18742 this.selectRow(ds.indexOf(records[i]), true);
18747 * Gets the number of selected rows.
18750 getCount : function(){
18751 return this.selections.length;
18755 * Selects the first row in the grid.
18757 selectFirstRow : function(){
18762 * Select the last row.
18763 * @param {Boolean} keepExisting (optional) True to keep existing selections
18765 selectLastRow : function(keepExisting){
18766 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18770 * Selects the row immediately following the last selected row.
18771 * @param {Boolean} keepExisting (optional) True to keep existing selections
18773 selectNext : function(keepExisting){
18774 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18775 this.selectRow(this.last+1, keepExisting);
18776 this.grid.getView().focusRow(this.last);
18781 * Selects the row that precedes the last selected row.
18782 * @param {Boolean} keepExisting (optional) True to keep existing selections
18784 selectPrevious : function(keepExisting){
18786 this.selectRow(this.last-1, keepExisting);
18787 this.grid.getView().focusRow(this.last);
18792 * Returns the selected records
18793 * @return {Array} Array of selected records
18795 getSelections : function(){
18796 return [].concat(this.selections.items);
18800 * Returns the first selected record.
18803 getSelected : function(){
18804 return this.selections.itemAt(0);
18809 * Clears all selections.
18811 clearSelections : function(fast){
18812 if(this.locked) return;
18814 var ds = this.grid.dataSource;
18815 var s = this.selections;
18816 s.each(function(r){
18817 this.deselectRow(ds.indexOfId(r.id));
18821 this.selections.clear();
18828 * Selects all rows.
18830 selectAll : function(){
18831 if(this.locked) return;
18832 this.selections.clear();
18833 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18834 this.selectRow(i, true);
18839 * Returns True if there is a selection.
18840 * @return {Boolean}
18842 hasSelection : function(){
18843 return this.selections.length > 0;
18847 * Returns True if the specified row is selected.
18848 * @param {Number/Record} record The record or index of the record to check
18849 * @return {Boolean}
18851 isSelected : function(index){
18852 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18853 return (r && this.selections.key(r.id) ? true : false);
18857 * Returns True if the specified record id is selected.
18858 * @param {String} id The id of record to check
18859 * @return {Boolean}
18861 isIdSelected : function(id){
18862 return (this.selections.key(id) ? true : false);
18866 handleMouseDown : function(e, t){
18867 var view = this.grid.getView(), rowIndex;
18868 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18871 if(e.shiftKey && this.last !== false){
18872 var last = this.last;
18873 this.selectRange(last, rowIndex, e.ctrlKey);
18874 this.last = last; // reset the last
18875 view.focusRow(rowIndex);
18877 var isSelected = this.isSelected(rowIndex);
18878 if(e.button !== 0 && isSelected){
18879 view.focusRow(rowIndex);
18880 }else if(e.ctrlKey && isSelected){
18881 this.deselectRow(rowIndex);
18882 }else if(!isSelected){
18883 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18884 view.focusRow(rowIndex);
18887 this.fireEvent("afterselectionchange", this);
18890 handleDragableRowClick : function(grid, rowIndex, e)
18892 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18893 this.selectRow(rowIndex, false);
18894 grid.view.focusRow(rowIndex);
18895 this.fireEvent("afterselectionchange", this);
18900 * Selects multiple rows.
18901 * @param {Array} rows Array of the indexes of the row to select
18902 * @param {Boolean} keepExisting (optional) True to keep existing selections
18904 selectRows : function(rows, keepExisting){
18906 this.clearSelections();
18908 for(var i = 0, len = rows.length; i < len; i++){
18909 this.selectRow(rows[i], true);
18914 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18915 * @param {Number} startRow The index of the first row in the range
18916 * @param {Number} endRow The index of the last row in the range
18917 * @param {Boolean} keepExisting (optional) True to retain existing selections
18919 selectRange : function(startRow, endRow, keepExisting){
18920 if(this.locked) return;
18922 this.clearSelections();
18924 if(startRow <= endRow){
18925 for(var i = startRow; i <= endRow; i++){
18926 this.selectRow(i, true);
18929 for(var i = startRow; i >= endRow; i--){
18930 this.selectRow(i, true);
18936 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18937 * @param {Number} startRow The index of the first row in the range
18938 * @param {Number} endRow The index of the last row in the range
18940 deselectRange : function(startRow, endRow, preventViewNotify){
18941 if(this.locked) return;
18942 for(var i = startRow; i <= endRow; i++){
18943 this.deselectRow(i, preventViewNotify);
18949 * @param {Number} row The index of the row to select
18950 * @param {Boolean} keepExisting (optional) True to keep existing selections
18952 selectRow : function(index, keepExisting, preventViewNotify){
18953 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18954 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18955 if(!keepExisting || this.singleSelect){
18956 this.clearSelections();
18958 var r = this.grid.dataSource.getAt(index);
18959 this.selections.add(r);
18960 this.last = this.lastActive = index;
18961 if(!preventViewNotify){
18962 this.grid.getView().onRowSelect(index);
18964 this.fireEvent("rowselect", this, index, r);
18965 this.fireEvent("selectionchange", this);
18971 * @param {Number} row The index of the row to deselect
18973 deselectRow : function(index, preventViewNotify){
18974 if(this.locked) return;
18975 if(this.last == index){
18978 if(this.lastActive == index){
18979 this.lastActive = false;
18981 var r = this.grid.dataSource.getAt(index);
18982 this.selections.remove(r);
18983 if(!preventViewNotify){
18984 this.grid.getView().onRowDeselect(index);
18986 this.fireEvent("rowdeselect", this, index);
18987 this.fireEvent("selectionchange", this);
18991 restoreLast : function(){
18993 this.last = this._last;
18998 acceptsNav : function(row, col, cm){
18999 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19003 onEditorKey : function(field, e){
19004 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19009 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19011 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19013 }else if(k == e.ENTER && !e.ctrlKey){
19017 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19019 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19021 }else if(k == e.ESC){
19025 g.startEditing(newCell[0], newCell[1]);
19030 * Ext JS Library 1.1.1
19031 * Copyright(c) 2006-2007, Ext JS, LLC.
19033 * Originally Released Under LGPL - original licence link has changed is not relivant.
19036 * <script type="text/javascript">
19040 * @class Roo.bootstrap.PagingToolbar
19042 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19044 * Create a new PagingToolbar
19045 * @param {Object} config The config object
19047 Roo.bootstrap.PagingToolbar = function(config)
19049 // old args format still supported... - xtype is prefered..
19050 // created from xtype...
19051 var ds = config.dataSource;
19052 this.toolbarItems = [];
19053 if (config.items) {
19054 this.toolbarItems = config.items;
19055 // config.items = [];
19058 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19065 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19069 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19071 * @cfg {Roo.data.Store} dataSource
19072 * The underlying data store providing the paged data
19075 * @cfg {String/HTMLElement/Element} container
19076 * container The id or element that will contain the toolbar
19079 * @cfg {Boolean} displayInfo
19080 * True to display the displayMsg (defaults to false)
19083 * @cfg {Number} pageSize
19084 * The number of records to display per page (defaults to 20)
19088 * @cfg {String} displayMsg
19089 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19091 displayMsg : 'Displaying {0} - {1} of {2}',
19093 * @cfg {String} emptyMsg
19094 * The message to display when no records are found (defaults to "No data to display")
19096 emptyMsg : 'No data to display',
19098 * Customizable piece of the default paging text (defaults to "Page")
19101 beforePageText : "Page",
19103 * Customizable piece of the default paging text (defaults to "of %0")
19106 afterPageText : "of {0}",
19108 * Customizable piece of the default paging text (defaults to "First Page")
19111 firstText : "First Page",
19113 * Customizable piece of the default paging text (defaults to "Previous Page")
19116 prevText : "Previous Page",
19118 * Customizable piece of the default paging text (defaults to "Next Page")
19121 nextText : "Next Page",
19123 * Customizable piece of the default paging text (defaults to "Last Page")
19126 lastText : "Last Page",
19128 * Customizable piece of the default paging text (defaults to "Refresh")
19131 refreshText : "Refresh",
19135 onRender : function(ct, position)
19137 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19138 this.navgroup.parentId = this.id;
19139 this.navgroup.onRender(this.el, null);
19140 // add the buttons to the navgroup
19142 if(this.displayInfo){
19143 Roo.log(this.el.select('ul.navbar-nav',true).first());
19144 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19145 this.displayEl = this.el.select('.x-paging-info', true).first();
19146 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19147 // this.displayEl = navel.el.select('span',true).first();
19153 Roo.each(_this.buttons, function(e){
19154 Roo.factory(e).onRender(_this.el, null);
19158 Roo.each(_this.toolbarItems, function(e) {
19159 _this.navgroup.addItem(e);
19162 this.first = this.navgroup.addItem({
19163 tooltip: this.firstText,
19165 icon : 'fa fa-backward',
19167 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19170 this.prev = this.navgroup.addItem({
19171 tooltip: this.prevText,
19173 icon : 'fa fa-step-backward',
19175 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19177 //this.addSeparator();
19180 var field = this.navgroup.addItem( {
19182 cls : 'x-paging-position',
19184 html : this.beforePageText +
19185 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19186 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19189 this.field = field.el.select('input', true).first();
19190 this.field.on("keydown", this.onPagingKeydown, this);
19191 this.field.on("focus", function(){this.dom.select();});
19194 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19195 //this.field.setHeight(18);
19196 //this.addSeparator();
19197 this.next = this.navgroup.addItem({
19198 tooltip: this.nextText,
19200 html : ' <i class="fa fa-step-forward">',
19202 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19204 this.last = this.navgroup.addItem({
19205 tooltip: this.lastText,
19206 icon : 'fa fa-forward',
19209 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19211 //this.addSeparator();
19212 this.loading = this.navgroup.addItem({
19213 tooltip: this.refreshText,
19214 icon: 'fa fa-refresh',
19216 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19222 updateInfo : function(){
19223 if(this.displayEl){
19224 var count = this.ds.getCount();
19225 var msg = count == 0 ?
19229 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19231 this.displayEl.update(msg);
19236 onLoad : function(ds, r, o){
19237 this.cursor = o.params ? o.params.start : 0;
19238 var d = this.getPageData(),
19242 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19243 this.field.dom.value = ap;
19244 this.first.setDisabled(ap == 1);
19245 this.prev.setDisabled(ap == 1);
19246 this.next.setDisabled(ap == ps);
19247 this.last.setDisabled(ap == ps);
19248 this.loading.enable();
19253 getPageData : function(){
19254 var total = this.ds.getTotalCount();
19257 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19258 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19263 onLoadError : function(){
19264 this.loading.enable();
19268 onPagingKeydown : function(e){
19269 var k = e.getKey();
19270 var d = this.getPageData();
19272 var v = this.field.dom.value, pageNum;
19273 if(!v || isNaN(pageNum = parseInt(v, 10))){
19274 this.field.dom.value = d.activePage;
19277 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19278 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19281 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))
19283 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19284 this.field.dom.value = pageNum;
19285 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19288 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19290 var v = this.field.dom.value, pageNum;
19291 var increment = (e.shiftKey) ? 10 : 1;
19292 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19294 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19295 this.field.dom.value = d.activePage;
19298 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19300 this.field.dom.value = parseInt(v, 10) + increment;
19301 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19302 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19309 beforeLoad : function(){
19311 this.loading.disable();
19316 onClick : function(which){
19323 ds.load({params:{start: 0, limit: this.pageSize}});
19326 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19329 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19332 var total = ds.getTotalCount();
19333 var extra = total % this.pageSize;
19334 var lastStart = extra ? (total - extra) : total-this.pageSize;
19335 ds.load({params:{start: lastStart, limit: this.pageSize}});
19338 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19344 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19345 * @param {Roo.data.Store} store The data store to unbind
19347 unbind : function(ds){
19348 ds.un("beforeload", this.beforeLoad, this);
19349 ds.un("load", this.onLoad, this);
19350 ds.un("loadexception", this.onLoadError, this);
19351 ds.un("remove", this.updateInfo, this);
19352 ds.un("add", this.updateInfo, this);
19353 this.ds = undefined;
19357 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19358 * @param {Roo.data.Store} store The data store to bind
19360 bind : function(ds){
19361 ds.on("beforeload", this.beforeLoad, this);
19362 ds.on("load", this.onLoad, this);
19363 ds.on("loadexception", this.onLoadError, this);
19364 ds.on("remove", this.updateInfo, this);
19365 ds.on("add", this.updateInfo, this);
19376 * @class Roo.bootstrap.MessageBar
19377 * @extends Roo.bootstrap.Component
19378 * Bootstrap MessageBar class
19379 * @cfg {String} html contents of the MessageBar
19380 * @cfg {String} weight (info | success | warning | danger) default info
19381 * @cfg {String} beforeClass insert the bar before the given class
19382 * @cfg {Boolean} closable (true | false) default false
19383 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19386 * Create a new Element
19387 * @param {Object} config The config object
19390 Roo.bootstrap.MessageBar = function(config){
19391 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19394 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19400 beforeClass: 'bootstrap-sticky-wrap',
19402 getAutoCreate : function(){
19406 cls: 'alert alert-dismissable alert-' + this.weight,
19411 html: this.html || ''
19417 cfg.cls += ' alert-messages-fixed';
19431 onRender : function(ct, position)
19433 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19436 var cfg = Roo.apply({}, this.getAutoCreate());
19440 cfg.cls += ' ' + this.cls;
19443 cfg.style = this.style;
19445 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19447 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19450 this.el.select('>button.close').on('click', this.hide, this);
19456 if (!this.rendered) {
19462 this.fireEvent('show', this);
19468 if (!this.rendered) {
19474 this.fireEvent('hide', this);
19477 update : function()
19479 // var e = this.el.dom.firstChild;
19481 // if(this.closable){
19482 // e = e.nextSibling;
19485 // e.data = this.html || '';
19487 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19503 * @class Roo.bootstrap.Graph
19504 * @extends Roo.bootstrap.Component
19505 * Bootstrap Graph class
19509 @cfg {String} graphtype bar | vbar | pie
19510 @cfg {number} g_x coodinator | centre x (pie)
19511 @cfg {number} g_y coodinator | centre y (pie)
19512 @cfg {number} g_r radius (pie)
19513 @cfg {number} g_height height of the chart (respected by all elements in the set)
19514 @cfg {number} g_width width of the chart (respected by all elements in the set)
19515 @cfg {Object} title The title of the chart
19518 -opts (object) options for the chart
19520 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19521 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19523 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.
19524 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19526 o stretch (boolean)
19528 -opts (object) options for the pie
19531 o startAngle (number)
19532 o endAngle (number)
19536 * Create a new Input
19537 * @param {Object} config The config object
19540 Roo.bootstrap.Graph = function(config){
19541 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19547 * The img click event for the img.
19548 * @param {Roo.EventObject} e
19554 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19565 //g_colors: this.colors,
19572 getAutoCreate : function(){
19583 onRender : function(ct,position){
19584 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19585 this.raphael = Raphael(this.el.dom);
19587 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19588 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19589 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19590 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19592 r.text(160, 10, "Single Series Chart").attr(txtattr);
19593 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19594 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19595 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19597 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19598 r.barchart(330, 10, 300, 220, data1);
19599 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19600 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19603 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19604 // r.barchart(30, 30, 560, 250, xdata, {
19605 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19606 // axis : "0 0 1 1",
19607 // axisxlabels : xdata
19608 // //yvalues : cols,
19611 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19613 // this.load(null,xdata,{
19614 // axis : "0 0 1 1",
19615 // axisxlabels : xdata
19620 load : function(graphtype,xdata,opts){
19621 this.raphael.clear();
19623 graphtype = this.graphtype;
19628 var r = this.raphael,
19629 fin = function () {
19630 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19632 fout = function () {
19633 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19635 pfin = function() {
19636 this.sector.stop();
19637 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19640 this.label[0].stop();
19641 this.label[0].attr({ r: 7.5 });
19642 this.label[1].attr({ "font-weight": 800 });
19645 pfout = function() {
19646 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19649 this.label[0].animate({ r: 5 }, 500, "bounce");
19650 this.label[1].attr({ "font-weight": 400 });
19656 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19659 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19662 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19663 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19665 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19672 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19677 setTitle: function(o)
19682 initEvents: function() {
19685 this.el.on('click', this.onClick, this);
19689 onClick : function(e)
19691 Roo.log('img onclick');
19692 this.fireEvent('click', this, e);
19704 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19707 * @class Roo.bootstrap.dash.NumberBox
19708 * @extends Roo.bootstrap.Component
19709 * Bootstrap NumberBox class
19710 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19711 * @cfg {String} headline Box headline
19712 * @cfg {String} content Box content
19713 * @cfg {String} icon Box icon
19714 * @cfg {String} footer Footer text
19715 * @cfg {String} fhref Footer href
19718 * Create a new NumberBox
19719 * @param {Object} config The config object
19723 Roo.bootstrap.dash.NumberBox = function(config){
19724 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19728 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19738 getAutoCreate : function(){
19742 cls : 'small-box bg-' + this.bgcolor,
19750 cls : 'roo-headline',
19751 html : this.headline
19755 cls : 'roo-content',
19756 html : this.content
19770 cls : 'ion ' + this.icon
19779 cls : 'small-box-footer',
19780 href : this.fhref || '#',
19784 cfg.cn.push(footer);
19791 onRender : function(ct,position){
19792 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19799 setHeadline: function (value)
19801 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19804 setFooter: function (value, href)
19806 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19809 this.el.select('a.small-box-footer',true).first().attr('href', href);
19814 setContent: function (value)
19816 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19819 initEvents: function()
19833 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19836 * @class Roo.bootstrap.dash.TabBox
19837 * @extends Roo.bootstrap.Component
19838 * Bootstrap TabBox class
19839 * @cfg {String} title Title of the TabBox
19840 * @cfg {String} icon Icon of the TabBox
19841 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19844 * Create a new TabBox
19845 * @param {Object} config The config object
19849 Roo.bootstrap.dash.TabBox = function(config){
19850 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19855 * When a pane is added
19856 * @param {Roo.bootstrap.dash.TabPane} pane
19863 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19869 getChildContainer : function()
19871 return this.el.select('.tab-content', true).first();
19874 getAutoCreate : function(){
19878 cls: 'pull-left header',
19886 cls: 'fa ' + this.icon
19893 cls: 'nav-tabs-custom',
19897 cls: 'nav nav-tabs pull-right',
19904 cls: 'tab-content no-padding',
19912 initEvents : function()
19914 //Roo.log('add add pane handler');
19915 this.on('addpane', this.onAddPane, this);
19918 * Updates the box title
19919 * @param {String} html to set the title to.
19921 setTitle : function(value)
19923 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19925 onAddPane : function(pane)
19927 //Roo.log('addpane');
19929 // tabs are rendere left to right..
19930 if(!this.showtabs){
19934 var ctr = this.el.select('.nav-tabs', true).first();
19937 var existing = ctr.select('.nav-tab',true);
19938 var qty = existing.getCount();;
19941 var tab = ctr.createChild({
19943 cls : 'nav-tab' + (qty ? '' : ' active'),
19951 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19954 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19956 pane.el.addClass('active');
19961 onTabClick : function(ev,un,ob,pane)
19963 //Roo.log('tab - prev default');
19964 ev.preventDefault();
19967 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19968 pane.tab.addClass('active');
19969 //Roo.log(pane.title);
19970 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19971 // technically we should have a deactivate event.. but maybe add later.
19972 // and it should not de-activate the selected tab...
19974 pane.el.addClass('active');
19975 pane.fireEvent('activate');
19990 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19992 * @class Roo.bootstrap.TabPane
19993 * @extends Roo.bootstrap.Component
19994 * Bootstrap TabPane class
19995 * @cfg {Boolean} active (false | true) Default false
19996 * @cfg {String} title title of panel
20000 * Create a new TabPane
20001 * @param {Object} config The config object
20004 Roo.bootstrap.dash.TabPane = function(config){
20005 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20011 * When a pane is activated
20012 * @param {Roo.bootstrap.dash.TabPane} pane
20019 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20024 // the tabBox that this is attached to.
20027 getAutoCreate : function()
20035 cfg.cls += ' active';
20040 initEvents : function()
20042 //Roo.log('trigger add pane handler');
20043 this.parent().fireEvent('addpane', this)
20047 * Updates the tab title
20048 * @param {String} html to set the title to.
20050 setTitle: function(str)
20056 this.tab.select('a', true).first().dom.innerHTML = str;
20073 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20076 * @class Roo.bootstrap.menu.Menu
20077 * @extends Roo.bootstrap.Component
20078 * Bootstrap Menu class - container for Menu
20079 * @cfg {String} html Text of the menu
20080 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20081 * @cfg {String} icon Font awesome icon
20082 * @cfg {String} pos Menu align to (top | bottom) default bottom
20086 * Create a new Menu
20087 * @param {Object} config The config object
20091 Roo.bootstrap.menu.Menu = function(config){
20092 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20096 * @event beforeshow
20097 * Fires before this menu is displayed
20098 * @param {Roo.bootstrap.menu.Menu} this
20102 * @event beforehide
20103 * Fires before this menu is hidden
20104 * @param {Roo.bootstrap.menu.Menu} this
20109 * Fires after this menu is displayed
20110 * @param {Roo.bootstrap.menu.Menu} this
20115 * Fires after this menu is hidden
20116 * @param {Roo.bootstrap.menu.Menu} this
20121 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20122 * @param {Roo.bootstrap.menu.Menu} this
20123 * @param {Roo.EventObject} e
20130 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20134 weight : 'default',
20139 getChildContainer : function() {
20140 if(this.isSubMenu){
20144 return this.el.select('ul.dropdown-menu', true).first();
20147 getAutoCreate : function()
20152 cls : 'roo-menu-text',
20160 cls : 'fa ' + this.icon
20171 cls : 'dropdown-button btn btn-' + this.weight,
20176 cls : 'dropdown-toggle btn btn-' + this.weight,
20186 cls : 'dropdown-menu'
20192 if(this.pos == 'top'){
20193 cfg.cls += ' dropup';
20196 if(this.isSubMenu){
20199 cls : 'dropdown-menu'
20206 onRender : function(ct, position)
20208 this.isSubMenu = ct.hasClass('dropdown-submenu');
20210 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20213 initEvents : function()
20215 if(this.isSubMenu){
20219 this.hidden = true;
20221 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20222 this.triggerEl.on('click', this.onTriggerPress, this);
20224 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20225 this.buttonEl.on('click', this.onClick, this);
20231 if(this.isSubMenu){
20235 return this.el.select('ul.dropdown-menu', true).first();
20238 onClick : function(e)
20240 this.fireEvent("click", this, e);
20243 onTriggerPress : function(e)
20245 if (this.isVisible()) {
20252 isVisible : function(){
20253 return !this.hidden;
20258 this.fireEvent("beforeshow", this);
20260 this.hidden = false;
20261 this.el.addClass('open');
20263 Roo.get(document).on("mouseup", this.onMouseUp, this);
20265 this.fireEvent("show", this);
20272 this.fireEvent("beforehide", this);
20274 this.hidden = true;
20275 this.el.removeClass('open');
20277 Roo.get(document).un("mouseup", this.onMouseUp);
20279 this.fireEvent("hide", this);
20282 onMouseUp : function()
20296 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20299 * @class Roo.bootstrap.menu.Item
20300 * @extends Roo.bootstrap.Component
20301 * Bootstrap MenuItem class
20302 * @cfg {Boolean} submenu (true | false) default false
20303 * @cfg {String} html text of the item
20304 * @cfg {String} href the link
20305 * @cfg {Boolean} disable (true | false) default false
20306 * @cfg {Boolean} preventDefault (true | false) default true
20307 * @cfg {String} icon Font awesome icon
20308 * @cfg {String} pos Submenu align to (left | right) default right
20312 * Create a new Item
20313 * @param {Object} config The config object
20317 Roo.bootstrap.menu.Item = function(config){
20318 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20322 * Fires when the mouse is hovering over this menu
20323 * @param {Roo.bootstrap.menu.Item} this
20324 * @param {Roo.EventObject} e
20329 * Fires when the mouse exits this menu
20330 * @param {Roo.bootstrap.menu.Item} this
20331 * @param {Roo.EventObject} e
20337 * The raw click event for the entire grid.
20338 * @param {Roo.EventObject} e
20344 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20349 preventDefault: true,
20354 getAutoCreate : function()
20359 cls : 'roo-menu-item-text',
20367 cls : 'fa ' + this.icon
20376 href : this.href || '#',
20383 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20387 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20389 if(this.pos == 'left'){
20390 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20397 initEvents : function()
20399 this.el.on('mouseover', this.onMouseOver, this);
20400 this.el.on('mouseout', this.onMouseOut, this);
20402 this.el.select('a', true).first().on('click', this.onClick, this);
20406 onClick : function(e)
20408 if(this.preventDefault){
20409 e.preventDefault();
20412 this.fireEvent("click", this, e);
20415 onMouseOver : function(e)
20417 if(this.submenu && this.pos == 'left'){
20418 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20421 this.fireEvent("mouseover", this, e);
20424 onMouseOut : function(e)
20426 this.fireEvent("mouseout", this, e);
20438 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20441 * @class Roo.bootstrap.menu.Separator
20442 * @extends Roo.bootstrap.Component
20443 * Bootstrap Separator class
20446 * Create a new Separator
20447 * @param {Object} config The config object
20451 Roo.bootstrap.menu.Separator = function(config){
20452 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20455 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20457 getAutoCreate : function(){