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
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
104 cfg.id = this.id || Roo.id();
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
129 this.el = ct.createChild(cfg, position);
132 this.tooltipEl().attr('tooltip', this.tooltip);
135 if(this.tabIndex !== undefined){
136 this.el.dom.setAttribute('tabIndex', this.tabIndex);
143 * Fetch the element to add children to
144 * @return {Roo.Element} defaults to this.el
146 getChildContainer : function()
151 * Fetch the element to display the tooltip on.
152 * @return {Roo.Element} defaults to this.el
154 tooltipEl : function()
159 addxtype : function(tree,cntr)
163 cn = Roo.factory(tree);
165 cn.parentType = this.xtype; //??
166 cn.parentId = this.id;
168 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
169 if (typeof(cn.container_method) == 'string') {
170 cntr = cn.container_method;
174 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
176 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
178 var build_from_html = Roo.XComponent.build_from_html;
180 var is_body = (tree.xtype == 'Body') ;
182 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
184 var self_cntr_el = Roo.get(this[cntr](false));
186 // do not try and build conditional elements
187 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
192 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
193 return this.addxtypeChild(tree,cntr);
196 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202 Roo.log('skipping render');
208 if (!build_from_html) {
212 // this i think handles overlaying multiple children of the same type
213 // with the sam eelement.. - which might be buggy..
215 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
221 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
230 addxtypeChild : function (tree, cntr)
232 Roo.debug && Roo.log('addxtypeChild:' + cntr);
234 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
238 (typeof(tree['flexy:foreach']) != 'undefined');
242 skip_children = false;
243 // render the element if it's not BODY.
244 if (tree.xtype != 'Body') {
246 cn = Roo.factory(tree);
248 cn.parentType = this.xtype; //??
249 cn.parentId = this.id;
251 var build_from_html = Roo.XComponent.build_from_html;
254 // does the container contain child eleemnts with 'xtype' attributes.
255 // that match this xtype..
256 // note - when we render we create these as well..
257 // so we should check to see if body has xtype set.
258 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
260 var self_cntr_el = Roo.get(this[cntr](false));
261 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
263 //Roo.log(Roo.XComponent.build_from_html);
264 //Roo.log("got echild:");
267 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
268 // and are not displayed -this causes this to use up the wrong element when matching.
269 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
273 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
279 //echild.dom.removeAttribute('xtype');
281 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
282 Roo.debug && Roo.log(self_cntr_el);
283 Roo.debug && Roo.log(echild);
284 Roo.debug && Roo.log(cn);
290 // if object has flexy:if - then it may or may not be rendered.
291 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
292 // skip a flexy if element.
293 Roo.debug && Roo.log('skipping render');
294 Roo.debug && Roo.log(tree);
296 Roo.debug && Roo.log('skipping all children');
297 skip_children = true;
302 // actually if flexy:foreach is found, we really want to create
303 // multiple copies here...
305 //Roo.log(this[cntr]());
306 cn.render(this[cntr](true));
308 // then add the element..
316 if (typeof (tree.menu) != 'undefined') {
317 tree.menu.parentType = cn.xtype;
318 tree.menu.triggerEl = cn.el;
319 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
323 if (!tree.items || !tree.items.length) {
327 var items = tree.items;
330 //Roo.log(items.length);
332 if (!skip_children) {
333 for(var i =0;i < items.length;i++) {
334 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
340 this.fireEvent('childrenrendered', this);
345 * Show a component - removes 'hidden' class
350 this.el.removeClass('hidden');
354 * Hide a component - adds 'hidden' class
358 if (this.el && !this.el.hasClass('hidden')) {
359 this.el.addClass('hidden');
373 * @class Roo.bootstrap.Body
374 * @extends Roo.bootstrap.Component
375 * Bootstrap Body class
379 * @param {Object} config The config object
382 Roo.bootstrap.Body = function(config){
383 Roo.bootstrap.Body.superclass.constructor.call(this, config);
384 this.el = Roo.get(document.body);
385 if (this.cls && this.cls.length) {
386 Roo.get(document.body).addClass(this.cls);
390 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
395 onRender : function(ct, position)
397 /* Roo.log("Roo.bootstrap.Body - onRender");
398 if (this.cls && this.cls.length) {
399 Roo.get(document.body).addClass(this.cls);
419 * @class Roo.bootstrap.ButtonGroup
420 * @extends Roo.bootstrap.Component
421 * Bootstrap ButtonGroup class
422 * @cfg {String} size lg | sm | xs (default empty normal)
423 * @cfg {String} align vertical | justified (default none)
424 * @cfg {String} direction up | down (default down)
425 * @cfg {Boolean} toolbar false | true
426 * @cfg {Boolean} btn true | false
431 * @param {Object} config The config object
434 Roo.bootstrap.ButtonGroup = function(config){
435 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
438 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
446 getAutoCreate : function(){
452 cfg.html = this.html || cfg.html;
463 if (['vertical','justified'].indexOf(this.align)!==-1) {
464 cfg.cls = 'btn-group-' + this.align;
466 if (this.align == 'justified') {
467 console.log(this.items);
471 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
472 cfg.cls += ' btn-group-' + this.size;
475 if (this.direction == 'up') {
476 cfg.cls += ' dropup' ;
492 * @class Roo.bootstrap.Button
493 * @extends Roo.bootstrap.Component
494 * Bootstrap Button class
495 * @cfg {String} html The button content
496 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
497 * @cfg {String} size ( lg | sm | xs)
498 * @cfg {String} tag ( a | input | submit)
499 * @cfg {String} href empty or href
500 * @cfg {Boolean} disabled default false;
501 * @cfg {Boolean} isClose default false;
502 * @cfg {String} glyphicon (| 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)
503 * @cfg {String} badge text for badge
504 * @cfg {String} theme default
505 * @cfg {Boolean} inverse
506 * @cfg {Boolean} toggle
507 * @cfg {String} ontext text for on toggle state
508 * @cfg {String} offtext text for off toggle state
509 * @cfg {Boolean} defaulton
510 * @cfg {Boolean} preventDefault default true
511 * @cfg {Boolean} removeClass remove the standard class..
512 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
515 * Create a new button
516 * @param {Object} config The config object
520 Roo.bootstrap.Button = function(config){
521 Roo.bootstrap.Button.superclass.constructor.call(this, config);
526 * When a butotn is pressed
527 * @param {Roo.bootstrap.Button} this
528 * @param {Roo.EventObject} e
533 * After the button has been toggles
534 * @param {Roo.EventObject} e
535 * @param {boolean} pressed (also available as button.pressed)
541 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
559 preventDefault: true,
568 getAutoCreate : function(){
576 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
577 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
582 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
584 if (this.toggle == true) {
587 cls: 'slider-frame roo-button',
592 'data-off-text':'OFF',
593 cls: 'slider-button',
599 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
600 cfg.cls += ' '+this.weight;
609 cfg["aria-hidden"] = true;
611 cfg.html = "×";
617 if (this.theme==='default') {
618 cfg.cls = 'btn roo-button';
620 //if (this.parentType != 'Navbar') {
621 this.weight = this.weight.length ? this.weight : 'default';
623 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
625 cfg.cls += ' btn-' + this.weight;
627 } else if (this.theme==='glow') {
630 cfg.cls = 'btn-glow roo-button';
632 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
634 cfg.cls += ' ' + this.weight;
640 this.cls += ' inverse';
645 cfg.cls += ' active';
649 cfg.disabled = 'disabled';
653 Roo.log('changing to ul' );
655 this.glyphicon = 'caret';
658 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
660 //gsRoo.log(this.parentType);
661 if (this.parentType === 'Navbar' && !this.parent().bar) {
662 Roo.log('changing to li?');
671 href : this.href || '#'
674 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
675 cfg.cls += ' dropdown';
682 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
684 if (this.glyphicon) {
685 cfg.html = ' ' + cfg.html;
690 cls: 'glyphicon glyphicon-' + this.glyphicon
700 // cfg.cls='btn roo-button';
704 var value = cfg.html;
709 cls: 'glyphicon glyphicon-' + this.glyphicon,
728 cfg.cls += ' dropdown';
729 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
732 if (cfg.tag !== 'a' && this.href !== '') {
733 throw "Tag must be a to set href.";
734 } else if (this.href.length > 0) {
735 cfg.href = this.href;
738 if(this.removeClass){
743 cfg.target = this.target;
748 initEvents: function() {
749 // Roo.log('init events?');
750 // Roo.log(this.el.dom);
753 if (typeof (this.menu) != 'undefined') {
754 this.menu.parentType = this.xtype;
755 this.menu.triggerEl = this.el;
756 this.addxtype(Roo.apply({}, this.menu));
760 if (this.el.hasClass('roo-button')) {
761 this.el.on('click', this.onClick, this);
763 this.el.select('.roo-button').on('click', this.onClick, this);
766 if(this.removeClass){
767 this.el.on('click', this.onClick, this);
770 this.el.enableDisplayMode();
773 onClick : function(e)
780 Roo.log('button on click ');
781 if(this.preventDefault){
784 if (this.pressed === true || this.pressed === false) {
785 this.pressed = !this.pressed;
786 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
787 this.fireEvent('toggle', this, e, this.pressed);
791 this.fireEvent('click', this, e);
795 * Enables this button
799 this.disabled = false;
800 this.el.removeClass('disabled');
804 * Disable this button
808 this.disabled = true;
809 this.el.addClass('disabled');
812 * sets the active state on/off,
813 * @param {Boolean} state (optional) Force a particular state
815 setActive : function(v) {
817 this.el[v ? 'addClass' : 'removeClass']('active');
820 * toggles the current active state
822 toggleActive : function()
824 var active = this.el.hasClass('active');
825 this.setActive(!active);
829 setText : function(str)
831 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
835 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
858 * @class Roo.bootstrap.Column
859 * @extends Roo.bootstrap.Component
860 * Bootstrap Column class
861 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
862 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
863 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
864 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
865 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
866 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
867 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
868 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
871 * @cfg {Boolean} hidden (true|false) hide the element
872 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
873 * @cfg {String} fa (ban|check|...) font awesome icon
874 * @cfg {Number} fasize (1|2|....) font awsome size
876 * @cfg {String} icon (info-sign|check|...) glyphicon name
878 * @cfg {String} html content of column.
881 * Create a new Column
882 * @param {Object} config The config object
885 Roo.bootstrap.Column = function(config){
886 Roo.bootstrap.Column.superclass.constructor.call(this, config);
889 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
907 getAutoCreate : function(){
908 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
916 ['xs','sm','md','lg'].map(function(size){
917 //Roo.log( size + ':' + settings[size]);
919 if (settings[size+'off'] !== false) {
920 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
923 if (settings[size] === false) {
926 Roo.log(settings[size]);
927 if (!settings[size]) { // 0 = hidden
928 cfg.cls += ' hidden-' + size;
931 cfg.cls += ' col-' + size + '-' + settings[size];
936 cfg.cls += ' hidden';
939 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
940 cfg.cls +=' alert alert-' + this.alert;
944 if (this.html.length) {
945 cfg.html = this.html;
949 if (this.fasize > 1) {
950 fasize = ' fa-' + this.fasize + 'x';
952 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
957 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
976 * @class Roo.bootstrap.Container
977 * @extends Roo.bootstrap.Component
978 * Bootstrap Container class
979 * @cfg {Boolean} jumbotron is it a jumbotron element
980 * @cfg {String} html content of element
981 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
982 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
983 * @cfg {String} header content of header (for panel)
984 * @cfg {String} footer content of footer (for panel)
985 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
986 * @cfg {String} tag (header|aside|section) type of HTML tag.
987 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
988 * @cfg {String} fa (ban|check|...) font awesome icon
989 * @cfg {String} icon (info-sign|check|...) glyphicon name
990 * @cfg {Boolean} hidden (true|false) hide the element
991 * @cfg {Boolean} expandable (true|false) default false
992 * @cfg {String} rheader contet on the right of header
996 * Create a new Container
997 * @param {Object} config The config object
1000 Roo.bootstrap.Container = function(config){
1001 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1007 * After the panel has been expand
1009 * @param {Roo.bootstrap.Container} this
1014 * After the panel has been collapsed
1016 * @param {Roo.bootstrap.Container} this
1022 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1039 getChildContainer : function() {
1045 if (this.panel.length) {
1046 return this.el.select('.panel-body',true).first();
1053 getAutoCreate : function(){
1056 tag : this.tag || 'div',
1060 if (this.jumbotron) {
1061 cfg.cls = 'jumbotron';
1066 // - this is applied by the parent..
1068 // cfg.cls = this.cls + '';
1071 if (this.sticky.length) {
1073 var bd = Roo.get(document.body);
1074 if (!bd.hasClass('bootstrap-sticky')) {
1075 bd.addClass('bootstrap-sticky');
1076 Roo.select('html',true).setStyle('height', '100%');
1079 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1083 if (this.well.length) {
1084 switch (this.well) {
1087 cfg.cls +=' well well-' +this.well;
1096 cfg.cls += ' hidden';
1100 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1101 cfg.cls +=' alert alert-' + this.alert;
1106 if (this.panel.length) {
1107 cfg.cls += ' panel panel-' + this.panel;
1109 if (this.header.length) {
1113 if(this.expandable){
1115 cfg.cls = cfg.cls + ' expandable';
1126 cls : 'panel-title',
1131 cls: 'panel-header-right',
1137 cls : 'panel-heading',
1150 if (this.footer.length) {
1152 cls : 'panel-footer',
1161 body.html = this.html || cfg.html;
1162 // prefix with the icons..
1164 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1167 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1172 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1173 cfg.cls = 'container';
1179 initEvents: function()
1181 if(!this.expandable){
1185 var headerEl = this.headerEl();
1191 headerEl.on('click', this.onToggleClick, this);
1195 onToggleClick : function()
1197 var headerEl = this.headerEl();
1213 if(this.fireEvent('expand', this)) {
1215 this.expanded = true;
1217 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1219 var toggleEl = this.toggleEl();
1225 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1230 collapse : function()
1232 if(this.fireEvent('collapse', this)) {
1234 this.expanded = false;
1236 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1238 var toggleEl = this.toggleEl();
1244 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1248 toggleEl : function()
1250 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1254 return this.el.select('.panel-heading .fa',true).first();
1257 headerEl : function()
1259 if(!this.el || !this.panel.length || !this.header.length){
1263 return this.el.select('.panel-heading',true).first()
1266 titleEl : function()
1268 if(!this.el || !this.panel.length || !this.header.length){
1272 return this.el.select('.panel-title',true).first();
1275 setTitle : function(v)
1277 var titleEl = this.titleEl();
1283 titleEl.dom.innerHTML = v;
1286 getTitle : function()
1289 var titleEl = this.titleEl();
1295 return titleEl.dom.innerHTML;
1298 setRightTitle : function(v)
1300 var t = this.el.select('.panel-header-right',true).first();
1306 t.dom.innerHTML = v;
1320 * @class Roo.bootstrap.Img
1321 * @extends Roo.bootstrap.Component
1322 * Bootstrap Img class
1323 * @cfg {Boolean} imgResponsive false | true
1324 * @cfg {String} border rounded | circle | thumbnail
1325 * @cfg {String} src image source
1326 * @cfg {String} alt image alternative text
1327 * @cfg {String} href a tag href
1328 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1331 * Create a new Input
1332 * @param {Object} config The config object
1335 Roo.bootstrap.Img = function(config){
1336 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1342 * The img click event for the img.
1343 * @param {Roo.EventObject} e
1349 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1351 imgResponsive: true,
1357 getAutoCreate : function(){
1361 cls: (this.imgResponsive) ? 'img-responsive' : '',
1365 cfg.html = this.html || cfg.html;
1367 cfg.src = this.src || cfg.src;
1369 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1370 cfg.cls += ' img-' + this.border;
1387 a.target = this.target;
1393 return (this.href) ? a : cfg;
1396 initEvents: function() {
1399 this.el.on('click', this.onClick, this);
1403 onClick : function(e)
1405 Roo.log('img onclick');
1406 this.fireEvent('click', this, e);
1420 * @class Roo.bootstrap.Link
1421 * @extends Roo.bootstrap.Component
1422 * Bootstrap Link Class
1423 * @cfg {String} alt image alternative text
1424 * @cfg {String} href a tag href
1425 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1426 * @cfg {String} html the content of the link.
1427 * @cfg {String} anchor name for the anchor link
1429 * @cfg {Boolean} preventDefault (true | false) default false
1433 * Create a new Input
1434 * @param {Object} config The config object
1437 Roo.bootstrap.Link = function(config){
1438 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1444 * The img click event for the img.
1445 * @param {Roo.EventObject} e
1451 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1455 preventDefault: false,
1459 getAutoCreate : function()
1465 // anchor's do not require html/href...
1466 if (this.anchor === false) {
1467 cfg.html = this.html || 'html-missing';
1468 cfg.href = this.href || '#';
1470 cfg.name = this.anchor;
1471 if (this.html !== false) {
1472 cfg.html = this.html;
1474 if (this.href !== false) {
1475 cfg.href = this.href;
1479 if(this.alt !== false){
1484 if(this.target !== false) {
1485 cfg.target = this.target;
1491 initEvents: function() {
1493 if(!this.href || this.preventDefault){
1494 this.el.on('click', this.onClick, this);
1498 onClick : function(e)
1500 if(this.preventDefault){
1503 //Roo.log('img onclick');
1504 this.fireEvent('click', this, e);
1517 * @class Roo.bootstrap.Header
1518 * @extends Roo.bootstrap.Component
1519 * Bootstrap Header class
1520 * @cfg {String} html content of header
1521 * @cfg {Number} level (1|2|3|4|5|6) default 1
1524 * Create a new Header
1525 * @param {Object} config The config object
1529 Roo.bootstrap.Header = function(config){
1530 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1533 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1541 getAutoCreate : function(){
1546 tag: 'h' + (1 *this.level),
1547 html: this.html || ''
1559 * Ext JS Library 1.1.1
1560 * Copyright(c) 2006-2007, Ext JS, LLC.
1562 * Originally Released Under LGPL - original licence link has changed is not relivant.
1565 * <script type="text/javascript">
1569 * @class Roo.bootstrap.MenuMgr
1570 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1573 Roo.bootstrap.MenuMgr = function(){
1574 var menus, active, groups = {}, attached = false, lastShow = new Date();
1576 // private - called when first menu is created
1579 active = new Roo.util.MixedCollection();
1580 Roo.get(document).addKeyListener(27, function(){
1581 if(active.length > 0){
1589 if(active && active.length > 0){
1590 var c = active.clone();
1600 if(active.length < 1){
1601 Roo.get(document).un("mouseup", onMouseDown);
1609 var last = active.last();
1610 lastShow = new Date();
1613 Roo.get(document).on("mouseup", onMouseDown);
1618 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1619 m.parentMenu.activeChild = m;
1620 }else if(last && last.isVisible()){
1621 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1626 function onBeforeHide(m){
1628 m.activeChild.hide();
1630 if(m.autoHideTimer){
1631 clearTimeout(m.autoHideTimer);
1632 delete m.autoHideTimer;
1637 function onBeforeShow(m){
1638 var pm = m.parentMenu;
1639 if(!pm && !m.allowOtherMenus){
1641 }else if(pm && pm.activeChild && active != m){
1642 pm.activeChild.hide();
1646 // private this should really trigger on mouseup..
1647 function onMouseDown(e){
1648 Roo.log("on Mouse Up");
1649 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1659 function onBeforeCheck(mi, state){
1661 var g = groups[mi.group];
1662 for(var i = 0, l = g.length; i < l; i++){
1664 g[i].setChecked(false);
1673 * Hides all menus that are currently visible
1675 hideAll : function(){
1680 register : function(menu){
1684 menus[menu.id] = menu;
1685 menu.on("beforehide", onBeforeHide);
1686 menu.on("hide", onHide);
1687 menu.on("beforeshow", onBeforeShow);
1688 menu.on("show", onShow);
1690 if(g && menu.events["checkchange"]){
1694 groups[g].push(menu);
1695 menu.on("checkchange", onCheck);
1700 * Returns a {@link Roo.menu.Menu} object
1701 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1702 * be used to generate and return a new Menu instance.
1704 get : function(menu){
1705 if(typeof menu == "string"){ // menu id
1707 }else if(menu.events){ // menu instance
1710 /*else if(typeof menu.length == 'number'){ // array of menu items?
1711 return new Roo.bootstrap.Menu({items:menu});
1712 }else{ // otherwise, must be a config
1713 return new Roo.bootstrap.Menu(menu);
1720 unregister : function(menu){
1721 delete menus[menu.id];
1722 menu.un("beforehide", onBeforeHide);
1723 menu.un("hide", onHide);
1724 menu.un("beforeshow", onBeforeShow);
1725 menu.un("show", onShow);
1727 if(g && menu.events["checkchange"]){
1728 groups[g].remove(menu);
1729 menu.un("checkchange", onCheck);
1734 registerCheckable : function(menuItem){
1735 var g = menuItem.group;
1740 groups[g].push(menuItem);
1741 menuItem.on("beforecheckchange", onBeforeCheck);
1746 unregisterCheckable : function(menuItem){
1747 var g = menuItem.group;
1749 groups[g].remove(menuItem);
1750 menuItem.un("beforecheckchange", onBeforeCheck);
1762 * @class Roo.bootstrap.Menu
1763 * @extends Roo.bootstrap.Component
1764 * Bootstrap Menu class - container for MenuItems
1765 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1769 * @param {Object} config The config object
1773 Roo.bootstrap.Menu = function(config){
1774 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1775 if (this.registerMenu) {
1776 Roo.bootstrap.MenuMgr.register(this);
1781 * Fires before this menu is displayed
1782 * @param {Roo.menu.Menu} this
1787 * Fires before this menu is hidden
1788 * @param {Roo.menu.Menu} this
1793 * Fires after this menu is displayed
1794 * @param {Roo.menu.Menu} this
1799 * Fires after this menu is hidden
1800 * @param {Roo.menu.Menu} this
1805 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1806 * @param {Roo.menu.Menu} this
1807 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1808 * @param {Roo.EventObject} e
1813 * Fires when the mouse is hovering over this menu
1814 * @param {Roo.menu.Menu} this
1815 * @param {Roo.EventObject} e
1816 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1821 * Fires when the mouse exits this menu
1822 * @param {Roo.menu.Menu} this
1823 * @param {Roo.EventObject} e
1824 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1829 * Fires when a menu item contained in this menu is clicked
1830 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1831 * @param {Roo.EventObject} e
1835 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1838 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1842 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1845 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1847 registerMenu : true,
1849 menuItems :false, // stores the menu items..
1855 getChildContainer : function() {
1859 getAutoCreate : function(){
1861 //if (['right'].indexOf(this.align)!==-1) {
1862 // cfg.cn[1].cls += ' pull-right'
1868 cls : 'dropdown-menu' ,
1869 style : 'z-index:1000'
1873 if (this.type === 'submenu') {
1874 cfg.cls = 'submenu active';
1876 if (this.type === 'treeview') {
1877 cfg.cls = 'treeview-menu';
1882 initEvents : function() {
1884 // Roo.log("ADD event");
1885 // Roo.log(this.triggerEl.dom);
1886 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1888 this.triggerEl.addClass('dropdown-toggle');
1889 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1891 this.el.on("mouseover", this.onMouseOver, this);
1892 this.el.on("mouseout", this.onMouseOut, this);
1896 findTargetItem : function(e){
1897 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1901 //Roo.log(t); Roo.log(t.id);
1903 //Roo.log(this.menuitems);
1904 return this.menuitems.get(t.id);
1906 //return this.items.get(t.menuItemId);
1911 onClick : function(e){
1912 Roo.log("menu.onClick");
1913 var t = this.findTargetItem(e);
1914 if(!t || t.isContainer){
1919 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1920 if(t == this.activeItem && t.shouldDeactivate(e)){
1921 this.activeItem.deactivate();
1922 delete this.activeItem;
1926 this.setActiveItem(t, true);
1934 Roo.log('pass click event');
1938 this.fireEvent("click", this, t, e);
1942 onMouseOver : function(e){
1943 var t = this.findTargetItem(e);
1946 // if(t.canActivate && !t.disabled){
1947 // this.setActiveItem(t, true);
1951 this.fireEvent("mouseover", this, e, t);
1953 isVisible : function(){
1954 return !this.hidden;
1956 onMouseOut : function(e){
1957 var t = this.findTargetItem(e);
1960 // if(t == this.activeItem && t.shouldDeactivate(e)){
1961 // this.activeItem.deactivate();
1962 // delete this.activeItem;
1965 this.fireEvent("mouseout", this, e, t);
1970 * Displays this menu relative to another element
1971 * @param {String/HTMLElement/Roo.Element} element The element to align to
1972 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1973 * the element (defaults to this.defaultAlign)
1974 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1976 show : function(el, pos, parentMenu){
1977 this.parentMenu = parentMenu;
1981 this.fireEvent("beforeshow", this);
1982 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1985 * Displays this menu at a specific xy position
1986 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1987 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1989 showAt : function(xy, parentMenu, /* private: */_e){
1990 this.parentMenu = parentMenu;
1995 this.fireEvent("beforeshow", this);
1996 //xy = this.el.adjustForConstraints(xy);
2000 this.hideMenuItems();
2001 this.hidden = false;
2002 this.triggerEl.addClass('open');
2004 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2005 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2010 this.fireEvent("show", this);
2016 this.doFocus.defer(50, this);
2020 doFocus : function(){
2022 this.focusEl.focus();
2027 * Hides this menu and optionally all parent menus
2028 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2030 hide : function(deep){
2032 this.hideMenuItems();
2033 if(this.el && this.isVisible()){
2034 this.fireEvent("beforehide", this);
2035 if(this.activeItem){
2036 this.activeItem.deactivate();
2037 this.activeItem = null;
2039 this.triggerEl.removeClass('open');;
2041 this.fireEvent("hide", this);
2043 if(deep === true && this.parentMenu){
2044 this.parentMenu.hide(true);
2048 onTriggerPress : function(e)
2051 Roo.log('trigger press');
2052 //Roo.log(e.getTarget());
2053 // Roo.log(this.triggerEl.dom);
2054 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2058 if (this.isVisible()) {
2063 this.show(this.triggerEl, false, false);
2072 hideMenuItems : function()
2074 //$(backdrop).remove()
2075 Roo.select('.open',true).each(function(aa) {
2077 aa.removeClass('open');
2078 //var parent = getParent($(this))
2079 //var relatedTarget = { relatedTarget: this }
2081 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2082 //if (e.isDefaultPrevented()) return
2083 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2086 addxtypeChild : function (tree, cntr) {
2087 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2089 this.menuitems.add(comp);
2110 * @class Roo.bootstrap.MenuItem
2111 * @extends Roo.bootstrap.Component
2112 * Bootstrap MenuItem class
2113 * @cfg {String} html the menu label
2114 * @cfg {String} href the link
2115 * @cfg {Boolean} preventDefault (true | false) default true
2116 * @cfg {Boolean} isContainer (true | false) default false
2120 * Create a new MenuItem
2121 * @param {Object} config The config object
2125 Roo.bootstrap.MenuItem = function(config){
2126 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2131 * The raw click event for the entire grid.
2132 * @param {Roo.bootstrap.MenuItem} this
2133 * @param {Roo.EventObject} e
2139 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2143 preventDefault: true,
2144 isContainer : false,
2146 getAutoCreate : function(){
2148 if(this.isContainer){
2151 cls: 'dropdown-menu-item'
2157 cls: 'dropdown-menu-item',
2166 if (this.parent().type == 'treeview') {
2167 cfg.cls = 'treeview-menu';
2170 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2171 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2175 initEvents: function() {
2177 //this.el.select('a').on('click', this.onClick, this);
2180 onClick : function(e)
2182 Roo.log('item on click ');
2183 //if(this.preventDefault){
2184 // e.preventDefault();
2186 //this.parent().hideMenuItems();
2188 this.fireEvent('click', this, e);
2207 * @class Roo.bootstrap.MenuSeparator
2208 * @extends Roo.bootstrap.Component
2209 * Bootstrap MenuSeparator class
2212 * Create a new MenuItem
2213 * @param {Object} config The config object
2217 Roo.bootstrap.MenuSeparator = function(config){
2218 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2221 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2223 getAutoCreate : function(){
2242 * @class Roo.bootstrap.Modal
2243 * @extends Roo.bootstrap.Component
2244 * Bootstrap Modal class
2245 * @cfg {String} title Title of dialog
2246 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2247 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2248 * @cfg {Boolean} specificTitle default false
2249 * @cfg {Array} buttons Array of buttons or standard button set..
2250 * @cfg {String} buttonPosition (left|right|center) default right
2251 * @cfg {Boolean} animate default true
2252 * @cfg {Boolean} allow_close default true
2255 * Create a new Modal Dialog
2256 * @param {Object} config The config object
2259 Roo.bootstrap.Modal = function(config){
2260 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2265 * The raw btnclick event for the button
2266 * @param {Roo.EventObject} e
2270 this.buttons = this.buttons || [];
2273 this.tmpl = Roo.factory(this.tmpl);
2278 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2280 title : 'test dialog',
2290 specificTitle: false,
2292 buttonPosition: 'right',
2306 onRender : function(ct, position)
2308 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2311 var cfg = Roo.apply({}, this.getAutoCreate());
2314 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2316 //if (!cfg.name.length) {
2320 cfg.cls += ' ' + this.cls;
2323 cfg.style = this.style;
2325 this.el = Roo.get(document.body).createChild(cfg, position);
2327 //var type = this.el.dom.type;
2332 if(this.tabIndex !== undefined){
2333 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2337 this.bodyEl = this.el.select('.modal-body',true).first();
2338 this.closeEl = this.el.select('.modal-header .close', true).first();
2339 this.footerEl = this.el.select('.modal-footer',true).first();
2340 this.titleEl = this.el.select('.modal-title',true).first();
2344 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2345 this.maskEl.enableDisplayMode("block");
2347 //this.el.addClass("x-dlg-modal");
2349 if (this.buttons.length) {
2350 Roo.each(this.buttons, function(bb) {
2351 b = Roo.apply({}, bb);
2352 b.xns = b.xns || Roo.bootstrap;
2353 b.xtype = b.xtype || 'Button';
2354 if (typeof(b.listeners) == 'undefined') {
2355 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2358 var btn = Roo.factory(b);
2360 btn.onRender(this.el.select('.modal-footer div').first());
2364 // render the children.
2367 if(typeof(this.items) != 'undefined'){
2368 var items = this.items;
2371 for(var i =0;i < items.length;i++) {
2372 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2376 this.items = nitems;
2378 // where are these used - they used to be body/close/footer
2382 //this.el.addClass([this.fieldClass, this.cls]);
2385 getAutoCreate : function(){
2390 html : this.html || ''
2395 cls : 'modal-title',
2399 if(this.specificTitle){
2405 if (this.allow_close) {
2416 style : 'display: none',
2419 cls: "modal-dialog",
2422 cls : "modal-content",
2425 cls : 'modal-header',
2430 cls : 'modal-footer',
2434 cls: 'btn-' + this.buttonPosition
2451 modal.cls += ' fade';
2457 getChildContainer : function() {
2462 getButtonContainer : function() {
2463 return this.el.select('.modal-footer div',true).first();
2466 initEvents : function()
2468 if (this.allow_close) {
2469 this.closeEl.on('click', this.hide, this);
2475 if (!this.rendered) {
2479 this.el.setStyle('display', 'block');
2483 (function(){ _this.el.addClass('in'); }).defer(50);
2485 this.el.addClass('in');
2488 // not sure how we can show data in here..
2490 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2493 Roo.get(document.body).addClass("x-body-masked");
2494 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2496 this.el.setStyle('zIndex', '10001');
2498 this.fireEvent('show', this);
2505 Roo.get(document.body).removeClass("x-body-masked");
2506 this.el.removeClass('in');
2510 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2512 this.el.setStyle('display', 'none');
2515 this.fireEvent('hide', this);
2518 addButton : function(str, cb)
2522 var b = Roo.apply({}, { html : str } );
2523 b.xns = b.xns || Roo.bootstrap;
2524 b.xtype = b.xtype || 'Button';
2525 if (typeof(b.listeners) == 'undefined') {
2526 b.listeners = { click : cb.createDelegate(this) };
2529 var btn = Roo.factory(b);
2531 btn.onRender(this.el.select('.modal-footer div').first());
2537 setDefaultButton : function(btn)
2539 //this.el.select('.modal-footer').()
2541 resizeTo: function(w,h)
2545 setContentSize : function(w, h)
2549 onButtonClick: function(btn,e)
2552 this.fireEvent('btnclick', btn.name, e);
2555 * Set the title of the Dialog
2556 * @param {String} str new Title
2558 setTitle: function(str) {
2559 this.titleEl.dom.innerHTML = str;
2562 * Set the body of the Dialog
2563 * @param {String} str new Title
2565 setBody: function(str) {
2566 this.bodyEl.dom.innerHTML = str;
2569 * Set the body of the Dialog using the template
2570 * @param {Obj} data - apply this data to the template and replace the body contents.
2572 applyBody: function(obj)
2575 Roo.log("Error - using apply Body without a template");
2578 this.tmpl.overwrite(this.bodyEl, obj);
2584 Roo.apply(Roo.bootstrap.Modal, {
2586 * Button config that displays a single OK button
2595 * Button config that displays Yes and No buttons
2611 * Button config that displays OK and Cancel buttons
2626 * Button config that displays Yes, No and Cancel buttons
2649 * messagebox - can be used as a replace
2653 * @class Roo.MessageBox
2654 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2658 Roo.Msg.alert('Status', 'Changes saved successfully.');
2660 // Prompt for user data:
2661 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2663 // process text value...
2667 // Show a dialog using config options:
2669 title:'Save Changes?',
2670 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2671 buttons: Roo.Msg.YESNOCANCEL,
2678 Roo.bootstrap.MessageBox = function(){
2679 var dlg, opt, mask, waitTimer;
2680 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2681 var buttons, activeTextEl, bwidth;
2685 var handleButton = function(button){
2687 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2691 var handleHide = function(){
2693 dlg.el.removeClass(opt.cls);
2696 // Roo.TaskMgr.stop(waitTimer);
2697 // waitTimer = null;
2702 var updateButtons = function(b){
2705 buttons["ok"].hide();
2706 buttons["cancel"].hide();
2707 buttons["yes"].hide();
2708 buttons["no"].hide();
2709 //dlg.footer.dom.style.display = 'none';
2712 dlg.footerEl.dom.style.display = '';
2713 for(var k in buttons){
2714 if(typeof buttons[k] != "function"){
2717 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2718 width += buttons[k].el.getWidth()+15;
2728 var handleEsc = function(d, k, e){
2729 if(opt && opt.closable !== false){
2739 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2740 * @return {Roo.BasicDialog} The BasicDialog element
2742 getDialog : function(){
2744 dlg = new Roo.bootstrap.Modal( {
2747 //constraintoviewport:false,
2749 //collapsible : false,
2754 //buttonAlign:"center",
2755 closeClick : function(){
2756 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2759 handleButton("cancel");
2764 dlg.on("hide", handleHide);
2766 //dlg.addKeyListener(27, handleEsc);
2768 this.buttons = buttons;
2769 var bt = this.buttonText;
2770 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2771 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2772 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2773 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2775 bodyEl = dlg.bodyEl.createChild({
2777 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2778 '<textarea class="roo-mb-textarea"></textarea>' +
2779 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2781 msgEl = bodyEl.dom.firstChild;
2782 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2783 textboxEl.enableDisplayMode();
2784 textboxEl.addKeyListener([10,13], function(){
2785 if(dlg.isVisible() && opt && opt.buttons){
2788 }else if(opt.buttons.yes){
2789 handleButton("yes");
2793 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2794 textareaEl.enableDisplayMode();
2795 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2796 progressEl.enableDisplayMode();
2797 var pf = progressEl.dom.firstChild;
2799 pp = Roo.get(pf.firstChild);
2800 pp.setHeight(pf.offsetHeight);
2808 * Updates the message box body text
2809 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2810 * the XHTML-compliant non-breaking space character '&#160;')
2811 * @return {Roo.MessageBox} This message box
2813 updateText : function(text){
2814 if(!dlg.isVisible() && !opt.width){
2815 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2817 msgEl.innerHTML = text || ' ';
2819 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2820 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2822 Math.min(opt.width || cw , this.maxWidth),
2823 Math.max(opt.minWidth || this.minWidth, bwidth)
2826 activeTextEl.setWidth(w);
2828 if(dlg.isVisible()){
2829 dlg.fixedcenter = false;
2831 // to big, make it scroll. = But as usual stupid IE does not support
2834 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2835 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2836 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2838 bodyEl.dom.style.height = '';
2839 bodyEl.dom.style.overflowY = '';
2842 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2844 bodyEl.dom.style.overflowX = '';
2847 dlg.setContentSize(w, bodyEl.getHeight());
2848 if(dlg.isVisible()){
2849 dlg.fixedcenter = true;
2855 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2856 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2857 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2858 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2859 * @return {Roo.MessageBox} This message box
2861 updateProgress : function(value, text){
2863 this.updateText(text);
2865 if (pp) { // weird bug on my firefox - for some reason this is not defined
2866 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2872 * Returns true if the message box is currently displayed
2873 * @return {Boolean} True if the message box is visible, else false
2875 isVisible : function(){
2876 return dlg && dlg.isVisible();
2880 * Hides the message box if it is displayed
2883 if(this.isVisible()){
2889 * Displays a new message box, or reinitializes an existing message box, based on the config options
2890 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2891 * The following config object properties are supported:
2893 Property Type Description
2894 ---------- --------------- ------------------------------------------------------------------------------------
2895 animEl String/Element An id or Element from which the message box should animate as it opens and
2896 closes (defaults to undefined)
2897 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2898 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2899 closable Boolean False to hide the top-right close button (defaults to true). Note that
2900 progress and wait dialogs will ignore this property and always hide the
2901 close button as they can only be closed programmatically.
2902 cls String A custom CSS class to apply to the message box element
2903 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2904 displayed (defaults to 75)
2905 fn Function A callback function to execute after closing the dialog. The arguments to the
2906 function will be btn (the name of the button that was clicked, if applicable,
2907 e.g. "ok"), and text (the value of the active text field, if applicable).
2908 Progress and wait dialogs will ignore this option since they do not respond to
2909 user actions and can only be closed programmatically, so any required function
2910 should be called by the same code after it closes the dialog.
2911 icon String A CSS class that provides a background image to be used as an icon for
2912 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2913 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2914 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2915 modal Boolean False to allow user interaction with the page while the message box is
2916 displayed (defaults to true)
2917 msg String A string that will replace the existing message box body text (defaults
2918 to the XHTML-compliant non-breaking space character ' ')
2919 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2920 progress Boolean True to display a progress bar (defaults to false)
2921 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2922 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2923 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2924 title String The title text
2925 value String The string value to set into the active textbox element if displayed
2926 wait Boolean True to display a progress bar (defaults to false)
2927 width Number The width of the dialog in pixels
2934 msg: 'Please enter your address:',
2936 buttons: Roo.MessageBox.OKCANCEL,
2939 animEl: 'addAddressBtn'
2942 * @param {Object} config Configuration options
2943 * @return {Roo.MessageBox} This message box
2945 show : function(options)
2948 // this causes nightmares if you show one dialog after another
2949 // especially on callbacks..
2951 if(this.isVisible()){
2954 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2955 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2956 Roo.log("New Dialog Message:" + options.msg )
2957 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2958 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2961 var d = this.getDialog();
2963 d.setTitle(opt.title || " ");
2964 d.closeEl.setDisplayed(opt.closable !== false);
2965 activeTextEl = textboxEl;
2966 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2971 textareaEl.setHeight(typeof opt.multiline == "number" ?
2972 opt.multiline : this.defaultTextHeight);
2973 activeTextEl = textareaEl;
2982 progressEl.setDisplayed(opt.progress === true);
2983 this.updateProgress(0);
2984 activeTextEl.dom.value = opt.value || "";
2986 dlg.setDefaultButton(activeTextEl);
2988 var bs = opt.buttons;
2992 }else if(bs && bs.yes){
2993 db = buttons["yes"];
2995 dlg.setDefaultButton(db);
2997 bwidth = updateButtons(opt.buttons);
2998 this.updateText(opt.msg);
3000 d.el.addClass(opt.cls);
3002 d.proxyDrag = opt.proxyDrag === true;
3003 d.modal = opt.modal !== false;
3004 d.mask = opt.modal !== false ? mask : false;
3006 // force it to the end of the z-index stack so it gets a cursor in FF
3007 document.body.appendChild(dlg.el.dom);
3008 d.animateTarget = null;
3009 d.show(options.animEl);
3015 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3016 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3017 * and closing the message box when the process is complete.
3018 * @param {String} title The title bar text
3019 * @param {String} msg The message box body text
3020 * @return {Roo.MessageBox} This message box
3022 progress : function(title, msg){
3029 minWidth: this.minProgressWidth,
3036 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3037 * If a callback function is passed it will be called after the user clicks the button, and the
3038 * id of the button that was clicked will be passed as the only parameter to the callback
3039 * (could also be the top-right close button).
3040 * @param {String} title The title bar text
3041 * @param {String} msg The message box body text
3042 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3043 * @param {Object} scope (optional) The scope of the callback function
3044 * @return {Roo.MessageBox} This message box
3046 alert : function(title, msg, fn, scope){
3059 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3060 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3061 * You are responsible for closing the message box when the process is complete.
3062 * @param {String} msg The message box body text
3063 * @param {String} title (optional) The title bar text
3064 * @return {Roo.MessageBox} This message box
3066 wait : function(msg, title){
3077 waitTimer = Roo.TaskMgr.start({
3079 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3087 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3088 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3089 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3090 * @param {String} title The title bar text
3091 * @param {String} msg The message box body text
3092 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3093 * @param {Object} scope (optional) The scope of the callback function
3094 * @return {Roo.MessageBox} This message box
3096 confirm : function(title, msg, fn, scope){
3100 buttons: this.YESNO,
3109 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3110 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3111 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3112 * (could also be the top-right close button) and the text that was entered will be passed as the two
3113 * parameters to the callback.
3114 * @param {String} title The title bar text
3115 * @param {String} msg The message box body text
3116 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3117 * @param {Object} scope (optional) The scope of the callback function
3118 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3119 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3120 * @return {Roo.MessageBox} This message box
3122 prompt : function(title, msg, fn, scope, multiline){
3126 buttons: this.OKCANCEL,
3131 multiline: multiline,
3138 * Button config that displays a single OK button
3143 * Button config that displays Yes and No buttons
3146 YESNO : {yes:true, no:true},
3148 * Button config that displays OK and Cancel buttons
3151 OKCANCEL : {ok:true, cancel:true},
3153 * Button config that displays Yes, No and Cancel buttons
3156 YESNOCANCEL : {yes:true, no:true, cancel:true},
3159 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3162 defaultTextHeight : 75,
3164 * The maximum width in pixels of the message box (defaults to 600)
3169 * The minimum width in pixels of the message box (defaults to 100)
3174 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3175 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3178 minProgressWidth : 250,
3180 * An object containing the default button text strings that can be overriden for localized language support.
3181 * Supported properties are: ok, cancel, yes and no.
3182 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3195 * Shorthand for {@link Roo.MessageBox}
3197 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3198 Roo.Msg = Roo.Msg || Roo.MessageBox;
3207 * @class Roo.bootstrap.Navbar
3208 * @extends Roo.bootstrap.Component
3209 * Bootstrap Navbar class
3212 * Create a new Navbar
3213 * @param {Object} config The config object
3217 Roo.bootstrap.Navbar = function(config){
3218 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3222 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3231 getAutoCreate : function(){
3234 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3238 initEvents :function ()
3240 //Roo.log(this.el.select('.navbar-toggle',true));
3241 this.el.select('.navbar-toggle',true).on('click', function() {
3242 // Roo.log('click');
3243 this.el.select('.navbar-collapse',true).toggleClass('in');
3251 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3253 var size = this.el.getSize();
3254 this.maskEl.setSize(size.width, size.height);
3255 this.maskEl.enableDisplayMode("block");
3264 getChildContainer : function()
3266 if (this.el.select('.collapse').getCount()) {
3267 return this.el.select('.collapse',true).first();
3300 * @class Roo.bootstrap.NavSimplebar
3301 * @extends Roo.bootstrap.Navbar
3302 * Bootstrap Sidebar class
3304 * @cfg {Boolean} inverse is inverted color
3306 * @cfg {String} type (nav | pills | tabs)
3307 * @cfg {Boolean} arrangement stacked | justified
3308 * @cfg {String} align (left | right) alignment
3310 * @cfg {Boolean} main (true|false) main nav bar? default false
3311 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3313 * @cfg {String} tag (header|footer|nav|div) default is nav
3319 * Create a new Sidebar
3320 * @param {Object} config The config object
3324 Roo.bootstrap.NavSimplebar = function(config){
3325 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3328 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3344 getAutoCreate : function(){
3348 tag : this.tag || 'div',
3361 this.type = this.type || 'nav';
3362 if (['tabs','pills'].indexOf(this.type)!==-1) {
3363 cfg.cn[0].cls += ' nav-' + this.type
3367 if (this.type!=='nav') {
3368 Roo.log('nav type must be nav/tabs/pills')
3370 cfg.cn[0].cls += ' navbar-nav'
3376 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3377 cfg.cn[0].cls += ' nav-' + this.arrangement;
3381 if (this.align === 'right') {
3382 cfg.cn[0].cls += ' navbar-right';
3386 cfg.cls += ' navbar-inverse';
3413 * @class Roo.bootstrap.NavHeaderbar
3414 * @extends Roo.bootstrap.NavSimplebar
3415 * Bootstrap Sidebar class
3417 * @cfg {String} brand what is brand
3418 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3419 * @cfg {String} brand_href href of the brand
3420 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3421 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3422 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3423 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3426 * Create a new Sidebar
3427 * @param {Object} config The config object
3431 Roo.bootstrap.NavHeaderbar = function(config){
3432 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3436 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3443 desktopCenter : false,
3446 getAutoCreate : function(){
3449 tag: this.nav || 'nav',
3456 if (this.desktopCenter) {
3457 cn.push({cls : 'container', cn : []});
3464 cls: 'navbar-header',
3469 cls: 'navbar-toggle',
3470 'data-toggle': 'collapse',
3475 html: 'Toggle navigation'
3497 cls: 'collapse navbar-collapse',
3501 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3503 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3504 cfg.cls += ' navbar-' + this.position;
3506 // tag can override this..
3508 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3511 if (this.brand !== '') {
3514 href: this.brand_href ? this.brand_href : '#',
3515 cls: 'navbar-brand',
3523 cfg.cls += ' main-nav';
3531 getHeaderChildContainer : function()
3533 if (this.el.select('.navbar-header').getCount()) {
3534 return this.el.select('.navbar-header',true).first();
3537 return this.getChildContainer();
3541 initEvents : function()
3543 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3545 if (this.autohide) {
3550 Roo.get(document).on('scroll',function(e) {
3551 var ns = Roo.get(document).getScroll().top;
3552 var os = prevScroll;
3556 ft.removeClass('slideDown');
3557 ft.addClass('slideUp');
3560 ft.removeClass('slideUp');
3561 ft.addClass('slideDown');
3582 * @class Roo.bootstrap.NavSidebar
3583 * @extends Roo.bootstrap.Navbar
3584 * Bootstrap Sidebar class
3587 * Create a new Sidebar
3588 * @param {Object} config The config object
3592 Roo.bootstrap.NavSidebar = function(config){
3593 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3596 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3598 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3600 getAutoCreate : function(){
3605 cls: 'sidebar sidebar-nav'
3627 * @class Roo.bootstrap.NavGroup
3628 * @extends Roo.bootstrap.Component
3629 * Bootstrap NavGroup class
3630 * @cfg {String} align (left|right)
3631 * @cfg {Boolean} inverse
3632 * @cfg {String} type (nav|pills|tab) default nav
3633 * @cfg {String} navId - reference Id for navbar.
3637 * Create a new nav group
3638 * @param {Object} config The config object
3641 Roo.bootstrap.NavGroup = function(config){
3642 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3645 Roo.bootstrap.NavGroup.register(this);
3649 * Fires when the active item changes
3650 * @param {Roo.bootstrap.NavGroup} this
3651 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3652 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3659 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3670 getAutoCreate : function()
3672 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3679 if (['tabs','pills'].indexOf(this.type)!==-1) {
3680 cfg.cls += ' nav-' + this.type
3682 if (this.type!=='nav') {
3683 Roo.log('nav type must be nav/tabs/pills')
3685 cfg.cls += ' navbar-nav'
3688 if (this.parent().sidebar) {
3691 cls: 'dashboard-menu sidebar-menu'
3697 if (this.form === true) {
3703 if (this.align === 'right') {
3704 cfg.cls += ' navbar-right';
3706 cfg.cls += ' navbar-left';
3710 if (this.align === 'right') {
3711 cfg.cls += ' navbar-right';
3715 cfg.cls += ' navbar-inverse';
3723 * sets the active Navigation item
3724 * @param {Roo.bootstrap.NavItem} the new current navitem
3726 setActiveItem : function(item)
3729 Roo.each(this.navItems, function(v){
3734 v.setActive(false, true);
3741 item.setActive(true, true);
3742 this.fireEvent('changed', this, item, prev);
3747 * gets the active Navigation item
3748 * @return {Roo.bootstrap.NavItem} the current navitem
3750 getActive : function()
3754 Roo.each(this.navItems, function(v){
3765 indexOfNav : function()
3769 Roo.each(this.navItems, function(v,i){
3780 * adds a Navigation item
3781 * @param {Roo.bootstrap.NavItem} the navitem to add
3783 addItem : function(cfg)
3785 var cn = new Roo.bootstrap.NavItem(cfg);
3787 cn.parentId = this.id;
3788 cn.onRender(this.el, null);
3792 * register a Navigation item
3793 * @param {Roo.bootstrap.NavItem} the navitem to add
3795 register : function(item)
3797 this.navItems.push( item);
3798 item.navId = this.navId;
3803 * clear all the Navigation item
3806 clearAll : function()
3809 this.el.dom.innerHTML = '';
3812 getNavItem: function(tabId)
3815 Roo.each(this.navItems, function(e) {
3816 if (e.tabId == tabId) {
3826 setActiveNext : function()
3828 var i = this.indexOfNav(this.getActive());
3829 if (i > this.navItems.length) {
3832 this.setActiveItem(this.navItems[i+1]);
3834 setActivePrev : function()
3836 var i = this.indexOfNav(this.getActive());
3840 this.setActiveItem(this.navItems[i-1]);
3842 clearWasActive : function(except) {
3843 Roo.each(this.navItems, function(e) {
3844 if (e.tabId != except.tabId && e.was_active) {
3845 e.was_active = false;
3852 getWasActive : function ()
3855 Roo.each(this.navItems, function(e) {
3870 Roo.apply(Roo.bootstrap.NavGroup, {
3874 * register a Navigation Group
3875 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3877 register : function(navgrp)
3879 this.groups[navgrp.navId] = navgrp;
3883 * fetch a Navigation Group based on the navigation ID
3884 * @param {string} the navgroup to add
3885 * @returns {Roo.bootstrap.NavGroup} the navgroup
3887 get: function(navId) {
3888 if (typeof(this.groups[navId]) == 'undefined') {
3890 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3892 return this.groups[navId] ;
3907 * @class Roo.bootstrap.NavItem
3908 * @extends Roo.bootstrap.Component
3909 * Bootstrap Navbar.NavItem class
3910 * @cfg {String} href link to
3911 * @cfg {String} html content of button
3912 * @cfg {String} badge text inside badge
3913 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3914 * @cfg {String} glyphicon name of glyphicon
3915 * @cfg {String} icon name of font awesome icon
3916 * @cfg {Boolean} active Is item active
3917 * @cfg {Boolean} disabled Is item disabled
3919 * @cfg {Boolean} preventDefault (true | false) default false
3920 * @cfg {String} tabId the tab that this item activates.
3921 * @cfg {String} tagtype (a|span) render as a href or span?
3922 * @cfg {Boolean} animateRef (true|false) link to element default false
3925 * Create a new Navbar Item
3926 * @param {Object} config The config object
3928 Roo.bootstrap.NavItem = function(config){
3929 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3934 * The raw click event for the entire grid.
3935 * @param {Roo.EventObject} e
3940 * Fires when the active item active state changes
3941 * @param {Roo.bootstrap.NavItem} this
3942 * @param {boolean} state the new state
3948 * Fires when scroll to element
3949 * @param {Roo.bootstrap.NavItem} this
3950 * @param {Object} options
3951 * @param {Roo.EventObject} e
3959 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3967 preventDefault : false,
3974 getAutoCreate : function(){
3982 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3984 if (this.disabled) {
3985 cfg.cls += ' disabled';
3988 if (this.href || this.html || this.glyphicon || this.icon) {
3992 href : this.href || "#",
3993 html: this.html || ''
3998 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4001 if(this.glyphicon) {
4002 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4007 cfg.cn[0].html += " <span class='caret'></span>";
4011 if (this.badge !== '') {
4013 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4021 initEvents: function()
4023 if (typeof (this.menu) != 'undefined') {
4024 this.menu.parentType = this.xtype;
4025 this.menu.triggerEl = this.el;
4026 this.menu = this.addxtype(Roo.apply({}, this.menu));
4029 this.el.select('a',true).on('click', this.onClick, this);
4031 if(this.tagtype == 'span'){
4032 this.el.select('span',true).on('click', this.onClick, this);
4035 // at this point parent should be available..
4036 this.parent().register(this);
4039 onClick : function(e)
4042 this.preventDefault ||
4049 if (this.disabled) {
4053 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4054 if (tg && tg.transition) {
4055 Roo.log("waiting for the transitionend");
4061 //Roo.log("fire event clicked");
4062 if(this.fireEvent('click', this, e) === false){
4066 if(this.tagtype == 'span'){
4070 //Roo.log(this.href);
4071 var ael = this.el.select('a',true).first();
4074 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4075 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4076 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4077 return; // ignore... - it's a 'hash' to another page.
4081 this.scrollToElement(e);
4085 var p = this.parent();
4087 if (['tabs','pills'].indexOf(p.type)!==-1) {
4088 if (typeof(p.setActiveItem) !== 'undefined') {
4089 p.setActiveItem(this);
4093 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4094 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4095 // remove the collapsed menu expand...
4096 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4100 isActive: function () {
4103 setActive : function(state, fire, is_was_active)
4105 if (this.active && !state & this.navId) {
4106 this.was_active = true;
4107 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4109 nv.clearWasActive(this);
4113 this.active = state;
4116 this.el.removeClass('active');
4117 } else if (!this.el.hasClass('active')) {
4118 this.el.addClass('active');
4121 this.fireEvent('changed', this, state);
4124 // show a panel if it's registered and related..
4126 if (!this.navId || !this.tabId || !state || is_was_active) {
4130 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4134 var pan = tg.getPanelByName(this.tabId);
4138 // if we can not flip to new panel - go back to old nav highlight..
4139 if (false == tg.showPanel(pan)) {
4140 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4142 var onav = nv.getWasActive();
4144 onav.setActive(true, false, true);
4153 // this should not be here...
4154 setDisabled : function(state)
4156 this.disabled = state;
4158 this.el.removeClass('disabled');
4159 } else if (!this.el.hasClass('disabled')) {
4160 this.el.addClass('disabled');
4166 * Fetch the element to display the tooltip on.
4167 * @return {Roo.Element} defaults to this.el
4169 tooltipEl : function()
4171 return this.el.select('' + this.tagtype + '', true).first();
4174 scrollToElement : function(e)
4176 var c = document.body;
4179 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4181 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4182 c = document.documentElement;
4185 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4191 var o = target.calcOffsetsTo(c);
4198 this.fireEvent('scrollto', this, options, e);
4200 Roo.get(c).scrollTo('top', options.value, true);
4213 * <span> icon </span>
4214 * <span> text </span>
4215 * <span>badge </span>
4219 * @class Roo.bootstrap.NavSidebarItem
4220 * @extends Roo.bootstrap.NavItem
4221 * Bootstrap Navbar.NavSidebarItem class
4223 * Create a new Navbar Button
4224 * @param {Object} config The config object
4226 Roo.bootstrap.NavSidebarItem = function(config){
4227 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4232 * The raw click event for the entire grid.
4233 * @param {Roo.EventObject} e
4238 * Fires when the active item active state changes
4239 * @param {Roo.bootstrap.NavSidebarItem} this
4240 * @param {boolean} state the new state
4248 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4251 getAutoCreate : function(){
4256 href : this.href || '#',
4268 html : this.html || ''
4273 cfg.cls += ' active';
4277 if (this.glyphicon || this.icon) {
4278 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4279 a.cn.push({ tag : 'i', cls : c }) ;
4284 if (this.badge !== '') {
4285 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4289 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4290 a.cls += 'dropdown-toggle treeview' ;
4314 * @class Roo.bootstrap.Row
4315 * @extends Roo.bootstrap.Component
4316 * Bootstrap Row class (contains columns...)
4320 * @param {Object} config The config object
4323 Roo.bootstrap.Row = function(config){
4324 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4327 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4329 getAutoCreate : function(){
4348 * @class Roo.bootstrap.Element
4349 * @extends Roo.bootstrap.Component
4350 * Bootstrap Element class
4351 * @cfg {String} html contents of the element
4352 * @cfg {String} tag tag of the element
4353 * @cfg {String} cls class of the element
4354 * @cfg {Boolean} preventDefault (true|false) default false
4355 * @cfg {Boolean} clickable (true|false) default false
4358 * Create a new Element
4359 * @param {Object} config The config object
4362 Roo.bootstrap.Element = function(config){
4363 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4369 * When a element is chick
4370 * @param {Roo.bootstrap.Element} this
4371 * @param {Roo.EventObject} e
4377 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4382 preventDefault: false,
4385 getAutoCreate : function(){
4396 initEvents: function()
4398 Roo.bootstrap.Element.superclass.initEvents.call(this);
4401 this.el.on('click', this.onClick, this);
4406 onClick : function(e)
4408 if(this.preventDefault){
4412 this.fireEvent('click', this, e);
4415 getValue : function()
4417 return this.el.dom.innerHTML;
4420 setValue : function(value)
4422 this.el.dom.innerHTML = value;
4437 * @class Roo.bootstrap.Pagination
4438 * @extends Roo.bootstrap.Component
4439 * Bootstrap Pagination class
4440 * @cfg {String} size xs | sm | md | lg
4441 * @cfg {Boolean} inverse false | true
4444 * Create a new Pagination
4445 * @param {Object} config The config object
4448 Roo.bootstrap.Pagination = function(config){
4449 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4452 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4458 getAutoCreate : function(){
4464 cfg.cls += ' inverse';
4470 cfg.cls += " " + this.cls;
4488 * @class Roo.bootstrap.PaginationItem
4489 * @extends Roo.bootstrap.Component
4490 * Bootstrap PaginationItem class
4491 * @cfg {String} html text
4492 * @cfg {String} href the link
4493 * @cfg {Boolean} preventDefault (true | false) default true
4494 * @cfg {Boolean} active (true | false) default false
4495 * @cfg {Boolean} disabled default false
4499 * Create a new PaginationItem
4500 * @param {Object} config The config object
4504 Roo.bootstrap.PaginationItem = function(config){
4505 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4510 * The raw click event for the entire grid.
4511 * @param {Roo.EventObject} e
4517 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4521 preventDefault: true,
4526 getAutoCreate : function(){
4532 href : this.href ? this.href : '#',
4533 html : this.html ? this.html : ''
4543 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4547 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4553 initEvents: function() {
4555 this.el.on('click', this.onClick, this);
4558 onClick : function(e)
4560 Roo.log('PaginationItem on click ');
4561 if(this.preventDefault){
4569 this.fireEvent('click', this, e);
4585 * @class Roo.bootstrap.Slider
4586 * @extends Roo.bootstrap.Component
4587 * Bootstrap Slider class
4590 * Create a new Slider
4591 * @param {Object} config The config object
4594 Roo.bootstrap.Slider = function(config){
4595 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4598 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4600 getAutoCreate : function(){
4604 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4608 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4620 * Ext JS Library 1.1.1
4621 * Copyright(c) 2006-2007, Ext JS, LLC.
4623 * Originally Released Under LGPL - original licence link has changed is not relivant.
4626 * <script type="text/javascript">
4631 * @class Roo.grid.ColumnModel
4632 * @extends Roo.util.Observable
4633 * This is the default implementation of a ColumnModel used by the Grid. It defines
4634 * the columns in the grid.
4637 var colModel = new Roo.grid.ColumnModel([
4638 {header: "Ticker", width: 60, sortable: true, locked: true},
4639 {header: "Company Name", width: 150, sortable: true},
4640 {header: "Market Cap.", width: 100, sortable: true},
4641 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4642 {header: "Employees", width: 100, sortable: true, resizable: false}
4647 * The config options listed for this class are options which may appear in each
4648 * individual column definition.
4649 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4651 * @param {Object} config An Array of column config objects. See this class's
4652 * config objects for details.
4654 Roo.grid.ColumnModel = function(config){
4656 * The config passed into the constructor
4658 this.config = config;
4661 // if no id, create one
4662 // if the column does not have a dataIndex mapping,
4663 // map it to the order it is in the config
4664 for(var i = 0, len = config.length; i < len; i++){
4666 if(typeof c.dataIndex == "undefined"){
4669 if(typeof c.renderer == "string"){
4670 c.renderer = Roo.util.Format[c.renderer];
4672 if(typeof c.id == "undefined"){
4675 if(c.editor && c.editor.xtype){
4676 c.editor = Roo.factory(c.editor, Roo.grid);
4678 if(c.editor && c.editor.isFormField){
4679 c.editor = new Roo.grid.GridEditor(c.editor);
4681 this.lookup[c.id] = c;
4685 * The width of columns which have no width specified (defaults to 100)
4688 this.defaultWidth = 100;
4691 * Default sortable of columns which have no sortable specified (defaults to false)
4694 this.defaultSortable = false;
4698 * @event widthchange
4699 * Fires when the width of a column changes.
4700 * @param {ColumnModel} this
4701 * @param {Number} columnIndex The column index
4702 * @param {Number} newWidth The new width
4704 "widthchange": true,
4706 * @event headerchange
4707 * Fires when the text of a header changes.
4708 * @param {ColumnModel} this
4709 * @param {Number} columnIndex The column index
4710 * @param {Number} newText The new header text
4712 "headerchange": true,
4714 * @event hiddenchange
4715 * Fires when a column is hidden or "unhidden".
4716 * @param {ColumnModel} this
4717 * @param {Number} columnIndex The column index
4718 * @param {Boolean} hidden true if hidden, false otherwise
4720 "hiddenchange": true,
4722 * @event columnmoved
4723 * Fires when a column is moved.
4724 * @param {ColumnModel} this
4725 * @param {Number} oldIndex
4726 * @param {Number} newIndex
4728 "columnmoved" : true,
4730 * @event columlockchange
4731 * Fires when a column's locked state is changed
4732 * @param {ColumnModel} this
4733 * @param {Number} colIndex
4734 * @param {Boolean} locked true if locked
4736 "columnlockchange" : true
4738 Roo.grid.ColumnModel.superclass.constructor.call(this);
4740 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4742 * @cfg {String} header The header text to display in the Grid view.
4745 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4746 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4747 * specified, the column's index is used as an index into the Record's data Array.
4750 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4751 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4754 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4755 * Defaults to the value of the {@link #defaultSortable} property.
4756 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4759 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4762 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4765 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4768 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4771 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4772 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4773 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4774 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4777 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4780 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4783 * @cfg {String} cursor (Optional)
4786 * @cfg {String} tooltip (Optional)
4789 * Returns the id of the column at the specified index.
4790 * @param {Number} index The column index
4791 * @return {String} the id
4793 getColumnId : function(index){
4794 return this.config[index].id;
4798 * Returns the column for a specified id.
4799 * @param {String} id The column id
4800 * @return {Object} the column
4802 getColumnById : function(id){
4803 return this.lookup[id];
4808 * Returns the column for a specified dataIndex.
4809 * @param {String} dataIndex The column dataIndex
4810 * @return {Object|Boolean} the column or false if not found
4812 getColumnByDataIndex: function(dataIndex){
4813 var index = this.findColumnIndex(dataIndex);
4814 return index > -1 ? this.config[index] : false;
4818 * Returns the index for a specified column id.
4819 * @param {String} id The column id
4820 * @return {Number} the index, or -1 if not found
4822 getIndexById : function(id){
4823 for(var i = 0, len = this.config.length; i < len; i++){
4824 if(this.config[i].id == id){
4832 * Returns the index for a specified column dataIndex.
4833 * @param {String} dataIndex The column dataIndex
4834 * @return {Number} the index, or -1 if not found
4837 findColumnIndex : function(dataIndex){
4838 for(var i = 0, len = this.config.length; i < len; i++){
4839 if(this.config[i].dataIndex == dataIndex){
4847 moveColumn : function(oldIndex, newIndex){
4848 var c = this.config[oldIndex];
4849 this.config.splice(oldIndex, 1);
4850 this.config.splice(newIndex, 0, c);
4851 this.dataMap = null;
4852 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4855 isLocked : function(colIndex){
4856 return this.config[colIndex].locked === true;
4859 setLocked : function(colIndex, value, suppressEvent){
4860 if(this.isLocked(colIndex) == value){
4863 this.config[colIndex].locked = value;
4865 this.fireEvent("columnlockchange", this, colIndex, value);
4869 getTotalLockedWidth : function(){
4871 for(var i = 0; i < this.config.length; i++){
4872 if(this.isLocked(i) && !this.isHidden(i)){
4873 this.totalWidth += this.getColumnWidth(i);
4879 getLockedCount : function(){
4880 for(var i = 0, len = this.config.length; i < len; i++){
4881 if(!this.isLocked(i)){
4888 * Returns the number of columns.
4891 getColumnCount : function(visibleOnly){
4892 if(visibleOnly === true){
4894 for(var i = 0, len = this.config.length; i < len; i++){
4895 if(!this.isHidden(i)){
4901 return this.config.length;
4905 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4906 * @param {Function} fn
4907 * @param {Object} scope (optional)
4908 * @return {Array} result
4910 getColumnsBy : function(fn, scope){
4912 for(var i = 0, len = this.config.length; i < len; i++){
4913 var c = this.config[i];
4914 if(fn.call(scope||this, c, i) === true){
4922 * Returns true if the specified column is sortable.
4923 * @param {Number} col The column index
4926 isSortable : function(col){
4927 if(typeof this.config[col].sortable == "undefined"){
4928 return this.defaultSortable;
4930 return this.config[col].sortable;
4934 * Returns the rendering (formatting) function defined for the column.
4935 * @param {Number} col The column index.
4936 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4938 getRenderer : function(col){
4939 if(!this.config[col].renderer){
4940 return Roo.grid.ColumnModel.defaultRenderer;
4942 return this.config[col].renderer;
4946 * Sets the rendering (formatting) function for a column.
4947 * @param {Number} col The column index
4948 * @param {Function} fn The function to use to process the cell's raw data
4949 * to return HTML markup for the grid view. The render function is called with
4950 * the following parameters:<ul>
4951 * <li>Data value.</li>
4952 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4953 * <li>css A CSS style string to apply to the table cell.</li>
4954 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4955 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4956 * <li>Row index</li>
4957 * <li>Column index</li>
4958 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4960 setRenderer : function(col, fn){
4961 this.config[col].renderer = fn;
4965 * Returns the width for the specified column.
4966 * @param {Number} col The column index
4969 getColumnWidth : function(col){
4970 return this.config[col].width * 1 || this.defaultWidth;
4974 * Sets the width for a column.
4975 * @param {Number} col The column index
4976 * @param {Number} width The new width
4978 setColumnWidth : function(col, width, suppressEvent){
4979 this.config[col].width = width;
4980 this.totalWidth = null;
4982 this.fireEvent("widthchange", this, col, width);
4987 * Returns the total width of all columns.
4988 * @param {Boolean} includeHidden True to include hidden column widths
4991 getTotalWidth : function(includeHidden){
4992 if(!this.totalWidth){
4993 this.totalWidth = 0;
4994 for(var i = 0, len = this.config.length; i < len; i++){
4995 if(includeHidden || !this.isHidden(i)){
4996 this.totalWidth += this.getColumnWidth(i);
5000 return this.totalWidth;
5004 * Returns the header for the specified column.
5005 * @param {Number} col The column index
5008 getColumnHeader : function(col){
5009 return this.config[col].header;
5013 * Sets the header for a column.
5014 * @param {Number} col The column index
5015 * @param {String} header The new header
5017 setColumnHeader : function(col, header){
5018 this.config[col].header = header;
5019 this.fireEvent("headerchange", this, col, header);
5023 * Returns the tooltip for the specified column.
5024 * @param {Number} col The column index
5027 getColumnTooltip : function(col){
5028 return this.config[col].tooltip;
5031 * Sets the tooltip for a column.
5032 * @param {Number} col The column index
5033 * @param {String} tooltip The new tooltip
5035 setColumnTooltip : function(col, tooltip){
5036 this.config[col].tooltip = tooltip;
5040 * Returns the dataIndex for the specified column.
5041 * @param {Number} col The column index
5044 getDataIndex : function(col){
5045 return this.config[col].dataIndex;
5049 * Sets the dataIndex for a column.
5050 * @param {Number} col The column index
5051 * @param {Number} dataIndex The new dataIndex
5053 setDataIndex : function(col, dataIndex){
5054 this.config[col].dataIndex = dataIndex;
5060 * Returns true if the cell is editable.
5061 * @param {Number} colIndex The column index
5062 * @param {Number} rowIndex The row index
5065 isCellEditable : function(colIndex, rowIndex){
5066 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5070 * Returns the editor defined for the cell/column.
5071 * return false or null to disable editing.
5072 * @param {Number} colIndex The column index
5073 * @param {Number} rowIndex The row index
5076 getCellEditor : function(colIndex, rowIndex){
5077 return this.config[colIndex].editor;
5081 * Sets if a column is editable.
5082 * @param {Number} col The column index
5083 * @param {Boolean} editable True if the column is editable
5085 setEditable : function(col, editable){
5086 this.config[col].editable = editable;
5091 * Returns true if the column is hidden.
5092 * @param {Number} colIndex The column index
5095 isHidden : function(colIndex){
5096 return this.config[colIndex].hidden;
5101 * Returns true if the column width cannot be changed
5103 isFixed : function(colIndex){
5104 return this.config[colIndex].fixed;
5108 * Returns true if the column can be resized
5111 isResizable : function(colIndex){
5112 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5115 * Sets if a column is hidden.
5116 * @param {Number} colIndex The column index
5117 * @param {Boolean} hidden True if the column is hidden
5119 setHidden : function(colIndex, hidden){
5120 this.config[colIndex].hidden = hidden;
5121 this.totalWidth = null;
5122 this.fireEvent("hiddenchange", this, colIndex, hidden);
5126 * Sets the editor for a column.
5127 * @param {Number} col The column index
5128 * @param {Object} editor The editor object
5130 setEditor : function(col, editor){
5131 this.config[col].editor = editor;
5135 Roo.grid.ColumnModel.defaultRenderer = function(value){
5136 if(typeof value == "string" && value.length < 1){
5142 // Alias for backwards compatibility
5143 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5146 * Ext JS Library 1.1.1
5147 * Copyright(c) 2006-2007, Ext JS, LLC.
5149 * Originally Released Under LGPL - original licence link has changed is not relivant.
5152 * <script type="text/javascript">
5156 * @class Roo.LoadMask
5157 * A simple utility class for generically masking elements while loading data. If the element being masked has
5158 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5159 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5160 * element's UpdateManager load indicator and will be destroyed after the initial load.
5162 * Create a new LoadMask
5163 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5164 * @param {Object} config The config object
5166 Roo.LoadMask = function(el, config){
5167 this.el = Roo.get(el);
5168 Roo.apply(this, config);
5170 this.store.on('beforeload', this.onBeforeLoad, this);
5171 this.store.on('load', this.onLoad, this);
5172 this.store.on('loadexception', this.onLoadException, this);
5173 this.removeMask = false;
5175 var um = this.el.getUpdateManager();
5176 um.showLoadIndicator = false; // disable the default indicator
5177 um.on('beforeupdate', this.onBeforeLoad, this);
5178 um.on('update', this.onLoad, this);
5179 um.on('failure', this.onLoad, this);
5180 this.removeMask = true;
5184 Roo.LoadMask.prototype = {
5186 * @cfg {Boolean} removeMask
5187 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5188 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5192 * The text to display in a centered loading message box (defaults to 'Loading...')
5196 * @cfg {String} msgCls
5197 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5199 msgCls : 'x-mask-loading',
5202 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5208 * Disables the mask to prevent it from being displayed
5210 disable : function(){
5211 this.disabled = true;
5215 * Enables the mask so that it can be displayed
5217 enable : function(){
5218 this.disabled = false;
5221 onLoadException : function()
5225 if (typeof(arguments[3]) != 'undefined') {
5226 Roo.MessageBox.alert("Error loading",arguments[3]);
5230 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5231 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5240 this.el.unmask(this.removeMask);
5245 this.el.unmask(this.removeMask);
5249 onBeforeLoad : function(){
5251 this.el.mask(this.msg, this.msgCls);
5256 destroy : function(){
5258 this.store.un('beforeload', this.onBeforeLoad, this);
5259 this.store.un('load', this.onLoad, this);
5260 this.store.un('loadexception', this.onLoadException, this);
5262 var um = this.el.getUpdateManager();
5263 um.un('beforeupdate', this.onBeforeLoad, this);
5264 um.un('update', this.onLoad, this);
5265 um.un('failure', this.onLoad, this);
5276 * @class Roo.bootstrap.Table
5277 * @extends Roo.bootstrap.Component
5278 * Bootstrap Table class
5279 * @cfg {String} cls table class
5280 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5281 * @cfg {String} bgcolor Specifies the background color for a table
5282 * @cfg {Number} border Specifies whether the table cells should have borders or not
5283 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5284 * @cfg {Number} cellspacing Specifies the space between cells
5285 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5286 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5287 * @cfg {String} sortable Specifies that the table should be sortable
5288 * @cfg {String} summary Specifies a summary of the content of a table
5289 * @cfg {Number} width Specifies the width of a table
5290 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5292 * @cfg {boolean} striped Should the rows be alternative striped
5293 * @cfg {boolean} bordered Add borders to the table
5294 * @cfg {boolean} hover Add hover highlighting
5295 * @cfg {boolean} condensed Format condensed
5296 * @cfg {boolean} responsive Format condensed
5297 * @cfg {Boolean} loadMask (true|false) default false
5298 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5299 * @cfg {Boolean} thead (true|false) generate thead, default true
5300 * @cfg {Boolean} RowSelection (true|false) default false
5301 * @cfg {Boolean} CellSelection (true|false) default false
5302 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5306 * Create a new Table
5307 * @param {Object} config The config object
5310 Roo.bootstrap.Table = function(config){
5311 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5314 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5315 this.sm = this.selModel;
5316 this.sm.xmodule = this.xmodule || false;
5318 if (this.cm && typeof(this.cm.config) == 'undefined') {
5319 this.colModel = new Roo.grid.ColumnModel(this.cm);
5320 this.cm = this.colModel;
5321 this.cm.xmodule = this.xmodule || false;
5324 this.store= Roo.factory(this.store, Roo.data);
5325 this.ds = this.store;
5326 this.ds.xmodule = this.xmodule || false;
5329 if (this.footer && this.store) {
5330 this.footer.dataSource = this.ds;
5331 this.footer = Roo.factory(this.footer);
5338 * Fires when a cell is clicked
5339 * @param {Roo.bootstrap.Table} this
5340 * @param {Roo.Element} el
5341 * @param {Number} rowIndex
5342 * @param {Number} columnIndex
5343 * @param {Roo.EventObject} e
5347 * @event celldblclick
5348 * Fires when a cell is double clicked
5349 * @param {Roo.bootstrap.Table} this
5350 * @param {Roo.Element} el
5351 * @param {Number} rowIndex
5352 * @param {Number} columnIndex
5353 * @param {Roo.EventObject} e
5355 "celldblclick" : true,
5358 * Fires when a row is clicked
5359 * @param {Roo.bootstrap.Table} this
5360 * @param {Roo.Element} el
5361 * @param {Number} rowIndex
5362 * @param {Roo.EventObject} e
5366 * @event rowdblclick
5367 * Fires when a row is double clicked
5368 * @param {Roo.bootstrap.Table} this
5369 * @param {Roo.Element} el
5370 * @param {Number} rowIndex
5371 * @param {Roo.EventObject} e
5373 "rowdblclick" : true,
5376 * Fires when a mouseover occur
5377 * @param {Roo.bootstrap.Table} this
5378 * @param {Roo.Element} el
5379 * @param {Number} rowIndex
5380 * @param {Number} columnIndex
5381 * @param {Roo.EventObject} e
5386 * Fires when a mouseout occur
5387 * @param {Roo.bootstrap.Table} this
5388 * @param {Roo.Element} el
5389 * @param {Number} rowIndex
5390 * @param {Number} columnIndex
5391 * @param {Roo.EventObject} e
5396 * Fires when a row is rendered, so you can change add a style to it.
5397 * @param {Roo.bootstrap.Table} this
5398 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5402 * @event rowsrendered
5403 * Fires when all the rows have been rendered
5404 * @param {Roo.bootstrap.Table} this
5406 'rowsrendered' : true
5411 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5435 RowSelection : false,
5436 CellSelection : false,
5439 // Roo.Element - the tbody
5442 getAutoCreate : function(){
5443 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5452 cfg.cls += ' table-striped';
5456 cfg.cls += ' table-hover';
5458 if (this.bordered) {
5459 cfg.cls += ' table-bordered';
5461 if (this.condensed) {
5462 cfg.cls += ' table-condensed';
5464 if (this.responsive) {
5465 cfg.cls += ' table-responsive';
5469 cfg.cls+= ' ' +this.cls;
5472 // this lot should be simplifed...
5475 cfg.align=this.align;
5478 cfg.bgcolor=this.bgcolor;
5481 cfg.border=this.border;
5483 if (this.cellpadding) {
5484 cfg.cellpadding=this.cellpadding;
5486 if (this.cellspacing) {
5487 cfg.cellspacing=this.cellspacing;
5490 cfg.frame=this.frame;
5493 cfg.rules=this.rules;
5495 if (this.sortable) {
5496 cfg.sortable=this.sortable;
5499 cfg.summary=this.summary;
5502 cfg.width=this.width;
5505 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5508 if(this.store || this.cm){
5510 cfg.cn.push(this.renderHeader());
5513 cfg.cn.push(this.renderBody());
5516 cfg.cn.push(this.renderFooter());
5519 cfg.cls+= ' TableGrid';
5522 return { cn : [ cfg ] };
5525 initEvents : function()
5527 if(!this.store || !this.cm){
5531 //Roo.log('initEvents with ds!!!!');
5533 this.mainBody = this.el.select('tbody', true).first();
5538 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5539 e.on('click', _this.sort, _this);
5542 this.el.on("click", this.onClick, this);
5543 this.el.on("dblclick", this.onDblClick, this);
5545 // why is this done????? = it breaks dialogs??
5546 //this.parent().el.setStyle('position', 'relative');
5550 this.footer.parentId = this.id;
5551 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5554 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5556 this.store.on('load', this.onLoad, this);
5557 this.store.on('beforeload', this.onBeforeLoad, this);
5558 this.store.on('update', this.onUpdate, this);
5559 this.store.on('add', this.onAdd, this);
5563 onMouseover : function(e, el)
5565 var cell = Roo.get(el);
5571 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5572 cell = cell.findParent('td', false, true);
5575 var row = cell.findParent('tr', false, true);
5576 var cellIndex = cell.dom.cellIndex;
5577 var rowIndex = row.dom.rowIndex - 1; // start from 0
5579 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5583 onMouseout : function(e, el)
5585 var cell = Roo.get(el);
5591 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5592 cell = cell.findParent('td', false, true);
5595 var row = cell.findParent('tr', false, true);
5596 var cellIndex = cell.dom.cellIndex;
5597 var rowIndex = row.dom.rowIndex - 1; // start from 0
5599 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5603 onClick : function(e, el)
5605 var cell = Roo.get(el);
5607 if(!cell || (!this.CellSelection && !this.RowSelection)){
5611 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5612 cell = cell.findParent('td', false, true);
5615 if(!cell || typeof(cell) == 'undefined'){
5619 var row = cell.findParent('tr', false, true);
5621 if(!row || typeof(row) == 'undefined'){
5625 var cellIndex = cell.dom.cellIndex;
5626 var rowIndex = this.getRowIndex(row);
5628 if(this.CellSelection){
5629 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5632 if(this.RowSelection){
5633 this.fireEvent('rowclick', this, row, rowIndex, e);
5639 onDblClick : function(e,el)
5641 var cell = Roo.get(el);
5643 if(!cell || (!this.CellSelection && !this.RowSelection)){
5647 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5648 cell = cell.findParent('td', false, true);
5651 if(!cell || typeof(cell) == 'undefined'){
5655 var row = cell.findParent('tr', false, true);
5657 if(!row || typeof(row) == 'undefined'){
5661 var cellIndex = cell.dom.cellIndex;
5662 var rowIndex = this.getRowIndex(row);
5664 if(this.CellSelection){
5665 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5668 if(this.RowSelection){
5669 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5673 sort : function(e,el)
5675 var col = Roo.get(el);
5677 if(!col.hasClass('sortable')){
5681 var sort = col.attr('sort');
5684 if(col.hasClass('glyphicon-arrow-up')){
5688 this.store.sortInfo = {field : sort, direction : dir};
5691 Roo.log("calling footer first");
5692 this.footer.onClick('first');
5695 this.store.load({ params : { start : 0 } });
5699 renderHeader : function()
5708 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5710 var config = cm.config[i];
5715 html: cm.getColumnHeader(i)
5718 if(typeof(config.tooltip) != 'undefined'){
5719 c.tooltip = config.tooltip;
5722 if(typeof(config.colspan) != 'undefined'){
5723 c.colspan = config.colspan;
5726 if(typeof(config.hidden) != 'undefined' && config.hidden){
5727 c.style += ' display:none;';
5730 if(typeof(config.dataIndex) != 'undefined'){
5731 c.sort = config.dataIndex;
5734 if(typeof(config.sortable) != 'undefined' && config.sortable){
5738 if(typeof(config.align) != 'undefined' && config.align.length){
5739 c.style += ' text-align:' + config.align + ';';
5742 if(typeof(config.width) != 'undefined'){
5743 c.style += ' width:' + config.width + 'px;';
5746 if(typeof(config.cls) != 'undefined'){
5747 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5756 renderBody : function()
5766 colspan : this.cm.getColumnCount()
5776 renderFooter : function()
5786 colspan : this.cm.getColumnCount()
5800 Roo.log('ds onload');
5805 var ds = this.store;
5807 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5808 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5810 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5811 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5814 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5815 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5819 var tbody = this.mainBody;
5821 if(ds.getCount() > 0){
5822 ds.data.each(function(d,rowIndex){
5823 var row = this.renderRow(cm, ds, rowIndex);
5825 tbody.createChild(row);
5829 if(row.cellObjects.length){
5830 Roo.each(row.cellObjects, function(r){
5831 _this.renderCellObject(r);
5838 Roo.each(this.el.select('tbody td', true).elements, function(e){
5839 e.on('mouseover', _this.onMouseover, _this);
5842 Roo.each(this.el.select('tbody td', true).elements, function(e){
5843 e.on('mouseout', _this.onMouseout, _this);
5845 this.fireEvent('rowsrendered', this);
5846 //if(this.loadMask){
5847 // this.maskEl.hide();
5852 onUpdate : function(ds,record)
5854 this.refreshRow(record);
5857 onRemove : function(ds, record, index, isUpdate){
5858 if(isUpdate !== true){
5859 this.fireEvent("beforerowremoved", this, index, record);
5861 var bt = this.mainBody.dom;
5863 var rows = this.el.select('tbody > tr', true).elements;
5865 if(typeof(rows[index]) != 'undefined'){
5866 bt.removeChild(rows[index].dom);
5869 // if(bt.rows[index]){
5870 // bt.removeChild(bt.rows[index]);
5873 if(isUpdate !== true){
5874 //this.stripeRows(index);
5875 //this.syncRowHeights(index, index);
5877 this.fireEvent("rowremoved", this, index, record);
5881 onAdd : function(ds, records, rowIndex)
5883 //Roo.log('on Add called');
5884 // - note this does not handle multiple adding very well..
5885 var bt = this.mainBody.dom;
5886 for (var i =0 ; i < records.length;i++) {
5887 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5888 //Roo.log(records[i]);
5889 //Roo.log(this.store.getAt(rowIndex+i));
5890 this.insertRow(this.store, rowIndex + i, false);
5897 refreshRow : function(record){
5898 var ds = this.store, index;
5899 if(typeof record == 'number'){
5901 record = ds.getAt(index);
5903 index = ds.indexOf(record);
5905 this.insertRow(ds, index, true);
5906 this.onRemove(ds, record, index+1, true);
5907 //this.syncRowHeights(index, index);
5909 this.fireEvent("rowupdated", this, index, record);
5912 insertRow : function(dm, rowIndex, isUpdate){
5915 this.fireEvent("beforerowsinserted", this, rowIndex);
5917 //var s = this.getScrollState();
5918 var row = this.renderRow(this.cm, this.store, rowIndex);
5919 // insert before rowIndex..
5920 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5924 if(row.cellObjects.length){
5925 Roo.each(row.cellObjects, function(r){
5926 _this.renderCellObject(r);
5931 this.fireEvent("rowsinserted", this, rowIndex);
5932 //this.syncRowHeights(firstRow, lastRow);
5933 //this.stripeRows(firstRow);
5940 getRowDom : function(rowIndex)
5942 var rows = this.el.select('tbody > tr', true).elements;
5944 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5947 // returns the object tree for a tr..
5950 renderRow : function(cm, ds, rowIndex)
5953 var d = ds.getAt(rowIndex);
5960 var cellObjects = [];
5962 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5963 var config = cm.config[i];
5965 var renderer = cm.getRenderer(i);
5969 if(typeof(renderer) !== 'undefined'){
5970 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5972 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5973 // and are rendered into the cells after the row is rendered - using the id for the element.
5975 if(typeof(value) === 'object'){
5985 rowIndex : rowIndex,
5990 this.fireEvent('rowclass', this, rowcfg);
5994 cls : rowcfg.rowClass,
5996 html: (typeof(value) === 'object') ? '' : value
6003 if(typeof(config.colspan) != 'undefined'){
6004 td.colspan = config.colspan;
6007 if(typeof(config.hidden) != 'undefined' && config.hidden){
6008 td.style += ' display:none;';
6011 if(typeof(config.align) != 'undefined' && config.align.length){
6012 td.style += ' text-align:' + config.align + ';';
6015 if(typeof(config.width) != 'undefined'){
6016 td.style += ' width:' + config.width + 'px;';
6019 if(typeof(config.cursor) != 'undefined'){
6020 td.style += ' cursor:' + config.cursor + ';';
6023 if(typeof(config.cls) != 'undefined'){
6024 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6031 row.cellObjects = cellObjects;
6039 onBeforeLoad : function()
6041 //Roo.log('ds onBeforeLoad');
6045 //if(this.loadMask){
6046 // this.maskEl.show();
6054 this.el.select('tbody', true).first().dom.innerHTML = '';
6057 * Show or hide a row.
6058 * @param {Number} rowIndex to show or hide
6059 * @param {Boolean} state hide
6061 setRowVisibility : function(rowIndex, state)
6063 var bt = this.mainBody.dom;
6065 var rows = this.el.select('tbody > tr', true).elements;
6067 if(typeof(rows[rowIndex]) == 'undefined'){
6070 rows[rowIndex].dom.style.display = state ? '' : 'none';
6074 getSelectionModel : function(){
6076 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6078 return this.selModel;
6081 * Render the Roo.bootstrap object from renderder
6083 renderCellObject : function(r)
6087 var t = r.cfg.render(r.container);
6090 Roo.each(r.cfg.cn, function(c){
6092 container: t.getChildContainer(),
6095 _this.renderCellObject(child);
6100 getRowIndex : function(row)
6104 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6127 * @class Roo.bootstrap.TableCell
6128 * @extends Roo.bootstrap.Component
6129 * Bootstrap TableCell class
6130 * @cfg {String} html cell contain text
6131 * @cfg {String} cls cell class
6132 * @cfg {String} tag cell tag (td|th) default td
6133 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6134 * @cfg {String} align Aligns the content in a cell
6135 * @cfg {String} axis Categorizes cells
6136 * @cfg {String} bgcolor Specifies the background color of a cell
6137 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6138 * @cfg {Number} colspan Specifies the number of columns a cell should span
6139 * @cfg {String} headers Specifies one or more header cells a cell is related to
6140 * @cfg {Number} height Sets the height of a cell
6141 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6142 * @cfg {Number} rowspan Sets the number of rows a cell should span
6143 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6144 * @cfg {String} valign Vertical aligns the content in a cell
6145 * @cfg {Number} width Specifies the width of a cell
6148 * Create a new TableCell
6149 * @param {Object} config The config object
6152 Roo.bootstrap.TableCell = function(config){
6153 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6156 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6176 getAutoCreate : function(){
6177 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6197 cfg.align=this.align
6203 cfg.bgcolor=this.bgcolor
6206 cfg.charoff=this.charoff
6209 cfg.colspan=this.colspan
6212 cfg.headers=this.headers
6215 cfg.height=this.height
6218 cfg.nowrap=this.nowrap
6221 cfg.rowspan=this.rowspan
6224 cfg.scope=this.scope
6227 cfg.valign=this.valign
6230 cfg.width=this.width
6249 * @class Roo.bootstrap.TableRow
6250 * @extends Roo.bootstrap.Component
6251 * Bootstrap TableRow class
6252 * @cfg {String} cls row class
6253 * @cfg {String} align Aligns the content in a table row
6254 * @cfg {String} bgcolor Specifies a background color for a table row
6255 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6256 * @cfg {String} valign Vertical aligns the content in a table row
6259 * Create a new TableRow
6260 * @param {Object} config The config object
6263 Roo.bootstrap.TableRow = function(config){
6264 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6267 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6275 getAutoCreate : function(){
6276 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6286 cfg.align = this.align;
6289 cfg.bgcolor = this.bgcolor;
6292 cfg.charoff = this.charoff;
6295 cfg.valign = this.valign;
6313 * @class Roo.bootstrap.TableBody
6314 * @extends Roo.bootstrap.Component
6315 * Bootstrap TableBody class
6316 * @cfg {String} cls element class
6317 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6318 * @cfg {String} align Aligns the content inside the element
6319 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6320 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6323 * Create a new TableBody
6324 * @param {Object} config The config object
6327 Roo.bootstrap.TableBody = function(config){
6328 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6331 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6339 getAutoCreate : function(){
6340 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6354 cfg.align = this.align;
6357 cfg.charoff = this.charoff;
6360 cfg.valign = this.valign;
6367 // initEvents : function()
6374 // this.store = Roo.factory(this.store, Roo.data);
6375 // this.store.on('load', this.onLoad, this);
6377 // this.store.load();
6381 // onLoad: function ()
6383 // this.fireEvent('load', this);
6393 * Ext JS Library 1.1.1
6394 * Copyright(c) 2006-2007, Ext JS, LLC.
6396 * Originally Released Under LGPL - original licence link has changed is not relivant.
6399 * <script type="text/javascript">
6402 // as we use this in bootstrap.
6403 Roo.namespace('Roo.form');
6405 * @class Roo.form.Action
6406 * Internal Class used to handle form actions
6408 * @param {Roo.form.BasicForm} el The form element or its id
6409 * @param {Object} config Configuration options
6414 // define the action interface
6415 Roo.form.Action = function(form, options){
6417 this.options = options || {};
6420 * Client Validation Failed
6423 Roo.form.Action.CLIENT_INVALID = 'client';
6425 * Server Validation Failed
6428 Roo.form.Action.SERVER_INVALID = 'server';
6430 * Connect to Server Failed
6433 Roo.form.Action.CONNECT_FAILURE = 'connect';
6435 * Reading Data from Server Failed
6438 Roo.form.Action.LOAD_FAILURE = 'load';
6440 Roo.form.Action.prototype = {
6442 failureType : undefined,
6443 response : undefined,
6447 run : function(options){
6452 success : function(response){
6457 handleResponse : function(response){
6461 // default connection failure
6462 failure : function(response){
6464 this.response = response;
6465 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6466 this.form.afterAction(this, false);
6469 processResponse : function(response){
6470 this.response = response;
6471 if(!response.responseText){
6474 this.result = this.handleResponse(response);
6478 // utility functions used internally
6479 getUrl : function(appendParams){
6480 var url = this.options.url || this.form.url || this.form.el.dom.action;
6482 var p = this.getParams();
6484 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6490 getMethod : function(){
6491 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6494 getParams : function(){
6495 var bp = this.form.baseParams;
6496 var p = this.options.params;
6498 if(typeof p == "object"){
6499 p = Roo.urlEncode(Roo.applyIf(p, bp));
6500 }else if(typeof p == 'string' && bp){
6501 p += '&' + Roo.urlEncode(bp);
6504 p = Roo.urlEncode(bp);
6509 createCallback : function(){
6511 success: this.success,
6512 failure: this.failure,
6514 timeout: (this.form.timeout*1000),
6515 upload: this.form.fileUpload ? this.success : undefined
6520 Roo.form.Action.Submit = function(form, options){
6521 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6524 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6527 haveProgress : false,
6528 uploadComplete : false,
6530 // uploadProgress indicator.
6531 uploadProgress : function()
6533 if (!this.form.progressUrl) {
6537 if (!this.haveProgress) {
6538 Roo.MessageBox.progress("Uploading", "Uploading");
6540 if (this.uploadComplete) {
6541 Roo.MessageBox.hide();
6545 this.haveProgress = true;
6547 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6549 var c = new Roo.data.Connection();
6551 url : this.form.progressUrl,
6556 success : function(req){
6557 //console.log(data);
6561 rdata = Roo.decode(req.responseText)
6563 Roo.log("Invalid data from server..");
6567 if (!rdata || !rdata.success) {
6569 Roo.MessageBox.alert(Roo.encode(rdata));
6572 var data = rdata.data;
6574 if (this.uploadComplete) {
6575 Roo.MessageBox.hide();
6580 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6581 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6584 this.uploadProgress.defer(2000,this);
6587 failure: function(data) {
6588 Roo.log('progress url failed ');
6599 // run get Values on the form, so it syncs any secondary forms.
6600 this.form.getValues();
6602 var o = this.options;
6603 var method = this.getMethod();
6604 var isPost = method == 'POST';
6605 if(o.clientValidation === false || this.form.isValid()){
6607 if (this.form.progressUrl) {
6608 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6609 (new Date() * 1) + '' + Math.random());
6614 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6615 form:this.form.el.dom,
6616 url:this.getUrl(!isPost),
6618 params:isPost ? this.getParams() : null,
6619 isUpload: this.form.fileUpload
6622 this.uploadProgress();
6624 }else if (o.clientValidation !== false){ // client validation failed
6625 this.failureType = Roo.form.Action.CLIENT_INVALID;
6626 this.form.afterAction(this, false);
6630 success : function(response)
6632 this.uploadComplete= true;
6633 if (this.haveProgress) {
6634 Roo.MessageBox.hide();
6638 var result = this.processResponse(response);
6639 if(result === true || result.success){
6640 this.form.afterAction(this, true);
6644 this.form.markInvalid(result.errors);
6645 this.failureType = Roo.form.Action.SERVER_INVALID;
6647 this.form.afterAction(this, false);
6649 failure : function(response)
6651 this.uploadComplete= true;
6652 if (this.haveProgress) {
6653 Roo.MessageBox.hide();
6656 this.response = response;
6657 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6658 this.form.afterAction(this, false);
6661 handleResponse : function(response){
6662 if(this.form.errorReader){
6663 var rs = this.form.errorReader.read(response);
6666 for(var i = 0, len = rs.records.length; i < len; i++) {
6667 var r = rs.records[i];
6671 if(errors.length < 1){
6675 success : rs.success,
6681 ret = Roo.decode(response.responseText);
6685 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6695 Roo.form.Action.Load = function(form, options){
6696 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6697 this.reader = this.form.reader;
6700 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6705 Roo.Ajax.request(Roo.apply(
6706 this.createCallback(), {
6707 method:this.getMethod(),
6708 url:this.getUrl(false),
6709 params:this.getParams()
6713 success : function(response){
6715 var result = this.processResponse(response);
6716 if(result === true || !result.success || !result.data){
6717 this.failureType = Roo.form.Action.LOAD_FAILURE;
6718 this.form.afterAction(this, false);
6721 this.form.clearInvalid();
6722 this.form.setValues(result.data);
6723 this.form.afterAction(this, true);
6726 handleResponse : function(response){
6727 if(this.form.reader){
6728 var rs = this.form.reader.read(response);
6729 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6731 success : rs.success,
6735 return Roo.decode(response.responseText);
6739 Roo.form.Action.ACTION_TYPES = {
6740 'load' : Roo.form.Action.Load,
6741 'submit' : Roo.form.Action.Submit
6750 * @class Roo.bootstrap.Form
6751 * @extends Roo.bootstrap.Component
6752 * Bootstrap Form class
6753 * @cfg {String} method GET | POST (default POST)
6754 * @cfg {String} labelAlign top | left (default top)
6755 * @cfg {String} align left | right - for navbars
6756 * @cfg {Boolean} loadMask load mask when submit (default true)
6761 * @param {Object} config The config object
6765 Roo.bootstrap.Form = function(config){
6766 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6769 * @event clientvalidation
6770 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6771 * @param {Form} this
6772 * @param {Boolean} valid true if the form has passed client-side validation
6774 clientvalidation: true,
6776 * @event beforeaction
6777 * Fires before any action is performed. Return false to cancel the action.
6778 * @param {Form} this
6779 * @param {Action} action The action to be performed
6783 * @event actionfailed
6784 * Fires when an action fails.
6785 * @param {Form} this
6786 * @param {Action} action The action that failed
6788 actionfailed : true,
6790 * @event actioncomplete
6791 * Fires when an action is completed.
6792 * @param {Form} this
6793 * @param {Action} action The action that completed
6795 actioncomplete : true
6800 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6803 * @cfg {String} method
6804 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6809 * The URL to use for form actions if one isn't supplied in the action options.
6812 * @cfg {Boolean} fileUpload
6813 * Set to true if this form is a file upload.
6817 * @cfg {Object} baseParams
6818 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6822 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6826 * @cfg {Sting} align (left|right) for navbar forms
6831 activeAction : null,
6834 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6835 * element by passing it or its id or mask the form itself by passing in true.
6838 waitMsgTarget : false,
6842 getAutoCreate : function(){
6846 method : this.method || 'POST',
6847 id : this.id || Roo.id(),
6850 if (this.parent().xtype.match(/^Nav/)) {
6851 cfg.cls = 'navbar-form navbar-' + this.align;
6855 if (this.labelAlign == 'left' ) {
6856 cfg.cls += ' form-horizontal';
6862 initEvents : function()
6864 this.el.on('submit', this.onSubmit, this);
6865 // this was added as random key presses on the form where triggering form submit.
6866 this.el.on('keypress', function(e) {
6867 if (e.getCharCode() != 13) {
6870 // we might need to allow it for textareas.. and some other items.
6871 // check e.getTarget().
6873 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6877 Roo.log("keypress blocked");
6885 onSubmit : function(e){
6890 * Returns true if client-side validation on the form is successful.
6893 isValid : function(){
6894 var items = this.getItems();
6896 items.each(function(f){
6905 * Returns true if any fields in this form have changed since their original load.
6908 isDirty : function(){
6910 var items = this.getItems();
6911 items.each(function(f){
6921 * Performs a predefined action (submit or load) or custom actions you define on this form.
6922 * @param {String} actionName The name of the action type
6923 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6924 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6925 * accept other config options):
6927 Property Type Description
6928 ---------------- --------------- ----------------------------------------------------------------------------------
6929 url String The url for the action (defaults to the form's url)
6930 method String The form method to use (defaults to the form's method, or POST if not defined)
6931 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6932 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6933 validate the form on the client (defaults to false)
6935 * @return {BasicForm} this
6937 doAction : function(action, options){
6938 if(typeof action == 'string'){
6939 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6941 if(this.fireEvent('beforeaction', this, action) !== false){
6942 this.beforeAction(action);
6943 action.run.defer(100, action);
6949 beforeAction : function(action){
6950 var o = action.options;
6953 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6955 // not really supported yet.. ??
6957 //if(this.waitMsgTarget === true){
6958 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6959 //}else if(this.waitMsgTarget){
6960 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6961 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6963 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6969 afterAction : function(action, success){
6970 this.activeAction = null;
6971 var o = action.options;
6973 //if(this.waitMsgTarget === true){
6975 //}else if(this.waitMsgTarget){
6976 // this.waitMsgTarget.unmask();
6978 // Roo.MessageBox.updateProgress(1);
6979 // Roo.MessageBox.hide();
6986 Roo.callback(o.success, o.scope, [this, action]);
6987 this.fireEvent('actioncomplete', this, action);
6991 // failure condition..
6992 // we have a scenario where updates need confirming.
6993 // eg. if a locking scenario exists..
6994 // we look for { errors : { needs_confirm : true }} in the response.
6996 (typeof(action.result) != 'undefined') &&
6997 (typeof(action.result.errors) != 'undefined') &&
6998 (typeof(action.result.errors.needs_confirm) != 'undefined')
7001 Roo.log("not supported yet");
7004 Roo.MessageBox.confirm(
7005 "Change requires confirmation",
7006 action.result.errorMsg,
7011 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7021 Roo.callback(o.failure, o.scope, [this, action]);
7022 // show an error message if no failed handler is set..
7023 if (!this.hasListener('actionfailed')) {
7024 Roo.log("need to add dialog support");
7026 Roo.MessageBox.alert("Error",
7027 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7028 action.result.errorMsg :
7029 "Saving Failed, please check your entries or try again"
7034 this.fireEvent('actionfailed', this, action);
7039 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7040 * @param {String} id The value to search for
7043 findField : function(id){
7044 var items = this.getItems();
7045 var field = items.get(id);
7047 items.each(function(f){
7048 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7055 return field || null;
7058 * Mark fields in this form invalid in bulk.
7059 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7060 * @return {BasicForm} this
7062 markInvalid : function(errors){
7063 if(errors instanceof Array){
7064 for(var i = 0, len = errors.length; i < len; i++){
7065 var fieldError = errors[i];
7066 var f = this.findField(fieldError.id);
7068 f.markInvalid(fieldError.msg);
7074 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7075 field.markInvalid(errors[id]);
7079 //Roo.each(this.childForms || [], function (f) {
7080 // f.markInvalid(errors);
7087 * Set values for fields in this form in bulk.
7088 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7089 * @return {BasicForm} this
7091 setValues : function(values){
7092 if(values instanceof Array){ // array of objects
7093 for(var i = 0, len = values.length; i < len; i++){
7095 var f = this.findField(v.id);
7097 f.setValue(v.value);
7098 if(this.trackResetOnLoad){
7099 f.originalValue = f.getValue();
7103 }else{ // object hash
7106 if(typeof values[id] != 'function' && (field = this.findField(id))){
7108 if (field.setFromData &&
7110 field.displayField &&
7111 // combos' with local stores can
7112 // be queried via setValue()
7113 // to set their value..
7114 (field.store && !field.store.isLocal)
7118 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7119 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7120 field.setFromData(sd);
7123 field.setValue(values[id]);
7127 if(this.trackResetOnLoad){
7128 field.originalValue = field.getValue();
7134 //Roo.each(this.childForms || [], function (f) {
7135 // f.setValues(values);
7142 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7143 * they are returned as an array.
7144 * @param {Boolean} asString
7147 getValues : function(asString){
7148 //if (this.childForms) {
7149 // copy values from the child forms
7150 // Roo.each(this.childForms, function (f) {
7151 // this.setValues(f.getValues());
7157 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7158 if(asString === true){
7161 return Roo.urlDecode(fs);
7165 * Returns the fields in this form as an object with key/value pairs.
7166 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7169 getFieldValues : function(with_hidden)
7171 var items = this.getItems();
7173 items.each(function(f){
7177 var v = f.getValue();
7178 if (f.inputType =='radio') {
7179 if (typeof(ret[f.getName()]) == 'undefined') {
7180 ret[f.getName()] = ''; // empty..
7183 if (!f.el.dom.checked) {
7191 // not sure if this supported any more..
7192 if ((typeof(v) == 'object') && f.getRawValue) {
7193 v = f.getRawValue() ; // dates..
7195 // combo boxes where name != hiddenName...
7196 if (f.name != f.getName()) {
7197 ret[f.name] = f.getRawValue();
7199 ret[f.getName()] = v;
7206 * Clears all invalid messages in this form.
7207 * @return {BasicForm} this
7209 clearInvalid : function(){
7210 var items = this.getItems();
7212 items.each(function(f){
7223 * @return {BasicForm} this
7226 var items = this.getItems();
7227 items.each(function(f){
7231 Roo.each(this.childForms || [], function (f) {
7238 getItems : function()
7240 var r=new Roo.util.MixedCollection(false, function(o){
7241 return o.id || (o.id = Roo.id());
7243 var iter = function(el) {
7250 Roo.each(el.items,function(e) {
7270 * Ext JS Library 1.1.1
7271 * Copyright(c) 2006-2007, Ext JS, LLC.
7273 * Originally Released Under LGPL - original licence link has changed is not relivant.
7276 * <script type="text/javascript">
7279 * @class Roo.form.VTypes
7280 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7283 Roo.form.VTypes = function(){
7284 // closure these in so they are only created once.
7285 var alpha = /^[a-zA-Z_]+$/;
7286 var alphanum = /^[a-zA-Z0-9_]+$/;
7287 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7288 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7290 // All these messages and functions are configurable
7293 * The function used to validate email addresses
7294 * @param {String} value The email address
7296 'email' : function(v){
7297 return email.test(v);
7300 * The error text to display when the email validation function returns false
7303 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7305 * The keystroke filter mask to be applied on email input
7308 'emailMask' : /[a-z0-9_\.\-@]/i,
7311 * The function used to validate URLs
7312 * @param {String} value The URL
7314 'url' : function(v){
7318 * The error text to display when the url validation function returns false
7321 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7324 * The function used to validate alpha values
7325 * @param {String} value The value
7327 'alpha' : function(v){
7328 return alpha.test(v);
7331 * The error text to display when the alpha validation function returns false
7334 'alphaText' : 'This field should only contain letters and _',
7336 * The keystroke filter mask to be applied on alpha input
7339 'alphaMask' : /[a-z_]/i,
7342 * The function used to validate alphanumeric values
7343 * @param {String} value The value
7345 'alphanum' : function(v){
7346 return alphanum.test(v);
7349 * The error text to display when the alphanumeric validation function returns false
7352 'alphanumText' : 'This field should only contain letters, numbers and _',
7354 * The keystroke filter mask to be applied on alphanumeric input
7357 'alphanumMask' : /[a-z0-9_]/i
7367 * @class Roo.bootstrap.Input
7368 * @extends Roo.bootstrap.Component
7369 * Bootstrap Input class
7370 * @cfg {Boolean} disabled is it disabled
7371 * @cfg {String} fieldLabel - the label associated
7372 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7373 * @cfg {String} name name of the input
7374 * @cfg {string} fieldLabel - the label associated
7375 * @cfg {string} inputType - input / file submit ...
7376 * @cfg {string} placeholder - placeholder to put in text.
7377 * @cfg {string} before - input group add on before
7378 * @cfg {string} after - input group add on after
7379 * @cfg {string} size - (lg|sm) or leave empty..
7380 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7381 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7382 * @cfg {Number} md colspan out of 12 for computer-sized screens
7383 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7384 * @cfg {string} value default value of the input
7385 * @cfg {Number} labelWidth set the width of label (0-12)
7386 * @cfg {String} labelAlign (top|left)
7387 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7388 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7390 * @cfg {String} align (left|center|right) Default left
7395 * Create a new Input
7396 * @param {Object} config The config object
7399 Roo.bootstrap.Input = function(config){
7400 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7405 * Fires when this field receives input focus.
7406 * @param {Roo.form.Field} this
7411 * Fires when this field loses input focus.
7412 * @param {Roo.form.Field} this
7417 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7418 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7419 * @param {Roo.form.Field} this
7420 * @param {Roo.EventObject} e The event object
7425 * Fires just before the field blurs if the field value has changed.
7426 * @param {Roo.form.Field} this
7427 * @param {Mixed} newValue The new value
7428 * @param {Mixed} oldValue The original value
7433 * Fires after the field has been marked as invalid.
7434 * @param {Roo.form.Field} this
7435 * @param {String} msg The validation message
7440 * Fires after the field has been validated with no errors.
7441 * @param {Roo.form.Field} this
7446 * Fires after the key up
7447 * @param {Roo.form.Field} this
7448 * @param {Roo.EventObject} e The event Object
7454 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7456 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7457 automatic validation (defaults to "keyup").
7459 validationEvent : "keyup",
7461 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7463 validateOnBlur : true,
7465 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7467 validationDelay : 250,
7469 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7471 focusClass : "x-form-focus", // not needed???
7475 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7477 invalidClass : "has-warning",
7480 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7482 validClass : "has-success",
7485 * @cfg {Boolean} hasFeedback (true|false) default true
7490 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7492 invalidFeedbackClass : "glyphicon-warning-sign",
7495 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7497 validFeedbackClass : "glyphicon-ok",
7500 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7502 selectOnFocus : false,
7505 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7509 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7514 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7516 disableKeyFilter : false,
7519 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7523 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7527 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7529 blankText : "This field is required",
7532 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7536 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7538 maxLength : Number.MAX_VALUE,
7540 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7542 minLengthText : "The minimum length for this field is {0}",
7544 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7546 maxLengthText : "The maximum length for this field is {0}",
7550 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7551 * If available, this function will be called only after the basic validators all return true, and will be passed the
7552 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7556 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7557 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7558 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7562 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7566 autocomplete: false,
7585 formatedValue : false,
7587 parentLabelAlign : function()
7590 while (parent.parent()) {
7591 parent = parent.parent();
7592 if (typeof(parent.labelAlign) !='undefined') {
7593 return parent.labelAlign;
7600 getAutoCreate : function(){
7602 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7608 if(this.inputType != 'hidden'){
7609 cfg.cls = 'form-group' //input-group
7615 type : this.inputType,
7617 cls : 'form-control',
7618 placeholder : this.placeholder || '',
7619 autocomplete : this.autocomplete || 'new-password'
7624 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7627 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7628 input.maxLength = this.maxLength;
7631 if (this.disabled) {
7632 input.disabled=true;
7635 if (this.readOnly) {
7636 input.readonly=true;
7640 input.name = this.name;
7643 input.cls += ' input-' + this.size;
7646 ['xs','sm','md','lg'].map(function(size){
7647 if (settings[size]) {
7648 cfg.cls += ' col-' + size + '-' + settings[size];
7652 var inputblock = input;
7656 cls: 'glyphicon form-control-feedback'
7659 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7662 cls : 'has-feedback',
7670 if (this.before || this.after) {
7673 cls : 'input-group',
7677 if (this.before && typeof(this.before) == 'string') {
7679 inputblock.cn.push({
7681 cls : 'roo-input-before input-group-addon',
7685 if (this.before && typeof(this.before) == 'object') {
7686 this.before = Roo.factory(this.before);
7687 Roo.log(this.before);
7688 inputblock.cn.push({
7690 cls : 'roo-input-before input-group-' +
7691 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7695 inputblock.cn.push(input);
7697 if (this.after && typeof(this.after) == 'string') {
7698 inputblock.cn.push({
7700 cls : 'roo-input-after input-group-addon',
7704 if (this.after && typeof(this.after) == 'object') {
7705 this.after = Roo.factory(this.after);
7706 Roo.log(this.after);
7707 inputblock.cn.push({
7709 cls : 'roo-input-after input-group-' +
7710 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7714 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7715 inputblock.cls += ' has-feedback';
7716 inputblock.cn.push(feedback);
7720 if (align ==='left' && this.fieldLabel.length) {
7721 Roo.log("left and has label");
7727 cls : 'control-label col-sm-' + this.labelWidth,
7728 html : this.fieldLabel
7732 cls : "col-sm-" + (12 - this.labelWidth),
7739 } else if ( this.fieldLabel.length) {
7745 //cls : 'input-group-addon',
7746 html : this.fieldLabel
7756 Roo.log(" no label && no align");
7765 Roo.log('input-parentType: ' + this.parentType);
7767 if (this.parentType === 'Navbar' && this.parent().bar) {
7768 cfg.cls += ' navbar-form';
7776 * return the real input element.
7778 inputEl: function ()
7780 return this.el.select('input.form-control',true).first();
7783 tooltipEl : function()
7785 return this.inputEl();
7788 setDisabled : function(v)
7790 var i = this.inputEl().dom;
7792 i.removeAttribute('disabled');
7796 i.setAttribute('disabled','true');
7798 initEvents : function()
7801 this.inputEl().on("keydown" , this.fireKey, this);
7802 this.inputEl().on("focus", this.onFocus, this);
7803 this.inputEl().on("blur", this.onBlur, this);
7805 this.inputEl().relayEvent('keyup', this);
7807 // reference to original value for reset
7808 this.originalValue = this.getValue();
7809 //Roo.form.TextField.superclass.initEvents.call(this);
7810 if(this.validationEvent == 'keyup'){
7811 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7812 this.inputEl().on('keyup', this.filterValidation, this);
7814 else if(this.validationEvent !== false){
7815 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7818 if(this.selectOnFocus){
7819 this.on("focus", this.preFocus, this);
7822 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7823 this.inputEl().on("keypress", this.filterKeys, this);
7826 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7827 this.el.on("click", this.autoSize, this);
7830 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7831 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7834 if (typeof(this.before) == 'object') {
7835 this.before.render(this.el.select('.roo-input-before',true).first());
7837 if (typeof(this.after) == 'object') {
7838 this.after.render(this.el.select('.roo-input-after',true).first());
7843 filterValidation : function(e){
7844 if(!e.isNavKeyPress()){
7845 this.validationTask.delay(this.validationDelay);
7849 * Validates the field value
7850 * @return {Boolean} True if the value is valid, else false
7852 validate : function(){
7853 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7854 if(this.disabled || this.validateValue(this.getRawValue())){
7865 * Validates a value according to the field's validation rules and marks the field as invalid
7866 * if the validation fails
7867 * @param {Mixed} value The value to validate
7868 * @return {Boolean} True if the value is valid, else false
7870 validateValue : function(value){
7871 if(value.length < 1) { // if it's blank
7872 if(this.allowBlank){
7878 if(value.length < this.minLength){
7881 if(value.length > this.maxLength){
7885 var vt = Roo.form.VTypes;
7886 if(!vt[this.vtype](value, this)){
7890 if(typeof this.validator == "function"){
7891 var msg = this.validator(value);
7897 if(this.regex && !this.regex.test(value)){
7907 fireKey : function(e){
7908 //Roo.log('field ' + e.getKey());
7909 if(e.isNavKeyPress()){
7910 this.fireEvent("specialkey", this, e);
7913 focus : function (selectText){
7915 this.inputEl().focus();
7916 if(selectText === true){
7917 this.inputEl().dom.select();
7923 onFocus : function(){
7924 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7925 // this.el.addClass(this.focusClass);
7928 this.hasFocus = true;
7929 this.startValue = this.getValue();
7930 this.fireEvent("focus", this);
7934 beforeBlur : Roo.emptyFn,
7938 onBlur : function(){
7940 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7941 //this.el.removeClass(this.focusClass);
7943 this.hasFocus = false;
7944 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7947 var v = this.getValue();
7948 if(String(v) !== String(this.startValue)){
7949 this.fireEvent('change', this, v, this.startValue);
7951 this.fireEvent("blur", this);
7955 * Resets the current field value to the originally loaded value and clears any validation messages
7958 this.setValue(this.originalValue);
7962 * Returns the name of the field
7963 * @return {Mixed} name The name field
7965 getName: function(){
7969 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7970 * @return {Mixed} value The field value
7972 getValue : function(){
7974 var v = this.inputEl().getValue();
7979 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7980 * @return {Mixed} value The field value
7982 getRawValue : function(){
7983 var v = this.inputEl().getValue();
7989 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7990 * @param {Mixed} value The value to set
7992 setRawValue : function(v){
7993 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7996 selectText : function(start, end){
7997 var v = this.getRawValue();
7999 start = start === undefined ? 0 : start;
8000 end = end === undefined ? v.length : end;
8001 var d = this.inputEl().dom;
8002 if(d.setSelectionRange){
8003 d.setSelectionRange(start, end);
8004 }else if(d.createTextRange){
8005 var range = d.createTextRange();
8006 range.moveStart("character", start);
8007 range.moveEnd("character", v.length-end);
8014 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8015 * @param {Mixed} value The value to set
8017 setValue : function(v){
8020 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8026 processValue : function(value){
8027 if(this.stripCharsRe){
8028 var newValue = value.replace(this.stripCharsRe, '');
8029 if(newValue !== value){
8030 this.setRawValue(newValue);
8037 preFocus : function(){
8039 if(this.selectOnFocus){
8040 this.inputEl().dom.select();
8043 filterKeys : function(e){
8045 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8048 var c = e.getCharCode(), cc = String.fromCharCode(c);
8049 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8052 if(!this.maskRe.test(cc)){
8057 * Clear any invalid styles/messages for this field
8059 clearInvalid : function(){
8061 if(!this.el || this.preventMark){ // not rendered
8064 this.el.removeClass(this.invalidClass);
8066 this.fireEvent('valid', this);
8070 * Mark this field as valid
8072 markValid : function(){
8073 if(!this.el || this.preventMark){ // not rendered
8077 this.el.removeClass([this.invalidClass, this.validClass]);
8079 if(this.disabled || this.allowBlank){
8083 this.el.addClass(this.validClass);
8085 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8087 var feedback = this.el.select('.form-control-feedback', true).first();
8090 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8091 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8096 this.fireEvent('valid', this);
8100 * Mark this field as invalid
8101 * @param {String} msg The validation message
8103 markInvalid : function(msg){
8104 if(!this.el || this.preventMark){ // not rendered
8108 this.el.removeClass([this.invalidClass, this.validClass]);
8110 if(this.disabled || this.allowBlank){
8114 this.el.addClass(this.invalidClass);
8116 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8118 var feedback = this.el.select('.form-control-feedback', true).first();
8121 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8123 if(this.getValue().length){
8124 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8131 this.fireEvent('invalid', this, msg);
8134 SafariOnKeyDown : function(event)
8136 // this is a workaround for a password hang bug on chrome/ webkit.
8138 var isSelectAll = false;
8140 if(this.inputEl().dom.selectionEnd > 0){
8141 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8143 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8144 event.preventDefault();
8149 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8151 event.preventDefault();
8152 // this is very hacky as keydown always get's upper case.
8154 var cc = String.fromCharCode(event.getCharCode());
8155 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8159 adjustWidth : function(tag, w){
8160 tag = tag.toLowerCase();
8161 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8162 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8166 if(tag == 'textarea'){
8169 }else if(Roo.isOpera){
8173 if(tag == 'textarea'){
8192 * @class Roo.bootstrap.TextArea
8193 * @extends Roo.bootstrap.Input
8194 * Bootstrap TextArea class
8195 * @cfg {Number} cols Specifies the visible width of a text area
8196 * @cfg {Number} rows Specifies the visible number of lines in a text area
8197 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8198 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8199 * @cfg {string} html text
8202 * Create a new TextArea
8203 * @param {Object} config The config object
8206 Roo.bootstrap.TextArea = function(config){
8207 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8211 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8221 getAutoCreate : function(){
8223 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8234 value : this.value || '',
8235 html: this.html || '',
8236 cls : 'form-control',
8237 placeholder : this.placeholder || ''
8241 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8242 input.maxLength = this.maxLength;
8246 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8250 input.cols = this.cols;
8253 if (this.readOnly) {
8254 input.readonly = true;
8258 input.name = this.name;
8262 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8266 ['xs','sm','md','lg'].map(function(size){
8267 if (settings[size]) {
8268 cfg.cls += ' col-' + size + '-' + settings[size];
8272 var inputblock = input;
8274 if(this.hasFeedback && !this.allowBlank){
8278 cls: 'glyphicon form-control-feedback'
8282 cls : 'has-feedback',
8291 if (this.before || this.after) {
8294 cls : 'input-group',
8298 inputblock.cn.push({
8300 cls : 'input-group-addon',
8305 inputblock.cn.push(input);
8307 if(this.hasFeedback && !this.allowBlank){
8308 inputblock.cls += ' has-feedback';
8309 inputblock.cn.push(feedback);
8313 inputblock.cn.push({
8315 cls : 'input-group-addon',
8322 if (align ==='left' && this.fieldLabel.length) {
8323 Roo.log("left and has label");
8329 cls : 'control-label col-sm-' + this.labelWidth,
8330 html : this.fieldLabel
8334 cls : "col-sm-" + (12 - this.labelWidth),
8341 } else if ( this.fieldLabel.length) {
8347 //cls : 'input-group-addon',
8348 html : this.fieldLabel
8358 Roo.log(" no label && no align");
8368 if (this.disabled) {
8369 input.disabled=true;
8376 * return the real textarea element.
8378 inputEl: function ()
8380 return this.el.select('textarea.form-control',true).first();
8388 * trigger field - base class for combo..
8393 * @class Roo.bootstrap.TriggerField
8394 * @extends Roo.bootstrap.Input
8395 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8396 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8397 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8398 * for which you can provide a custom implementation. For example:
8400 var trigger = new Roo.bootstrap.TriggerField();
8401 trigger.onTriggerClick = myTriggerFn;
8402 trigger.applyTo('my-field');
8405 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8406 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8407 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8408 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8409 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8412 * Create a new TriggerField.
8413 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8414 * to the base TextField)
8416 Roo.bootstrap.TriggerField = function(config){
8417 this.mimicing = false;
8418 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8421 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8423 * @cfg {String} triggerClass A CSS class to apply to the trigger
8426 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8431 * @cfg {Boolean} removable (true|false) special filter default false
8435 /** @cfg {Boolean} grow @hide */
8436 /** @cfg {Number} growMin @hide */
8437 /** @cfg {Number} growMax @hide */
8443 autoSize: Roo.emptyFn,
8450 actionMode : 'wrap',
8455 getAutoCreate : function(){
8457 var align = this.labelAlign || this.parentLabelAlign();
8462 cls: 'form-group' //input-group
8469 type : this.inputType,
8470 cls : 'form-control',
8471 autocomplete: 'new-password',
8472 placeholder : this.placeholder || ''
8476 input.name = this.name;
8479 input.cls += ' input-' + this.size;
8482 if (this.disabled) {
8483 input.disabled=true;
8486 var inputblock = input;
8488 if(this.hasFeedback && !this.allowBlank){
8492 cls: 'glyphicon form-control-feedback'
8495 if(this.removable && !this.editable && !this.tickable){
8497 cls : 'has-feedback',
8503 cls : 'roo-combo-removable-btn close'
8510 cls : 'has-feedback',
8519 if(this.removable && !this.editable && !this.tickable){
8521 cls : 'roo-removable',
8527 cls : 'roo-combo-removable-btn close'
8534 if (this.before || this.after) {
8537 cls : 'input-group',
8541 inputblock.cn.push({
8543 cls : 'input-group-addon',
8548 inputblock.cn.push(input);
8550 if(this.hasFeedback && !this.allowBlank){
8551 inputblock.cls += ' has-feedback';
8552 inputblock.cn.push(feedback);
8556 inputblock.cn.push({
8558 cls : 'input-group-addon',
8571 cls: 'form-hidden-field'
8579 Roo.log('multiple');
8587 cls: 'form-hidden-field'
8591 cls: 'select2-choices',
8595 cls: 'select2-search-field',
8608 cls: 'select2-container input-group',
8613 // cls: 'typeahead typeahead-long dropdown-menu',
8614 // style: 'display:none'
8619 if(!this.multiple && this.showToggleBtn){
8625 if (this.caret != false) {
8628 cls: 'fa fa-' + this.caret
8635 cls : 'input-group-addon btn dropdown-toggle',
8640 cls: 'combobox-clear',
8654 combobox.cls += ' select2-container-multi';
8657 if (align ==='left' && this.fieldLabel.length) {
8659 Roo.log("left and has label");
8665 cls : 'control-label col-sm-' + this.labelWidth,
8666 html : this.fieldLabel
8670 cls : "col-sm-" + (12 - this.labelWidth),
8677 } else if ( this.fieldLabel.length) {
8683 //cls : 'input-group-addon',
8684 html : this.fieldLabel
8694 Roo.log(" no label && no align");
8701 ['xs','sm','md','lg'].map(function(size){
8702 if (settings[size]) {
8703 cfg.cls += ' col-' + size + '-' + settings[size];
8714 onResize : function(w, h){
8715 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8716 // if(typeof w == 'number'){
8717 // var x = w - this.trigger.getWidth();
8718 // this.inputEl().setWidth(this.adjustWidth('input', x));
8719 // this.trigger.setStyle('left', x+'px');
8724 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8727 getResizeEl : function(){
8728 return this.inputEl();
8732 getPositionEl : function(){
8733 return this.inputEl();
8737 alignErrorIcon : function(){
8738 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8742 initEvents : function(){
8746 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8747 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8748 if(!this.multiple && this.showToggleBtn){
8749 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8750 if(this.hideTrigger){
8751 this.trigger.setDisplayed(false);
8753 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8757 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8760 if(this.removable && !this.editable && !this.tickable){
8761 var close = this.closeTriggerEl();
8764 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8765 close.on('click', this.removeBtnClick, this, close);
8769 //this.trigger.addClassOnOver('x-form-trigger-over');
8770 //this.trigger.addClassOnClick('x-form-trigger-click');
8773 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8777 closeTriggerEl : function()
8779 var close = this.el.select('.roo-combo-removable-btn', true).first();
8780 return close ? close : false;
8783 removeBtnClick : function(e, h, el)
8787 this.fireEvent("remove", this);
8790 createList : function()
8792 this.list = Roo.get(document.body).createChild({
8794 cls: 'typeahead typeahead-long dropdown-menu',
8795 style: 'display:none'
8798 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8803 initTrigger : function(){
8808 onDestroy : function(){
8810 this.trigger.removeAllListeners();
8811 // this.trigger.remove();
8814 // this.wrap.remove();
8816 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8820 onFocus : function(){
8821 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8824 this.wrap.addClass('x-trigger-wrap-focus');
8825 this.mimicing = true;
8826 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8827 if(this.monitorTab){
8828 this.el.on("keydown", this.checkTab, this);
8835 checkTab : function(e){
8836 if(e.getKey() == e.TAB){
8842 onBlur : function(){
8847 mimicBlur : function(e, t){
8849 if(!this.wrap.contains(t) && this.validateBlur()){
8856 triggerBlur : function(){
8857 this.mimicing = false;
8858 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8859 if(this.monitorTab){
8860 this.el.un("keydown", this.checkTab, this);
8862 //this.wrap.removeClass('x-trigger-wrap-focus');
8863 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8867 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8868 validateBlur : function(e, t){
8873 onDisable : function(){
8874 this.inputEl().dom.disabled = true;
8875 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8877 // this.wrap.addClass('x-item-disabled');
8882 onEnable : function(){
8883 this.inputEl().dom.disabled = false;
8884 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8886 // this.el.removeClass('x-item-disabled');
8891 onShow : function(){
8892 var ae = this.getActionEl();
8895 ae.dom.style.display = '';
8896 ae.dom.style.visibility = 'visible';
8902 onHide : function(){
8903 var ae = this.getActionEl();
8904 ae.dom.style.display = 'none';
8908 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8909 * by an implementing function.
8911 * @param {EventObject} e
8913 onTriggerClick : Roo.emptyFn
8917 * Ext JS Library 1.1.1
8918 * Copyright(c) 2006-2007, Ext JS, LLC.
8920 * Originally Released Under LGPL - original licence link has changed is not relivant.
8923 * <script type="text/javascript">
8928 * @class Roo.data.SortTypes
8930 * Defines the default sorting (casting?) comparison functions used when sorting data.
8932 Roo.data.SortTypes = {
8934 * Default sort that does nothing
8935 * @param {Mixed} s The value being converted
8936 * @return {Mixed} The comparison value
8943 * The regular expression used to strip tags
8947 stripTagsRE : /<\/?[^>]+>/gi,
8950 * Strips all HTML tags to sort on text only
8951 * @param {Mixed} s The value being converted
8952 * @return {String} The comparison value
8954 asText : function(s){
8955 return String(s).replace(this.stripTagsRE, "");
8959 * Strips all HTML tags to sort on text only - Case insensitive
8960 * @param {Mixed} s The value being converted
8961 * @return {String} The comparison value
8963 asUCText : function(s){
8964 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8968 * Case insensitive string
8969 * @param {Mixed} s The value being converted
8970 * @return {String} The comparison value
8972 asUCString : function(s) {
8973 return String(s).toUpperCase();
8978 * @param {Mixed} s The value being converted
8979 * @return {Number} The comparison value
8981 asDate : function(s) {
8985 if(s instanceof Date){
8988 return Date.parse(String(s));
8993 * @param {Mixed} s The value being converted
8994 * @return {Float} The comparison value
8996 asFloat : function(s) {
8997 var val = parseFloat(String(s).replace(/,/g, ""));
8998 if(isNaN(val)) val = 0;
9004 * @param {Mixed} s The value being converted
9005 * @return {Number} The comparison value
9007 asInt : function(s) {
9008 var val = parseInt(String(s).replace(/,/g, ""));
9009 if(isNaN(val)) val = 0;
9014 * Ext JS Library 1.1.1
9015 * Copyright(c) 2006-2007, Ext JS, LLC.
9017 * Originally Released Under LGPL - original licence link has changed is not relivant.
9020 * <script type="text/javascript">
9024 * @class Roo.data.Record
9025 * Instances of this class encapsulate both record <em>definition</em> information, and record
9026 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9027 * to access Records cached in an {@link Roo.data.Store} object.<br>
9029 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9030 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9033 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9035 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9036 * {@link #create}. The parameters are the same.
9037 * @param {Array} data An associative Array of data values keyed by the field name.
9038 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9039 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9040 * not specified an integer id is generated.
9042 Roo.data.Record = function(data, id){
9043 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9048 * Generate a constructor for a specific record layout.
9049 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9050 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9051 * Each field definition object may contain the following properties: <ul>
9052 * <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,
9053 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9054 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9055 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9056 * is being used, then this is a string containing the javascript expression to reference the data relative to
9057 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9058 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9059 * this may be omitted.</p></li>
9060 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9061 * <ul><li>auto (Default, implies no conversion)</li>
9066 * <li>date</li></ul></p></li>
9067 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9068 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9069 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9070 * by the Reader into an object that will be stored in the Record. It is passed the
9071 * following parameters:<ul>
9072 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9074 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9076 * <br>usage:<br><pre><code>
9077 var TopicRecord = Roo.data.Record.create(
9078 {name: 'title', mapping: 'topic_title'},
9079 {name: 'author', mapping: 'username'},
9080 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9081 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9082 {name: 'lastPoster', mapping: 'user2'},
9083 {name: 'excerpt', mapping: 'post_text'}
9086 var myNewRecord = new TopicRecord({
9087 title: 'Do my job please',
9090 lastPost: new Date(),
9091 lastPoster: 'Animal',
9092 excerpt: 'No way dude!'
9094 myStore.add(myNewRecord);
9099 Roo.data.Record.create = function(o){
9101 f.superclass.constructor.apply(this, arguments);
9103 Roo.extend(f, Roo.data.Record);
9104 var p = f.prototype;
9105 p.fields = new Roo.util.MixedCollection(false, function(field){
9108 for(var i = 0, len = o.length; i < len; i++){
9109 p.fields.add(new Roo.data.Field(o[i]));
9111 f.getField = function(name){
9112 return p.fields.get(name);
9117 Roo.data.Record.AUTO_ID = 1000;
9118 Roo.data.Record.EDIT = 'edit';
9119 Roo.data.Record.REJECT = 'reject';
9120 Roo.data.Record.COMMIT = 'commit';
9122 Roo.data.Record.prototype = {
9124 * Readonly flag - true if this record has been modified.
9133 join : function(store){
9138 * Set the named field to the specified value.
9139 * @param {String} name The name of the field to set.
9140 * @param {Object} value The value to set the field to.
9142 set : function(name, value){
9143 if(this.data[name] == value){
9150 if(typeof this.modified[name] == 'undefined'){
9151 this.modified[name] = this.data[name];
9153 this.data[name] = value;
9154 if(!this.editing && this.store){
9155 this.store.afterEdit(this);
9160 * Get the value of the named field.
9161 * @param {String} name The name of the field to get the value of.
9162 * @return {Object} The value of the field.
9164 get : function(name){
9165 return this.data[name];
9169 beginEdit : function(){
9170 this.editing = true;
9175 cancelEdit : function(){
9176 this.editing = false;
9177 delete this.modified;
9181 endEdit : function(){
9182 this.editing = false;
9183 if(this.dirty && this.store){
9184 this.store.afterEdit(this);
9189 * Usually called by the {@link Roo.data.Store} which owns the Record.
9190 * Rejects all changes made to the Record since either creation, or the last commit operation.
9191 * Modified fields are reverted to their original values.
9193 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9194 * of reject operations.
9196 reject : function(){
9197 var m = this.modified;
9199 if(typeof m[n] != "function"){
9200 this.data[n] = m[n];
9204 delete this.modified;
9205 this.editing = false;
9207 this.store.afterReject(this);
9212 * Usually called by the {@link Roo.data.Store} which owns the Record.
9213 * Commits all changes made to the Record since either creation, or the last commit operation.
9215 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9216 * of commit operations.
9218 commit : function(){
9220 delete this.modified;
9221 this.editing = false;
9223 this.store.afterCommit(this);
9228 hasError : function(){
9229 return this.error != null;
9233 clearError : function(){
9238 * Creates a copy of this record.
9239 * @param {String} id (optional) A new record id if you don't want to use this record's id
9242 copy : function(newId) {
9243 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
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">
9259 * @class Roo.data.Store
9260 * @extends Roo.util.Observable
9261 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9262 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9264 * 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
9265 * has no knowledge of the format of the data returned by the Proxy.<br>
9267 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9268 * instances from the data object. These records are cached and made available through accessor functions.
9270 * Creates a new Store.
9271 * @param {Object} config A config object containing the objects needed for the Store to access data,
9272 * and read the data into Records.
9274 Roo.data.Store = function(config){
9275 this.data = new Roo.util.MixedCollection(false);
9276 this.data.getKey = function(o){
9279 this.baseParams = {};
9286 "multisort" : "_multisort"
9289 if(config && config.data){
9290 this.inlineData = config.data;
9294 Roo.apply(this, config);
9296 if(this.reader){ // reader passed
9297 this.reader = Roo.factory(this.reader, Roo.data);
9298 this.reader.xmodule = this.xmodule || false;
9299 if(!this.recordType){
9300 this.recordType = this.reader.recordType;
9302 if(this.reader.onMetaChange){
9303 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9307 if(this.recordType){
9308 this.fields = this.recordType.prototype.fields;
9314 * @event datachanged
9315 * Fires when the data cache has changed, and a widget which is using this Store
9316 * as a Record cache should refresh its view.
9317 * @param {Store} this
9322 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9323 * @param {Store} this
9324 * @param {Object} meta The JSON metadata
9329 * Fires when Records have been added to the Store
9330 * @param {Store} this
9331 * @param {Roo.data.Record[]} records The array of Records added
9332 * @param {Number} index The index at which the record(s) were added
9337 * Fires when a Record has been removed from the Store
9338 * @param {Store} this
9339 * @param {Roo.data.Record} record The Record that was removed
9340 * @param {Number} index The index at which the record was removed
9345 * Fires when a Record has been updated
9346 * @param {Store} this
9347 * @param {Roo.data.Record} record The Record that was updated
9348 * @param {String} operation The update operation being performed. Value may be one of:
9350 Roo.data.Record.EDIT
9351 Roo.data.Record.REJECT
9352 Roo.data.Record.COMMIT
9358 * Fires when the data cache has been cleared.
9359 * @param {Store} this
9364 * Fires before a request is made for a new data object. If the beforeload handler returns false
9365 * the load action will be canceled.
9366 * @param {Store} this
9367 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9371 * @event beforeloadadd
9372 * Fires after a new set of Records has been loaded.
9373 * @param {Store} this
9374 * @param {Roo.data.Record[]} records The Records that were loaded
9375 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9377 beforeloadadd : true,
9380 * Fires after a new set of Records has been loaded, before they are added to the store.
9381 * @param {Store} this
9382 * @param {Roo.data.Record[]} records The Records that were loaded
9383 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9384 * @params {Object} return from reader
9388 * @event loadexception
9389 * Fires if an exception occurs in the Proxy during loading.
9390 * Called with the signature of the Proxy's "loadexception" event.
9391 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9394 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9395 * @param {Object} load options
9396 * @param {Object} jsonData from your request (normally this contains the Exception)
9398 loadexception : true
9402 this.proxy = Roo.factory(this.proxy, Roo.data);
9403 this.proxy.xmodule = this.xmodule || false;
9404 this.relayEvents(this.proxy, ["loadexception"]);
9406 this.sortToggle = {};
9407 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9409 Roo.data.Store.superclass.constructor.call(this);
9411 if(this.inlineData){
9412 this.loadData(this.inlineData);
9413 delete this.inlineData;
9417 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9419 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9420 * without a remote query - used by combo/forms at present.
9424 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9427 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9430 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9431 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9434 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9435 * on any HTTP request
9438 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9441 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9445 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9446 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9451 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9452 * loaded or when a record is removed. (defaults to false).
9454 pruneModifiedRecords : false,
9460 * Add Records to the Store and fires the add event.
9461 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9463 add : function(records){
9464 records = [].concat(records);
9465 for(var i = 0, len = records.length; i < len; i++){
9466 records[i].join(this);
9468 var index = this.data.length;
9469 this.data.addAll(records);
9470 this.fireEvent("add", this, records, index);
9474 * Remove a Record from the Store and fires the remove event.
9475 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9477 remove : function(record){
9478 var index = this.data.indexOf(record);
9479 this.data.removeAt(index);
9480 if(this.pruneModifiedRecords){
9481 this.modified.remove(record);
9483 this.fireEvent("remove", this, record, index);
9487 * Remove all Records from the Store and fires the clear event.
9489 removeAll : function(){
9491 if(this.pruneModifiedRecords){
9494 this.fireEvent("clear", this);
9498 * Inserts Records to the Store at the given index and fires the add event.
9499 * @param {Number} index The start index at which to insert the passed Records.
9500 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9502 insert : function(index, records){
9503 records = [].concat(records);
9504 for(var i = 0, len = records.length; i < len; i++){
9505 this.data.insert(index, records[i]);
9506 records[i].join(this);
9508 this.fireEvent("add", this, records, index);
9512 * Get the index within the cache of the passed Record.
9513 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9514 * @return {Number} The index of the passed Record. Returns -1 if not found.
9516 indexOf : function(record){
9517 return this.data.indexOf(record);
9521 * Get the index within the cache of the Record with the passed id.
9522 * @param {String} id The id of the Record to find.
9523 * @return {Number} The index of the Record. Returns -1 if not found.
9525 indexOfId : function(id){
9526 return this.data.indexOfKey(id);
9530 * Get the Record with the specified id.
9531 * @param {String} id The id of the Record to find.
9532 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9534 getById : function(id){
9535 return this.data.key(id);
9539 * Get the Record at the specified index.
9540 * @param {Number} index The index of the Record to find.
9541 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9543 getAt : function(index){
9544 return this.data.itemAt(index);
9548 * Returns a range of Records between specified indices.
9549 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9550 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9551 * @return {Roo.data.Record[]} An array of Records
9553 getRange : function(start, end){
9554 return this.data.getRange(start, end);
9558 storeOptions : function(o){
9559 o = Roo.apply({}, o);
9562 this.lastOptions = o;
9566 * Loads the Record cache from the configured Proxy using the configured Reader.
9568 * If using remote paging, then the first load call must specify the <em>start</em>
9569 * and <em>limit</em> properties in the options.params property to establish the initial
9570 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9572 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9573 * and this call will return before the new data has been loaded. Perform any post-processing
9574 * in a callback function, or in a "load" event handler.</strong>
9576 * @param {Object} options An object containing properties which control loading options:<ul>
9577 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9578 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9579 * passed the following arguments:<ul>
9580 * <li>r : Roo.data.Record[]</li>
9581 * <li>options: Options object from the load call</li>
9582 * <li>success: Boolean success indicator</li></ul></li>
9583 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9584 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9587 load : function(options){
9588 options = options || {};
9589 if(this.fireEvent("beforeload", this, options) !== false){
9590 this.storeOptions(options);
9591 var p = Roo.apply(options.params || {}, this.baseParams);
9592 // if meta was not loaded from remote source.. try requesting it.
9593 if (!this.reader.metaFromRemote) {
9596 if(this.sortInfo && this.remoteSort){
9597 var pn = this.paramNames;
9598 p[pn["sort"]] = this.sortInfo.field;
9599 p[pn["dir"]] = this.sortInfo.direction;
9601 if (this.multiSort) {
9602 var pn = this.paramNames;
9603 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9606 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9611 * Reloads the Record cache from the configured Proxy using the configured Reader and
9612 * the options from the last load operation performed.
9613 * @param {Object} options (optional) An object containing properties which may override the options
9614 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9615 * the most recently used options are reused).
9617 reload : function(options){
9618 this.load(Roo.applyIf(options||{}, this.lastOptions));
9622 // Called as a callback by the Reader during a load operation.
9623 loadRecords : function(o, options, success){
9624 if(!o || success === false){
9625 if(success !== false){
9626 this.fireEvent("load", this, [], options, o);
9628 if(options.callback){
9629 options.callback.call(options.scope || this, [], options, false);
9633 // if data returned failure - throw an exception.
9634 if (o.success === false) {
9635 // show a message if no listener is registered.
9636 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9637 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9639 // loadmask wil be hooked into this..
9640 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9643 var r = o.records, t = o.totalRecords || r.length;
9645 this.fireEvent("beforeloadadd", this, r, options, o);
9647 if(!options || options.add !== true){
9648 if(this.pruneModifiedRecords){
9651 for(var i = 0, len = r.length; i < len; i++){
9655 this.data = this.snapshot;
9656 delete this.snapshot;
9659 this.data.addAll(r);
9660 this.totalLength = t;
9662 this.fireEvent("datachanged", this);
9664 this.totalLength = Math.max(t, this.data.length+r.length);
9667 this.fireEvent("load", this, r, options, o);
9668 if(options.callback){
9669 options.callback.call(options.scope || this, r, options, true);
9675 * Loads data from a passed data block. A Reader which understands the format of the data
9676 * must have been configured in the constructor.
9677 * @param {Object} data The data block from which to read the Records. The format of the data expected
9678 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9679 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9681 loadData : function(o, append){
9682 var r = this.reader.readRecords(o);
9683 this.loadRecords(r, {add: append}, true);
9687 * Gets the number of cached records.
9689 * <em>If using paging, this may not be the total size of the dataset. If the data object
9690 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9691 * the data set size</em>
9693 getCount : function(){
9694 return this.data.length || 0;
9698 * Gets the total number of records in the dataset as returned by the server.
9700 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9701 * the dataset size</em>
9703 getTotalCount : function(){
9704 return this.totalLength || 0;
9708 * Returns the sort state of the Store as an object with two properties:
9710 field {String} The name of the field by which the Records are sorted
9711 direction {String} The sort order, "ASC" or "DESC"
9714 getSortState : function(){
9715 return this.sortInfo;
9719 applySort : function(){
9720 if(this.sortInfo && !this.remoteSort){
9721 var s = this.sortInfo, f = s.field;
9722 var st = this.fields.get(f).sortType;
9723 var fn = function(r1, r2){
9724 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9725 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9727 this.data.sort(s.direction, fn);
9728 if(this.snapshot && this.snapshot != this.data){
9729 this.snapshot.sort(s.direction, fn);
9735 * Sets the default sort column and order to be used by the next load operation.
9736 * @param {String} fieldName The name of the field to sort by.
9737 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9739 setDefaultSort : function(field, dir){
9740 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9745 * If remote sorting is used, the sort is performed on the server, and the cache is
9746 * reloaded. If local sorting is used, the cache is sorted internally.
9747 * @param {String} fieldName The name of the field to sort by.
9748 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9750 sort : function(fieldName, dir){
9751 var f = this.fields.get(fieldName);
9753 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9755 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9756 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9761 this.sortToggle[f.name] = dir;
9762 this.sortInfo = {field: f.name, direction: dir};
9763 if(!this.remoteSort){
9765 this.fireEvent("datachanged", this);
9767 this.load(this.lastOptions);
9772 * Calls the specified function for each of the Records in the cache.
9773 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9774 * Returning <em>false</em> aborts and exits the iteration.
9775 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9777 each : function(fn, scope){
9778 this.data.each(fn, scope);
9782 * Gets all records modified since the last commit. Modified records are persisted across load operations
9783 * (e.g., during paging).
9784 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9786 getModifiedRecords : function(){
9787 return this.modified;
9791 createFilterFn : function(property, value, anyMatch){
9792 if(!value.exec){ // not a regex
9793 value = String(value);
9794 if(value.length == 0){
9797 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9800 return value.test(r.data[property]);
9805 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9806 * @param {String} property A field on your records
9807 * @param {Number} start The record index to start at (defaults to 0)
9808 * @param {Number} end The last record index to include (defaults to length - 1)
9809 * @return {Number} The sum
9811 sum : function(property, start, end){
9812 var rs = this.data.items, v = 0;
9814 end = (end || end === 0) ? end : rs.length-1;
9816 for(var i = start; i <= end; i++){
9817 v += (rs[i].data[property] || 0);
9823 * Filter the records by a specified property.
9824 * @param {String} field A field on your records
9825 * @param {String/RegExp} value Either a string that the field
9826 * should start with or a RegExp to test against the field
9827 * @param {Boolean} anyMatch True to match any part not just the beginning
9829 filter : function(property, value, anyMatch){
9830 var fn = this.createFilterFn(property, value, anyMatch);
9831 return fn ? this.filterBy(fn) : this.clearFilter();
9835 * Filter by a function. The specified function will be called with each
9836 * record in this data source. If the function returns true the record is included,
9837 * otherwise it is filtered.
9838 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9839 * @param {Object} scope (optional) The scope of the function (defaults to this)
9841 filterBy : function(fn, scope){
9842 this.snapshot = this.snapshot || this.data;
9843 this.data = this.queryBy(fn, scope||this);
9844 this.fireEvent("datachanged", this);
9848 * Query the records by a specified property.
9849 * @param {String} field A field on your records
9850 * @param {String/RegExp} value Either a string that the field
9851 * should start with or a RegExp to test against the field
9852 * @param {Boolean} anyMatch True to match any part not just the beginning
9853 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9855 query : function(property, value, anyMatch){
9856 var fn = this.createFilterFn(property, value, anyMatch);
9857 return fn ? this.queryBy(fn) : this.data.clone();
9861 * Query by a function. The specified function will be called with each
9862 * record in this data source. If the function returns true the record is included
9864 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9865 * @param {Object} scope (optional) The scope of the function (defaults to this)
9866 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9868 queryBy : function(fn, scope){
9869 var data = this.snapshot || this.data;
9870 return data.filterBy(fn, scope||this);
9874 * Collects unique values for a particular dataIndex from this store.
9875 * @param {String} dataIndex The property to collect
9876 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9877 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9878 * @return {Array} An array of the unique values
9880 collect : function(dataIndex, allowNull, bypassFilter){
9881 var d = (bypassFilter === true && this.snapshot) ?
9882 this.snapshot.items : this.data.items;
9883 var v, sv, r = [], l = {};
9884 for(var i = 0, len = d.length; i < len; i++){
9885 v = d[i].data[dataIndex];
9887 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9896 * Revert to a view of the Record cache with no filtering applied.
9897 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9899 clearFilter : function(suppressEvent){
9900 if(this.snapshot && this.snapshot != this.data){
9901 this.data = this.snapshot;
9902 delete this.snapshot;
9903 if(suppressEvent !== true){
9904 this.fireEvent("datachanged", this);
9910 afterEdit : function(record){
9911 if(this.modified.indexOf(record) == -1){
9912 this.modified.push(record);
9914 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9918 afterReject : function(record){
9919 this.modified.remove(record);
9920 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9924 afterCommit : function(record){
9925 this.modified.remove(record);
9926 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9930 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9931 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9933 commitChanges : function(){
9934 var m = this.modified.slice(0);
9936 for(var i = 0, len = m.length; i < len; i++){
9942 * Cancel outstanding changes on all changed records.
9944 rejectChanges : function(){
9945 var m = this.modified.slice(0);
9947 for(var i = 0, len = m.length; i < len; i++){
9952 onMetaChange : function(meta, rtype, o){
9953 this.recordType = rtype;
9954 this.fields = rtype.prototype.fields;
9955 delete this.snapshot;
9956 this.sortInfo = meta.sortInfo || this.sortInfo;
9958 this.fireEvent('metachange', this, this.reader.meta);
9961 moveIndex : function(data, type)
9963 var index = this.indexOf(data);
9965 var newIndex = index + type;
9969 this.insert(newIndex, data);
9974 * Ext JS Library 1.1.1
9975 * Copyright(c) 2006-2007, Ext JS, LLC.
9977 * Originally Released Under LGPL - original licence link has changed is not relivant.
9980 * <script type="text/javascript">
9984 * @class Roo.data.SimpleStore
9985 * @extends Roo.data.Store
9986 * Small helper class to make creating Stores from Array data easier.
9987 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9988 * @cfg {Array} fields An array of field definition objects, or field name strings.
9989 * @cfg {Array} data The multi-dimensional array of data
9991 * @param {Object} config
9993 Roo.data.SimpleStore = function(config){
9994 Roo.data.SimpleStore.superclass.constructor.call(this, {
9996 reader: new Roo.data.ArrayReader({
9999 Roo.data.Record.create(config.fields)
10001 proxy : new Roo.data.MemoryProxy(config.data)
10005 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10007 * Ext JS Library 1.1.1
10008 * Copyright(c) 2006-2007, Ext JS, LLC.
10010 * Originally Released Under LGPL - original licence link has changed is not relivant.
10013 * <script type="text/javascript">
10018 * @extends Roo.data.Store
10019 * @class Roo.data.JsonStore
10020 * Small helper class to make creating Stores for JSON data easier. <br/>
10022 var store = new Roo.data.JsonStore({
10023 url: 'get-images.php',
10025 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10028 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10029 * JsonReader and HttpProxy (unless inline data is provided).</b>
10030 * @cfg {Array} fields An array of field definition objects, or field name strings.
10032 * @param {Object} config
10034 Roo.data.JsonStore = function(c){
10035 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10036 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10037 reader: new Roo.data.JsonReader(c, c.fields)
10040 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10042 * Ext JS Library 1.1.1
10043 * Copyright(c) 2006-2007, Ext JS, LLC.
10045 * Originally Released Under LGPL - original licence link has changed is not relivant.
10048 * <script type="text/javascript">
10052 Roo.data.Field = function(config){
10053 if(typeof config == "string"){
10054 config = {name: config};
10056 Roo.apply(this, config);
10059 this.type = "auto";
10062 var st = Roo.data.SortTypes;
10063 // named sortTypes are supported, here we look them up
10064 if(typeof this.sortType == "string"){
10065 this.sortType = st[this.sortType];
10068 // set default sortType for strings and dates
10069 if(!this.sortType){
10072 this.sortType = st.asUCString;
10075 this.sortType = st.asDate;
10078 this.sortType = st.none;
10083 var stripRe = /[\$,%]/g;
10085 // prebuilt conversion function for this field, instead of
10086 // switching every time we're reading a value
10088 var cv, dateFormat = this.dateFormat;
10093 cv = function(v){ return v; };
10096 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10100 return v !== undefined && v !== null && v !== '' ?
10101 parseInt(String(v).replace(stripRe, ""), 10) : '';
10106 return v !== undefined && v !== null && v !== '' ?
10107 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10112 cv = function(v){ return v === true || v === "true" || v == 1; };
10119 if(v instanceof Date){
10123 if(dateFormat == "timestamp"){
10124 return new Date(v*1000);
10126 return Date.parseDate(v, dateFormat);
10128 var parsed = Date.parse(v);
10129 return parsed ? new Date(parsed) : null;
10138 Roo.data.Field.prototype = {
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">
10155 // Base class for reading structured data from a data source. This class is intended to be
10156 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10159 * @class Roo.data.DataReader
10160 * Base class for reading structured data from a data source. This class is intended to be
10161 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10164 Roo.data.DataReader = function(meta, recordType){
10168 this.recordType = recordType instanceof Array ?
10169 Roo.data.Record.create(recordType) : recordType;
10172 Roo.data.DataReader.prototype = {
10174 * Create an empty record
10175 * @param {Object} data (optional) - overlay some values
10176 * @return {Roo.data.Record} record created.
10178 newRow : function(d) {
10180 this.recordType.prototype.fields.each(function(c) {
10182 case 'int' : da[c.name] = 0; break;
10183 case 'date' : da[c.name] = new Date(); break;
10184 case 'float' : da[c.name] = 0.0; break;
10185 case 'boolean' : da[c.name] = false; break;
10186 default : da[c.name] = ""; break;
10190 return new this.recordType(Roo.apply(da, d));
10195 * Ext JS Library 1.1.1
10196 * Copyright(c) 2006-2007, Ext JS, LLC.
10198 * Originally Released Under LGPL - original licence link has changed is not relivant.
10201 * <script type="text/javascript">
10205 * @class Roo.data.DataProxy
10206 * @extends Roo.data.Observable
10207 * This class is an abstract base class for implementations which provide retrieval of
10208 * unformatted data objects.<br>
10210 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10211 * (of the appropriate type which knows how to parse the data object) to provide a block of
10212 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10214 * Custom implementations must implement the load method as described in
10215 * {@link Roo.data.HttpProxy#load}.
10217 Roo.data.DataProxy = function(){
10220 * @event beforeload
10221 * Fires before a network request is made to retrieve a data object.
10222 * @param {Object} This DataProxy object.
10223 * @param {Object} params The params parameter to the load function.
10228 * Fires before the load method's callback is called.
10229 * @param {Object} This DataProxy object.
10230 * @param {Object} o The data object.
10231 * @param {Object} arg The callback argument object passed to the load function.
10235 * @event loadexception
10236 * Fires if an Exception occurs during data retrieval.
10237 * @param {Object} This DataProxy object.
10238 * @param {Object} o The data object.
10239 * @param {Object} arg The callback argument object passed to the load function.
10240 * @param {Object} e The Exception.
10242 loadexception : true
10244 Roo.data.DataProxy.superclass.constructor.call(this);
10247 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10250 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10254 * Ext JS Library 1.1.1
10255 * Copyright(c) 2006-2007, Ext JS, LLC.
10257 * Originally Released Under LGPL - original licence link has changed is not relivant.
10260 * <script type="text/javascript">
10263 * @class Roo.data.MemoryProxy
10264 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10265 * to the Reader when its load method is called.
10267 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10269 Roo.data.MemoryProxy = function(data){
10273 Roo.data.MemoryProxy.superclass.constructor.call(this);
10277 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10279 * Load data from the requested source (in this case an in-memory
10280 * data object passed to the constructor), read the data object into
10281 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10282 * process that block using the passed callback.
10283 * @param {Object} params This parameter is not used by the MemoryProxy class.
10284 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10285 * object into a block of Roo.data.Records.
10286 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10287 * The function must be passed <ul>
10288 * <li>The Record block object</li>
10289 * <li>The "arg" argument from the load function</li>
10290 * <li>A boolean success indicator</li>
10292 * @param {Object} scope The scope in which to call the callback
10293 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10295 load : function(params, reader, callback, scope, arg){
10296 params = params || {};
10299 result = reader.readRecords(this.data);
10301 this.fireEvent("loadexception", this, arg, null, e);
10302 callback.call(scope, null, arg, false);
10305 callback.call(scope, result, arg, true);
10309 update : function(params, records){
10314 * Ext JS Library 1.1.1
10315 * Copyright(c) 2006-2007, Ext JS, LLC.
10317 * Originally Released Under LGPL - original licence link has changed is not relivant.
10320 * <script type="text/javascript">
10323 * @class Roo.data.HttpProxy
10324 * @extends Roo.data.DataProxy
10325 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10326 * configured to reference a certain URL.<br><br>
10328 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10329 * from which the running page was served.<br><br>
10331 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10333 * Be aware that to enable the browser to parse an XML document, the server must set
10334 * the Content-Type header in the HTTP response to "text/xml".
10336 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10337 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10338 * will be used to make the request.
10340 Roo.data.HttpProxy = function(conn){
10341 Roo.data.HttpProxy.superclass.constructor.call(this);
10342 // is conn a conn config or a real conn?
10344 this.useAjax = !conn || !conn.events;
10348 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10349 // thse are take from connection...
10352 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10355 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10356 * extra parameters to each request made by this object. (defaults to undefined)
10359 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10360 * to each request made by this object. (defaults to undefined)
10363 * @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)
10366 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10369 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10375 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10379 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10380 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10381 * a finer-grained basis than the DataProxy events.
10383 getConnection : function(){
10384 return this.useAjax ? Roo.Ajax : this.conn;
10388 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10389 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10390 * process that block using the passed callback.
10391 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10392 * for the request to the remote server.
10393 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10394 * object into a block of Roo.data.Records.
10395 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10396 * The function must be passed <ul>
10397 * <li>The Record block object</li>
10398 * <li>The "arg" argument from the load function</li>
10399 * <li>A boolean success indicator</li>
10401 * @param {Object} scope The scope in which to call the callback
10402 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10404 load : function(params, reader, callback, scope, arg){
10405 if(this.fireEvent("beforeload", this, params) !== false){
10407 params : params || {},
10409 callback : callback,
10414 callback : this.loadResponse,
10418 Roo.applyIf(o, this.conn);
10419 if(this.activeRequest){
10420 Roo.Ajax.abort(this.activeRequest);
10422 this.activeRequest = Roo.Ajax.request(o);
10424 this.conn.request(o);
10427 callback.call(scope||this, null, arg, false);
10432 loadResponse : function(o, success, response){
10433 delete this.activeRequest;
10435 this.fireEvent("loadexception", this, o, response);
10436 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10441 result = o.reader.read(response);
10443 this.fireEvent("loadexception", this, o, response, e);
10444 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10448 this.fireEvent("load", this, o, o.request.arg);
10449 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10453 update : function(dataSet){
10458 updateResponse : function(dataSet){
10463 * Ext JS Library 1.1.1
10464 * Copyright(c) 2006-2007, Ext JS, LLC.
10466 * Originally Released Under LGPL - original licence link has changed is not relivant.
10469 * <script type="text/javascript">
10473 * @class Roo.data.ScriptTagProxy
10474 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10475 * other than the originating domain of the running page.<br><br>
10477 * <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
10478 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10480 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10481 * source code that is used as the source inside a <script> tag.<br><br>
10483 * In order for the browser to process the returned data, the server must wrap the data object
10484 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10485 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10486 * depending on whether the callback name was passed:
10489 boolean scriptTag = false;
10490 String cb = request.getParameter("callback");
10493 response.setContentType("text/javascript");
10495 response.setContentType("application/x-json");
10497 Writer out = response.getWriter();
10499 out.write(cb + "(");
10501 out.print(dataBlock.toJsonString());
10508 * @param {Object} config A configuration object.
10510 Roo.data.ScriptTagProxy = function(config){
10511 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10512 Roo.apply(this, config);
10513 this.head = document.getElementsByTagName("head")[0];
10516 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10518 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10520 * @cfg {String} url The URL from which to request the data object.
10523 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10527 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10528 * the server the name of the callback function set up by the load call to process the returned data object.
10529 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10530 * javascript output which calls this named function passing the data object as its only parameter.
10532 callbackParam : "callback",
10534 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10535 * name to the request.
10540 * Load data from the configured URL, read the data object into
10541 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10542 * process that block using the passed callback.
10543 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10544 * for the request to the remote server.
10545 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10546 * object into a block of Roo.data.Records.
10547 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10548 * The function must be passed <ul>
10549 * <li>The Record block object</li>
10550 * <li>The "arg" argument from the load function</li>
10551 * <li>A boolean success indicator</li>
10553 * @param {Object} scope The scope in which to call the callback
10554 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10556 load : function(params, reader, callback, scope, arg){
10557 if(this.fireEvent("beforeload", this, params) !== false){
10559 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10561 var url = this.url;
10562 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10564 url += "&_dc=" + (new Date().getTime());
10566 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10569 cb : "stcCallback"+transId,
10570 scriptId : "stcScript"+transId,
10574 callback : callback,
10580 window[trans.cb] = function(o){
10581 conn.handleResponse(o, trans);
10584 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10586 if(this.autoAbort !== false){
10590 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10592 var script = document.createElement("script");
10593 script.setAttribute("src", url);
10594 script.setAttribute("type", "text/javascript");
10595 script.setAttribute("id", trans.scriptId);
10596 this.head.appendChild(script);
10598 this.trans = trans;
10600 callback.call(scope||this, null, arg, false);
10605 isLoading : function(){
10606 return this.trans ? true : false;
10610 * Abort the current server request.
10612 abort : function(){
10613 if(this.isLoading()){
10614 this.destroyTrans(this.trans);
10619 destroyTrans : function(trans, isLoaded){
10620 this.head.removeChild(document.getElementById(trans.scriptId));
10621 clearTimeout(trans.timeoutId);
10623 window[trans.cb] = undefined;
10625 delete window[trans.cb];
10628 // if hasn't been loaded, wait for load to remove it to prevent script error
10629 window[trans.cb] = function(){
10630 window[trans.cb] = undefined;
10632 delete window[trans.cb];
10639 handleResponse : function(o, trans){
10640 this.trans = false;
10641 this.destroyTrans(trans, true);
10644 result = trans.reader.readRecords(o);
10646 this.fireEvent("loadexception", this, o, trans.arg, e);
10647 trans.callback.call(trans.scope||window, null, trans.arg, false);
10650 this.fireEvent("load", this, o, trans.arg);
10651 trans.callback.call(trans.scope||window, result, trans.arg, true);
10655 handleFailure : function(trans){
10656 this.trans = false;
10657 this.destroyTrans(trans, false);
10658 this.fireEvent("loadexception", this, null, trans.arg);
10659 trans.callback.call(trans.scope||window, null, trans.arg, false);
10663 * Ext JS Library 1.1.1
10664 * Copyright(c) 2006-2007, Ext JS, LLC.
10666 * Originally Released Under LGPL - original licence link has changed is not relivant.
10669 * <script type="text/javascript">
10673 * @class Roo.data.JsonReader
10674 * @extends Roo.data.DataReader
10675 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10676 * based on mappings in a provided Roo.data.Record constructor.
10678 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10679 * in the reply previously.
10684 var RecordDef = Roo.data.Record.create([
10685 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10686 {name: 'occupation'} // This field will use "occupation" as the mapping.
10688 var myReader = new Roo.data.JsonReader({
10689 totalProperty: "results", // The property which contains the total dataset size (optional)
10690 root: "rows", // The property which contains an Array of row objects
10691 id: "id" // The property within each row object that provides an ID for the record (optional)
10695 * This would consume a JSON file like this:
10697 { 'results': 2, 'rows': [
10698 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10699 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10702 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10703 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10704 * paged from the remote server.
10705 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10706 * @cfg {String} root name of the property which contains the Array of row objects.
10707 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10708 * @cfg {Array} fields Array of field definition objects
10710 * Create a new JsonReader
10711 * @param {Object} meta Metadata configuration options
10712 * @param {Object} recordType Either an Array of field definition objects,
10713 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10715 Roo.data.JsonReader = function(meta, recordType){
10718 // set some defaults:
10719 Roo.applyIf(meta, {
10720 totalProperty: 'total',
10721 successProperty : 'success',
10726 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10728 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10731 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10732 * Used by Store query builder to append _requestMeta to params.
10735 metaFromRemote : false,
10737 * This method is only used by a DataProxy which has retrieved data from a remote server.
10738 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10739 * @return {Object} data A data block which is used by an Roo.data.Store object as
10740 * a cache of Roo.data.Records.
10742 read : function(response){
10743 var json = response.responseText;
10745 var o = /* eval:var:o */ eval("("+json+")");
10747 throw {message: "JsonReader.read: Json object not found"};
10753 this.metaFromRemote = true;
10754 this.meta = o.metaData;
10755 this.recordType = Roo.data.Record.create(o.metaData.fields);
10756 this.onMetaChange(this.meta, this.recordType, o);
10758 return this.readRecords(o);
10761 // private function a store will implement
10762 onMetaChange : function(meta, recordType, o){
10769 simpleAccess: function(obj, subsc) {
10776 getJsonAccessor: function(){
10778 return function(expr) {
10780 return(re.test(expr))
10781 ? new Function("obj", "return obj." + expr)
10786 return Roo.emptyFn;
10791 * Create a data block containing Roo.data.Records from an XML document.
10792 * @param {Object} o An object which contains an Array of row objects in the property specified
10793 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10794 * which contains the total size of the dataset.
10795 * @return {Object} data A data block which is used by an Roo.data.Store object as
10796 * a cache of Roo.data.Records.
10798 readRecords : function(o){
10800 * After any data loads, the raw JSON data is available for further custom processing.
10804 var s = this.meta, Record = this.recordType,
10805 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10807 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10809 if(s.totalProperty) {
10810 this.getTotal = this.getJsonAccessor(s.totalProperty);
10812 if(s.successProperty) {
10813 this.getSuccess = this.getJsonAccessor(s.successProperty);
10815 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10817 var g = this.getJsonAccessor(s.id);
10818 this.getId = function(rec) {
10820 return (r === undefined || r === "") ? null : r;
10823 this.getId = function(){return null;};
10826 for(var jj = 0; jj < fl; jj++){
10828 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10829 this.ef[jj] = this.getJsonAccessor(map);
10833 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10834 if(s.totalProperty){
10835 var vt = parseInt(this.getTotal(o), 10);
10840 if(s.successProperty){
10841 var vs = this.getSuccess(o);
10842 if(vs === false || vs === 'false'){
10847 for(var i = 0; i < c; i++){
10850 var id = this.getId(n);
10851 for(var j = 0; j < fl; j++){
10853 var v = this.ef[j](n);
10855 Roo.log('missing convert for ' + f.name);
10859 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10861 var record = new Record(values, id);
10863 records[i] = record;
10869 totalRecords : totalRecords
10874 * Ext JS Library 1.1.1
10875 * Copyright(c) 2006-2007, Ext JS, LLC.
10877 * Originally Released Under LGPL - original licence link has changed is not relivant.
10880 * <script type="text/javascript">
10884 * @class Roo.data.ArrayReader
10885 * @extends Roo.data.DataReader
10886 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10887 * Each element of that Array represents a row of data fields. The
10888 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10889 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10893 var RecordDef = Roo.data.Record.create([
10894 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10895 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10897 var myReader = new Roo.data.ArrayReader({
10898 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10902 * This would consume an Array like this:
10904 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10906 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10908 * Create a new JsonReader
10909 * @param {Object} meta Metadata configuration options.
10910 * @param {Object} recordType Either an Array of field definition objects
10911 * as specified to {@link Roo.data.Record#create},
10912 * or an {@link Roo.data.Record} object
10913 * created using {@link Roo.data.Record#create}.
10915 Roo.data.ArrayReader = function(meta, recordType){
10916 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10919 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10921 * Create a data block containing Roo.data.Records from an XML document.
10922 * @param {Object} o An Array of row objects which represents the dataset.
10923 * @return {Object} data A data block which is used by an Roo.data.Store object as
10924 * a cache of Roo.data.Records.
10926 readRecords : function(o){
10927 var sid = this.meta ? this.meta.id : null;
10928 var recordType = this.recordType, fields = recordType.prototype.fields;
10931 for(var i = 0; i < root.length; i++){
10934 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10935 for(var j = 0, jlen = fields.length; j < jlen; j++){
10936 var f = fields.items[j];
10937 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10938 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10940 values[f.name] = v;
10942 var record = new recordType(values, id);
10944 records[records.length] = record;
10948 totalRecords : records.length
10957 * @class Roo.bootstrap.ComboBox
10958 * @extends Roo.bootstrap.TriggerField
10959 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10960 * @cfg {Boolean} append (true|false) default false
10961 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10962 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10963 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10964 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10965 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10967 * Create a new ComboBox.
10968 * @param {Object} config Configuration options
10970 Roo.bootstrap.ComboBox = function(config){
10971 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10975 * Fires when the dropdown list is expanded
10976 * @param {Roo.bootstrap.ComboBox} combo This combo box
10981 * Fires when the dropdown list is collapsed
10982 * @param {Roo.bootstrap.ComboBox} combo This combo box
10986 * @event beforeselect
10987 * Fires before a list item is selected. Return false to cancel the selection.
10988 * @param {Roo.bootstrap.ComboBox} combo This combo box
10989 * @param {Roo.data.Record} record The data record returned from the underlying store
10990 * @param {Number} index The index of the selected item in the dropdown list
10992 'beforeselect' : true,
10995 * Fires when a list item is selected
10996 * @param {Roo.bootstrap.ComboBox} combo This combo box
10997 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10998 * @param {Number} index The index of the selected item in the dropdown list
11002 * @event beforequery
11003 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11004 * The event object passed has these properties:
11005 * @param {Roo.bootstrap.ComboBox} combo This combo box
11006 * @param {String} query The query
11007 * @param {Boolean} forceAll true to force "all" query
11008 * @param {Boolean} cancel true to cancel the query
11009 * @param {Object} e The query event object
11011 'beforequery': true,
11014 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11015 * @param {Roo.bootstrap.ComboBox} combo This combo box
11020 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11021 * @param {Roo.bootstrap.ComboBox} combo This combo box
11022 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11027 * Fires when the remove value from the combobox array
11028 * @param {Roo.bootstrap.ComboBox} combo This combo box
11032 * @event specialfilter
11033 * Fires when specialfilter
11034 * @param {Roo.bootstrap.ComboBox} combo This combo box
11036 'specialfilter' : true
11041 this.tickItems = [];
11043 this.selectedIndex = -1;
11044 if(this.mode == 'local'){
11045 if(config.queryDelay === undefined){
11046 this.queryDelay = 10;
11048 if(config.minChars === undefined){
11054 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11057 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11058 * rendering into an Roo.Editor, defaults to false)
11061 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11062 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11065 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11068 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11069 * the dropdown list (defaults to undefined, with no header element)
11073 * @cfg {String/Roo.Template} tpl The template to use to render the output
11077 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11079 listWidth: undefined,
11081 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11082 * mode = 'remote' or 'text' if mode = 'local')
11084 displayField: undefined,
11087 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11088 * mode = 'remote' or 'value' if mode = 'local').
11089 * Note: use of a valueField requires the user make a selection
11090 * in order for a value to be mapped.
11092 valueField: undefined,
11096 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11097 * field's data value (defaults to the underlying DOM element's name)
11099 hiddenName: undefined,
11101 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11105 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11107 selectedClass: 'active',
11110 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11114 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11115 * anchor positions (defaults to 'tl-bl')
11117 listAlign: 'tl-bl?',
11119 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11123 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11124 * query specified by the allQuery config option (defaults to 'query')
11126 triggerAction: 'query',
11128 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11129 * (defaults to 4, does not apply if editable = false)
11133 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11134 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11138 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11139 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11143 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11144 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11148 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11149 * when editable = true (defaults to false)
11151 selectOnFocus:false,
11153 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11155 queryParam: 'query',
11157 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11158 * when mode = 'remote' (defaults to 'Loading...')
11160 loadingText: 'Loading...',
11162 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11166 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11170 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11171 * traditional select (defaults to true)
11175 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11179 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11183 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11184 * listWidth has a higher value)
11188 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11189 * allow the user to set arbitrary text into the field (defaults to false)
11191 forceSelection:false,
11193 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11194 * if typeAhead = true (defaults to 250)
11196 typeAheadDelay : 250,
11198 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11199 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11201 valueNotFoundText : undefined,
11203 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11205 blockFocus : false,
11208 * @cfg {Boolean} disableClear Disable showing of clear button.
11210 disableClear : false,
11212 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11214 alwaysQuery : false,
11217 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11222 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11224 invalidClass : "has-warning",
11227 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11229 validClass : "has-success",
11232 * @cfg {Boolean} specialFilter (true|false) special filter default false
11234 specialFilter : false,
11246 btnPosition : 'right',
11247 triggerList : true,
11248 showToggleBtn : true,
11249 // element that contains real text value.. (when hidden is used..)
11251 getAutoCreate : function()
11258 if(!this.tickable){
11259 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11264 * ComboBox with tickable selections
11267 var align = this.labelAlign || this.parentLabelAlign();
11270 cls : 'form-group roo-combobox-tickable' //input-group
11275 cls : 'tickable-buttons',
11280 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11287 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11294 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11301 buttons.cn.unshift({
11303 cls: 'select2-search-field-input'
11309 Roo.each(buttons.cn, function(c){
11311 c.cls += ' btn-' + _this.size;
11314 if (_this.disabled) {
11325 cls: 'form-hidden-field'
11329 cls: 'select2-choices',
11333 cls: 'select2-search-field',
11345 cls: 'select2-container input-group select2-container-multi',
11350 // cls: 'typeahead typeahead-long dropdown-menu',
11351 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11356 if(this.hasFeedback && !this.allowBlank){
11360 cls: 'glyphicon form-control-feedback'
11363 combobox.cn.push(feedback);
11366 if (align ==='left' && this.fieldLabel.length) {
11368 Roo.log("left and has label");
11374 cls : 'control-label col-sm-' + this.labelWidth,
11375 html : this.fieldLabel
11379 cls : "col-sm-" + (12 - this.labelWidth),
11386 } else if ( this.fieldLabel.length) {
11392 //cls : 'input-group-addon',
11393 html : this.fieldLabel
11403 Roo.log(" no label && no align");
11410 ['xs','sm','md','lg'].map(function(size){
11411 if (settings[size]) {
11412 cfg.cls += ' col-' + size + '-' + settings[size];
11421 initEvents: function()
11425 throw "can not find store for combo";
11427 this.store = Roo.factory(this.store, Roo.data);
11430 this.initTickableEvents();
11434 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11436 if(this.hiddenName){
11438 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11440 this.hiddenField.dom.value =
11441 this.hiddenValue !== undefined ? this.hiddenValue :
11442 this.value !== undefined ? this.value : '';
11444 // prevent input submission
11445 this.el.dom.removeAttribute('name');
11446 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11451 // this.el.dom.setAttribute('autocomplete', 'off');
11454 var cls = 'x-combo-list';
11456 //this.list = new Roo.Layer({
11457 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11463 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11464 _this.list.setWidth(lw);
11467 this.list.on('mouseover', this.onViewOver, this);
11468 this.list.on('mousemove', this.onViewMove, this);
11470 this.list.on('scroll', this.onViewScroll, this);
11473 this.list.swallowEvent('mousewheel');
11474 this.assetHeight = 0;
11477 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11478 this.assetHeight += this.header.getHeight();
11481 this.innerList = this.list.createChild({cls:cls+'-inner'});
11482 this.innerList.on('mouseover', this.onViewOver, this);
11483 this.innerList.on('mousemove', this.onViewMove, this);
11484 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11486 if(this.allowBlank && !this.pageSize && !this.disableClear){
11487 this.footer = this.list.createChild({cls:cls+'-ft'});
11488 this.pageTb = new Roo.Toolbar(this.footer);
11492 this.footer = this.list.createChild({cls:cls+'-ft'});
11493 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11494 {pageSize: this.pageSize});
11498 if (this.pageTb && this.allowBlank && !this.disableClear) {
11500 this.pageTb.add(new Roo.Toolbar.Fill(), {
11501 cls: 'x-btn-icon x-btn-clear',
11503 handler: function()
11506 _this.clearValue();
11507 _this.onSelect(false, -1);
11512 this.assetHeight += this.footer.getHeight();
11517 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11520 this.view = new Roo.View(this.list, this.tpl, {
11521 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11523 //this.view.wrapEl.setDisplayed(false);
11524 this.view.on('click', this.onViewClick, this);
11528 this.store.on('beforeload', this.onBeforeLoad, this);
11529 this.store.on('load', this.onLoad, this);
11530 this.store.on('loadexception', this.onLoadException, this);
11532 if(this.resizable){
11533 this.resizer = new Roo.Resizable(this.list, {
11534 pinned:true, handles:'se'
11536 this.resizer.on('resize', function(r, w, h){
11537 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11538 this.listWidth = w;
11539 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11540 this.restrictHeight();
11542 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11545 if(!this.editable){
11546 this.editable = true;
11547 this.setEditable(false);
11552 if (typeof(this.events.add.listeners) != 'undefined') {
11554 this.addicon = this.wrap.createChild(
11555 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11557 this.addicon.on('click', function(e) {
11558 this.fireEvent('add', this);
11561 if (typeof(this.events.edit.listeners) != 'undefined') {
11563 this.editicon = this.wrap.createChild(
11564 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11565 if (this.addicon) {
11566 this.editicon.setStyle('margin-left', '40px');
11568 this.editicon.on('click', function(e) {
11570 // we fire even if inothing is selected..
11571 this.fireEvent('edit', this, this.lastData );
11577 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11578 "up" : function(e){
11579 this.inKeyMode = true;
11583 "down" : function(e){
11584 if(!this.isExpanded()){
11585 this.onTriggerClick();
11587 this.inKeyMode = true;
11592 "enter" : function(e){
11593 // this.onViewClick();
11597 if(this.fireEvent("specialkey", this, e)){
11598 this.onViewClick(false);
11604 "esc" : function(e){
11608 "tab" : function(e){
11611 if(this.fireEvent("specialkey", this, e)){
11612 this.onViewClick(false);
11620 doRelay : function(foo, bar, hname){
11621 if(hname == 'down' || this.scope.isExpanded()){
11622 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11631 this.queryDelay = Math.max(this.queryDelay || 10,
11632 this.mode == 'local' ? 10 : 250);
11635 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11637 if(this.typeAhead){
11638 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11640 if(this.editable !== false){
11641 this.inputEl().on("keyup", this.onKeyUp, this);
11643 if(this.forceSelection){
11644 this.inputEl().on('blur', this.doForce, this);
11648 this.choices = this.el.select('ul.select2-choices', true).first();
11649 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11653 initTickableEvents: function()
11657 if(this.hiddenName){
11659 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11661 this.hiddenField.dom.value =
11662 this.hiddenValue !== undefined ? this.hiddenValue :
11663 this.value !== undefined ? this.value : '';
11665 // prevent input submission
11666 this.el.dom.removeAttribute('name');
11667 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11672 // this.list = this.el.select('ul.dropdown-menu',true).first();
11674 this.choices = this.el.select('ul.select2-choices', true).first();
11675 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11676 if(this.triggerList){
11677 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11680 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11681 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11683 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11684 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11686 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11687 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11689 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11690 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11691 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11694 this.cancelBtn.hide();
11699 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11700 _this.list.setWidth(lw);
11703 this.list.on('mouseover', this.onViewOver, this);
11704 this.list.on('mousemove', this.onViewMove, this);
11706 this.list.on('scroll', this.onViewScroll, this);
11709 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>';
11712 this.view = new Roo.View(this.list, this.tpl, {
11713 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11716 //this.view.wrapEl.setDisplayed(false);
11717 this.view.on('click', this.onViewClick, this);
11721 this.store.on('beforeload', this.onBeforeLoad, this);
11722 this.store.on('load', this.onLoad, this);
11723 this.store.on('loadexception', this.onLoadException, this);
11726 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11727 "up" : function(e){
11728 this.inKeyMode = true;
11732 "down" : function(e){
11733 this.inKeyMode = true;
11737 "enter" : function(e){
11738 if(this.fireEvent("specialkey", this, e)){
11739 this.onViewClick(false);
11745 "esc" : function(e){
11746 this.onTickableFooterButtonClick(e, false, false);
11749 "tab" : function(e){
11750 this.fireEvent("specialkey", this, e);
11752 this.onTickableFooterButtonClick(e, false, false);
11759 doRelay : function(e, fn, key){
11760 if(this.scope.isExpanded()){
11761 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11770 this.queryDelay = Math.max(this.queryDelay || 10,
11771 this.mode == 'local' ? 10 : 250);
11774 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11776 if(this.typeAhead){
11777 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11780 if(this.editable !== false){
11781 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11786 onDestroy : function(){
11788 this.view.setStore(null);
11789 this.view.el.removeAllListeners();
11790 this.view.el.remove();
11791 this.view.purgeListeners();
11794 this.list.dom.innerHTML = '';
11798 this.store.un('beforeload', this.onBeforeLoad, this);
11799 this.store.un('load', this.onLoad, this);
11800 this.store.un('loadexception', this.onLoadException, this);
11802 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11806 fireKey : function(e){
11807 if(e.isNavKeyPress() && !this.list.isVisible()){
11808 this.fireEvent("specialkey", this, e);
11813 onResize: function(w, h){
11814 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11816 // if(typeof w != 'number'){
11817 // // we do not handle it!?!?
11820 // var tw = this.trigger.getWidth();
11821 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11822 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11824 // this.inputEl().setWidth( this.adjustWidth('input', x));
11826 // //this.trigger.setStyle('left', x+'px');
11828 // if(this.list && this.listWidth === undefined){
11829 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11830 // this.list.setWidth(lw);
11831 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11839 * Allow or prevent the user from directly editing the field text. If false is passed,
11840 * the user will only be able to select from the items defined in the dropdown list. This method
11841 * is the runtime equivalent of setting the 'editable' config option at config time.
11842 * @param {Boolean} value True to allow the user to directly edit the field text
11844 setEditable : function(value){
11845 if(value == this.editable){
11848 this.editable = value;
11850 this.inputEl().dom.setAttribute('readOnly', true);
11851 this.inputEl().on('mousedown', this.onTriggerClick, this);
11852 this.inputEl().addClass('x-combo-noedit');
11854 this.inputEl().dom.setAttribute('readOnly', false);
11855 this.inputEl().un('mousedown', this.onTriggerClick, this);
11856 this.inputEl().removeClass('x-combo-noedit');
11862 onBeforeLoad : function(combo,opts){
11863 if(!this.hasFocus){
11867 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11869 this.restrictHeight();
11870 this.selectedIndex = -1;
11874 onLoad : function(){
11876 this.hasQuery = false;
11878 if(!this.hasFocus){
11882 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11883 this.loading.hide();
11886 if(this.store.getCount() > 0){
11888 this.restrictHeight();
11889 if(this.lastQuery == this.allQuery){
11890 if(this.editable && !this.tickable){
11891 this.inputEl().dom.select();
11895 !this.selectByValue(this.value, true) &&
11898 !this.store.lastOptions ||
11899 typeof(this.store.lastOptions.add) == 'undefined' ||
11900 this.store.lastOptions.add != true
11903 this.select(0, true);
11906 if(this.autoFocus){
11909 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11910 this.taTask.delay(this.typeAheadDelay);
11914 this.onEmptyResults();
11920 onLoadException : function()
11922 this.hasQuery = false;
11924 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11925 this.loading.hide();
11928 if(this.tickable && this.editable){
11934 Roo.log(this.store.reader.jsonData);
11935 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11937 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11943 onTypeAhead : function(){
11944 if(this.store.getCount() > 0){
11945 var r = this.store.getAt(0);
11946 var newValue = r.data[this.displayField];
11947 var len = newValue.length;
11948 var selStart = this.getRawValue().length;
11950 if(selStart != len){
11951 this.setRawValue(newValue);
11952 this.selectText(selStart, newValue.length);
11958 onSelect : function(record, index){
11960 if(this.fireEvent('beforeselect', this, record, index) !== false){
11962 this.setFromData(index > -1 ? record.data : false);
11965 this.fireEvent('select', this, record, index);
11970 * Returns the currently selected field value or empty string if no value is set.
11971 * @return {String} value The selected value
11973 getValue : function(){
11976 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11979 if(this.valueField){
11980 return typeof this.value != 'undefined' ? this.value : '';
11982 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11987 * Clears any text/value currently set in the field
11989 clearValue : function(){
11990 if(this.hiddenField){
11991 this.hiddenField.dom.value = '';
11994 this.setRawValue('');
11995 this.lastSelectionText = '';
11996 this.lastData = false;
12001 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12002 * will be displayed in the field. If the value does not match the data value of an existing item,
12003 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12004 * Otherwise the field will be blank (although the value will still be set).
12005 * @param {String} value The value to match
12007 setValue : function(v){
12014 if(this.valueField){
12015 var r = this.findRecord(this.valueField, v);
12017 text = r.data[this.displayField];
12018 }else if(this.valueNotFoundText !== undefined){
12019 text = this.valueNotFoundText;
12022 this.lastSelectionText = text;
12023 if(this.hiddenField){
12024 this.hiddenField.dom.value = v;
12026 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12029 var close = this.closeTriggerEl();
12032 (v.length || v * 1 > 0) ? close.show() : close.hide();
12036 * @property {Object} the last set data for the element
12041 * Sets the value of the field based on a object which is related to the record format for the store.
12042 * @param {Object} value the value to set as. or false on reset?
12044 setFromData : function(o){
12051 var dv = ''; // display value
12052 var vv = ''; // value value..
12054 if (this.displayField) {
12055 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12057 // this is an error condition!!!
12058 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12061 if(this.valueField){
12062 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12065 var close = this.closeTriggerEl();
12068 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12071 if(this.hiddenField){
12072 this.hiddenField.dom.value = vv;
12074 this.lastSelectionText = dv;
12075 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12079 // no hidden field.. - we store the value in 'value', but still display
12080 // display field!!!!
12081 this.lastSelectionText = dv;
12082 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12089 reset : function(){
12090 // overridden so that last data is reset..
12097 this.setValue(this.originalValue);
12098 this.clearInvalid();
12099 this.lastData = false;
12101 this.view.clearSelections();
12105 findRecord : function(prop, value){
12107 if(this.store.getCount() > 0){
12108 this.store.each(function(r){
12109 if(r.data[prop] == value){
12119 getName: function()
12121 // returns hidden if it's set..
12122 if (!this.rendered) {return ''};
12123 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12127 onViewMove : function(e, t){
12128 this.inKeyMode = false;
12132 onViewOver : function(e, t){
12133 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12136 var item = this.view.findItemFromChild(t);
12139 var index = this.view.indexOf(item);
12140 this.select(index, false);
12145 onViewClick : function(view, doFocus, el, e)
12147 var index = this.view.getSelectedIndexes()[0];
12149 var r = this.store.getAt(index);
12153 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12160 Roo.each(this.tickItems, function(v,k){
12162 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12163 _this.tickItems.splice(k, 1);
12165 if(typeof(e) == 'undefined' && view == false){
12166 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12178 this.tickItems.push(r.data);
12180 if(typeof(e) == 'undefined' && view == false){
12181 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12188 this.onSelect(r, index);
12190 if(doFocus !== false && !this.blockFocus){
12191 this.inputEl().focus();
12196 restrictHeight : function(){
12197 //this.innerList.dom.style.height = '';
12198 //var inner = this.innerList.dom;
12199 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12200 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12201 //this.list.beginUpdate();
12202 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12203 this.list.alignTo(this.inputEl(), this.listAlign);
12204 this.list.alignTo(this.inputEl(), this.listAlign);
12205 //this.list.endUpdate();
12209 onEmptyResults : function(){
12211 if(this.tickable && this.editable){
12212 this.restrictHeight();
12220 * Returns true if the dropdown list is expanded, else false.
12222 isExpanded : function(){
12223 return this.list.isVisible();
12227 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12228 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12229 * @param {String} value The data value of the item to select
12230 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12231 * selected item if it is not currently in view (defaults to true)
12232 * @return {Boolean} True if the value matched an item in the list, else false
12234 selectByValue : function(v, scrollIntoView){
12235 if(v !== undefined && v !== null){
12236 var r = this.findRecord(this.valueField || this.displayField, v);
12238 this.select(this.store.indexOf(r), scrollIntoView);
12246 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12247 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12248 * @param {Number} index The zero-based index of the list item to select
12249 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12250 * selected item if it is not currently in view (defaults to true)
12252 select : function(index, scrollIntoView){
12253 this.selectedIndex = index;
12254 this.view.select(index);
12255 if(scrollIntoView !== false){
12256 var el = this.view.getNode(index);
12258 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12261 this.list.scrollChildIntoView(el, false);
12267 selectNext : function(){
12268 var ct = this.store.getCount();
12270 if(this.selectedIndex == -1){
12272 }else if(this.selectedIndex < ct-1){
12273 this.select(this.selectedIndex+1);
12279 selectPrev : function(){
12280 var ct = this.store.getCount();
12282 if(this.selectedIndex == -1){
12284 }else if(this.selectedIndex != 0){
12285 this.select(this.selectedIndex-1);
12291 onKeyUp : function(e){
12292 if(this.editable !== false && !e.isSpecialKey()){
12293 this.lastKey = e.getKey();
12294 this.dqTask.delay(this.queryDelay);
12299 validateBlur : function(){
12300 return !this.list || !this.list.isVisible();
12304 initQuery : function(){
12306 var v = this.getRawValue();
12308 if(this.tickable && this.editable){
12309 v = this.tickableInputEl().getValue();
12316 doForce : function(){
12317 if(this.inputEl().dom.value.length > 0){
12318 this.inputEl().dom.value =
12319 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12325 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12326 * query allowing the query action to be canceled if needed.
12327 * @param {String} query The SQL query to execute
12328 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12329 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12330 * saved in the current store (defaults to false)
12332 doQuery : function(q, forceAll){
12334 if(q === undefined || q === null){
12339 forceAll: forceAll,
12343 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12348 forceAll = qe.forceAll;
12349 if(forceAll === true || (q.length >= this.minChars)){
12351 this.hasQuery = true;
12353 if(this.lastQuery != q || this.alwaysQuery){
12354 this.lastQuery = q;
12355 if(this.mode == 'local'){
12356 this.selectedIndex = -1;
12358 this.store.clearFilter();
12361 if(this.specialFilter){
12362 this.fireEvent('specialfilter', this);
12367 this.store.filter(this.displayField, q);
12370 this.store.fireEvent("datachanged", this.store);
12377 this.store.baseParams[this.queryParam] = q;
12379 var options = {params : this.getParams(q)};
12382 options.add = true;
12383 options.params.start = this.page * this.pageSize;
12386 this.store.load(options);
12389 * this code will make the page width larger, at the beginning, the list not align correctly,
12390 * we should expand the list on onLoad
12391 * so command out it
12396 this.selectedIndex = -1;
12401 this.loadNext = false;
12405 getParams : function(q){
12407 //p[this.queryParam] = q;
12411 p.limit = this.pageSize;
12417 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12419 collapse : function(){
12420 if(!this.isExpanded()){
12427 this.hasFocus = false;
12429 this.cancelBtn.hide();
12430 this.trigger.show();
12433 this.tickableInputEl().dom.value = '';
12434 this.tickableInputEl().blur();
12439 Roo.get(document).un('mousedown', this.collapseIf, this);
12440 Roo.get(document).un('mousewheel', this.collapseIf, this);
12441 if (!this.editable) {
12442 Roo.get(document).un('keydown', this.listKeyPress, this);
12444 this.fireEvent('collapse', this);
12448 collapseIf : function(e){
12449 var in_combo = e.within(this.el);
12450 var in_list = e.within(this.list);
12451 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12453 if (in_combo || in_list || is_list) {
12454 //e.stopPropagation();
12459 this.onTickableFooterButtonClick(e, false, false);
12467 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12469 expand : function(){
12471 if(this.isExpanded() || !this.hasFocus){
12475 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12476 this.list.setWidth(lw);
12483 this.restrictHeight();
12487 this.tickItems = Roo.apply([], this.item);
12490 this.cancelBtn.show();
12491 this.trigger.hide();
12494 this.tickableInputEl().focus();
12499 Roo.get(document).on('mousedown', this.collapseIf, this);
12500 Roo.get(document).on('mousewheel', this.collapseIf, this);
12501 if (!this.editable) {
12502 Roo.get(document).on('keydown', this.listKeyPress, this);
12505 this.fireEvent('expand', this);
12509 // Implements the default empty TriggerField.onTriggerClick function
12510 onTriggerClick : function(e)
12512 Roo.log('trigger click');
12514 if(this.disabled || !this.triggerList){
12519 this.loadNext = false;
12521 if(this.isExpanded()){
12523 if (!this.blockFocus) {
12524 this.inputEl().focus();
12528 this.hasFocus = true;
12529 if(this.triggerAction == 'all') {
12530 this.doQuery(this.allQuery, true);
12532 this.doQuery(this.getRawValue());
12534 if (!this.blockFocus) {
12535 this.inputEl().focus();
12540 onTickableTriggerClick : function(e)
12547 this.loadNext = false;
12548 this.hasFocus = true;
12550 if(this.triggerAction == 'all') {
12551 this.doQuery(this.allQuery, true);
12553 this.doQuery(this.getRawValue());
12557 onSearchFieldClick : function(e)
12559 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12560 this.onTickableFooterButtonClick(e, false, false);
12564 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12569 this.loadNext = false;
12570 this.hasFocus = true;
12572 if(this.triggerAction == 'all') {
12573 this.doQuery(this.allQuery, true);
12575 this.doQuery(this.getRawValue());
12579 listKeyPress : function(e)
12581 //Roo.log('listkeypress');
12582 // scroll to first matching element based on key pres..
12583 if (e.isSpecialKey()) {
12586 var k = String.fromCharCode(e.getKey()).toUpperCase();
12589 var csel = this.view.getSelectedNodes();
12590 var cselitem = false;
12592 var ix = this.view.indexOf(csel[0]);
12593 cselitem = this.store.getAt(ix);
12594 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12600 this.store.each(function(v) {
12602 // start at existing selection.
12603 if (cselitem.id == v.id) {
12609 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12610 match = this.store.indexOf(v);
12616 if (match === false) {
12617 return true; // no more action?
12620 this.view.select(match);
12621 var sn = Roo.get(this.view.getSelectedNodes()[0])
12622 sn.scrollIntoView(sn.dom.parentNode, false);
12625 onViewScroll : function(e, t){
12627 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){
12631 this.hasQuery = true;
12633 this.loading = this.list.select('.loading', true).first();
12635 if(this.loading === null){
12636 this.list.createChild({
12638 cls: 'loading select2-more-results select2-active',
12639 html: 'Loading more results...'
12642 this.loading = this.list.select('.loading', true).first();
12644 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12646 this.loading.hide();
12649 this.loading.show();
12654 this.loadNext = true;
12656 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12661 addItem : function(o)
12663 var dv = ''; // display value
12665 if (this.displayField) {
12666 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12668 // this is an error condition!!!
12669 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12676 var choice = this.choices.createChild({
12678 cls: 'select2-search-choice',
12687 cls: 'select2-search-choice-close',
12692 }, this.searchField);
12694 var close = choice.select('a.select2-search-choice-close', true).first()
12696 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12704 this.inputEl().dom.value = '';
12709 onRemoveItem : function(e, _self, o)
12711 e.preventDefault();
12713 this.lastItem = Roo.apply([], this.item);
12715 var index = this.item.indexOf(o.data) * 1;
12718 Roo.log('not this item?!');
12722 this.item.splice(index, 1);
12727 this.fireEvent('remove', this, e);
12733 syncValue : function()
12735 if(!this.item.length){
12742 Roo.each(this.item, function(i){
12743 if(_this.valueField){
12744 value.push(i[_this.valueField]);
12751 this.value = value.join(',');
12753 if(this.hiddenField){
12754 this.hiddenField.dom.value = this.value;
12757 this.store.fireEvent("datachanged", this.store);
12760 clearItem : function()
12762 if(!this.multiple){
12768 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12777 inputEl: function ()
12780 return this.searchField;
12782 return this.el.select('input.form-control',true).first();
12786 onTickableFooterButtonClick : function(e, btn, el)
12788 e.preventDefault();
12790 this.lastItem = Roo.apply([], this.item);
12792 if(btn && btn.name == 'cancel'){
12793 this.tickItems = Roo.apply([], this.item);
12802 Roo.each(this.tickItems, function(o){
12810 validate : function()
12812 var v = this.getRawValue();
12815 v = this.getValue();
12818 if(this.disabled || this.allowBlank || v.length){
12823 this.markInvalid();
12827 tickableInputEl : function()
12829 if(!this.tickable || !this.editable){
12830 return this.inputEl();
12833 return this.inputEl().select('.select2-search-field-input', true).first();
12839 * @cfg {Boolean} grow
12843 * @cfg {Number} growMin
12847 * @cfg {Number} growMax
12857 * Ext JS Library 1.1.1
12858 * Copyright(c) 2006-2007, Ext JS, LLC.
12860 * Originally Released Under LGPL - original licence link has changed is not relivant.
12863 * <script type="text/javascript">
12868 * @extends Roo.util.Observable
12869 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12870 * This class also supports single and multi selection modes. <br>
12871 * Create a data model bound view:
12873 var store = new Roo.data.Store(...);
12875 var view = new Roo.View({
12877 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12879 singleSelect: true,
12880 selectedClass: "ydataview-selected",
12884 // listen for node click?
12885 view.on("click", function(vw, index, node, e){
12886 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12890 dataModel.load("foobar.xml");
12892 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12894 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12895 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12897 * Note: old style constructor is still suported (container, template, config)
12900 * Create a new View
12901 * @param {Object} config The config object
12904 Roo.View = function(config, depreciated_tpl, depreciated_config){
12906 this.parent = false;
12908 if (typeof(depreciated_tpl) == 'undefined') {
12909 // new way.. - universal constructor.
12910 Roo.apply(this, config);
12911 this.el = Roo.get(this.el);
12914 this.el = Roo.get(config);
12915 this.tpl = depreciated_tpl;
12916 Roo.apply(this, depreciated_config);
12918 this.wrapEl = this.el.wrap().wrap();
12919 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12922 if(typeof(this.tpl) == "string"){
12923 this.tpl = new Roo.Template(this.tpl);
12925 // support xtype ctors..
12926 this.tpl = new Roo.factory(this.tpl, Roo);
12930 this.tpl.compile();
12935 * @event beforeclick
12936 * Fires before a click is processed. Returns false to cancel the default action.
12937 * @param {Roo.View} this
12938 * @param {Number} index The index of the target node
12939 * @param {HTMLElement} node The target node
12940 * @param {Roo.EventObject} e The raw event object
12942 "beforeclick" : true,
12945 * Fires when a template node is clicked.
12946 * @param {Roo.View} this
12947 * @param {Number} index The index of the target node
12948 * @param {HTMLElement} node The target node
12949 * @param {Roo.EventObject} e The raw event object
12954 * Fires when a template node is double clicked.
12955 * @param {Roo.View} this
12956 * @param {Number} index The index of the target node
12957 * @param {HTMLElement} node The target node
12958 * @param {Roo.EventObject} e The raw event object
12962 * @event contextmenu
12963 * Fires when a template node is right clicked.
12964 * @param {Roo.View} this
12965 * @param {Number} index The index of the target node
12966 * @param {HTMLElement} node The target node
12967 * @param {Roo.EventObject} e The raw event object
12969 "contextmenu" : true,
12971 * @event selectionchange
12972 * Fires when the selected nodes change.
12973 * @param {Roo.View} this
12974 * @param {Array} selections Array of the selected nodes
12976 "selectionchange" : true,
12979 * @event beforeselect
12980 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12981 * @param {Roo.View} this
12982 * @param {HTMLElement} node The node to be selected
12983 * @param {Array} selections Array of currently selected nodes
12985 "beforeselect" : true,
12987 * @event preparedata
12988 * Fires on every row to render, to allow you to change the data.
12989 * @param {Roo.View} this
12990 * @param {Object} data to be rendered (change this)
12992 "preparedata" : true
13000 "click": this.onClick,
13001 "dblclick": this.onDblClick,
13002 "contextmenu": this.onContextMenu,
13006 this.selections = [];
13008 this.cmp = new Roo.CompositeElementLite([]);
13010 this.store = Roo.factory(this.store, Roo.data);
13011 this.setStore(this.store, true);
13014 if ( this.footer && this.footer.xtype) {
13016 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13018 this.footer.dataSource = this.store
13019 this.footer.container = fctr;
13020 this.footer = Roo.factory(this.footer, Roo);
13021 fctr.insertFirst(this.el);
13023 // this is a bit insane - as the paging toolbar seems to detach the el..
13024 // dom.parentNode.parentNode.parentNode
13025 // they get detached?
13029 Roo.View.superclass.constructor.call(this);
13034 Roo.extend(Roo.View, Roo.util.Observable, {
13037 * @cfg {Roo.data.Store} store Data store to load data from.
13042 * @cfg {String|Roo.Element} el The container element.
13047 * @cfg {String|Roo.Template} tpl The template used by this View
13051 * @cfg {String} dataName the named area of the template to use as the data area
13052 * Works with domtemplates roo-name="name"
13056 * @cfg {String} selectedClass The css class to add to selected nodes
13058 selectedClass : "x-view-selected",
13060 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13065 * @cfg {String} text to display on mask (default Loading)
13069 * @cfg {Boolean} multiSelect Allow multiple selection
13071 multiSelect : false,
13073 * @cfg {Boolean} singleSelect Allow single selection
13075 singleSelect: false,
13078 * @cfg {Boolean} toggleSelect - selecting
13080 toggleSelect : false,
13083 * @cfg {Boolean} tickable - selecting
13088 * Returns the element this view is bound to.
13089 * @return {Roo.Element}
13091 getEl : function(){
13092 return this.wrapEl;
13098 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13100 refresh : function(){
13101 //Roo.log('refresh');
13104 // if we are using something like 'domtemplate', then
13105 // the what gets used is:
13106 // t.applySubtemplate(NAME, data, wrapping data..)
13107 // the outer template then get' applied with
13108 // the store 'extra data'
13109 // and the body get's added to the
13110 // roo-name="data" node?
13111 // <span class='roo-tpl-{name}'></span> ?????
13115 this.clearSelections();
13116 this.el.update("");
13118 var records = this.store.getRange();
13119 if(records.length < 1) {
13121 // is this valid?? = should it render a template??
13123 this.el.update(this.emptyText);
13127 if (this.dataName) {
13128 this.el.update(t.apply(this.store.meta)); //????
13129 el = this.el.child('.roo-tpl-' + this.dataName);
13132 for(var i = 0, len = records.length; i < len; i++){
13133 var data = this.prepareData(records[i].data, i, records[i]);
13134 this.fireEvent("preparedata", this, data, i, records[i]);
13136 var d = Roo.apply({}, data);
13139 Roo.apply(d, {'roo-id' : Roo.id()});
13143 Roo.each(this.parent.item, function(item){
13144 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13147 Roo.apply(d, {'roo-data-checked' : 'checked'});
13151 html[html.length] = Roo.util.Format.trim(
13153 t.applySubtemplate(this.dataName, d, this.store.meta) :
13160 el.update(html.join(""));
13161 this.nodes = el.dom.childNodes;
13162 this.updateIndexes(0);
13167 * Function to override to reformat the data that is sent to
13168 * the template for each node.
13169 * DEPRICATED - use the preparedata event handler.
13170 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13171 * a JSON object for an UpdateManager bound view).
13173 prepareData : function(data, index, record)
13175 this.fireEvent("preparedata", this, data, index, record);
13179 onUpdate : function(ds, record){
13180 // Roo.log('on update');
13181 this.clearSelections();
13182 var index = this.store.indexOf(record);
13183 var n = this.nodes[index];
13184 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13185 n.parentNode.removeChild(n);
13186 this.updateIndexes(index, index);
13192 onAdd : function(ds, records, index)
13194 //Roo.log(['on Add', ds, records, index] );
13195 this.clearSelections();
13196 if(this.nodes.length == 0){
13200 var n = this.nodes[index];
13201 for(var i = 0, len = records.length; i < len; i++){
13202 var d = this.prepareData(records[i].data, i, records[i]);
13204 this.tpl.insertBefore(n, d);
13207 this.tpl.append(this.el, d);
13210 this.updateIndexes(index);
13213 onRemove : function(ds, record, index){
13214 // Roo.log('onRemove');
13215 this.clearSelections();
13216 var el = this.dataName ?
13217 this.el.child('.roo-tpl-' + this.dataName) :
13220 el.dom.removeChild(this.nodes[index]);
13221 this.updateIndexes(index);
13225 * Refresh an individual node.
13226 * @param {Number} index
13228 refreshNode : function(index){
13229 this.onUpdate(this.store, this.store.getAt(index));
13232 updateIndexes : function(startIndex, endIndex){
13233 var ns = this.nodes;
13234 startIndex = startIndex || 0;
13235 endIndex = endIndex || ns.length - 1;
13236 for(var i = startIndex; i <= endIndex; i++){
13237 ns[i].nodeIndex = i;
13242 * Changes the data store this view uses and refresh the view.
13243 * @param {Store} store
13245 setStore : function(store, initial){
13246 if(!initial && this.store){
13247 this.store.un("datachanged", this.refresh);
13248 this.store.un("add", this.onAdd);
13249 this.store.un("remove", this.onRemove);
13250 this.store.un("update", this.onUpdate);
13251 this.store.un("clear", this.refresh);
13252 this.store.un("beforeload", this.onBeforeLoad);
13253 this.store.un("load", this.onLoad);
13254 this.store.un("loadexception", this.onLoad);
13258 store.on("datachanged", this.refresh, this);
13259 store.on("add", this.onAdd, this);
13260 store.on("remove", this.onRemove, this);
13261 store.on("update", this.onUpdate, this);
13262 store.on("clear", this.refresh, this);
13263 store.on("beforeload", this.onBeforeLoad, this);
13264 store.on("load", this.onLoad, this);
13265 store.on("loadexception", this.onLoad, this);
13273 * onbeforeLoad - masks the loading area.
13276 onBeforeLoad : function(store,opts)
13278 //Roo.log('onBeforeLoad');
13280 this.el.update("");
13282 this.el.mask(this.mask ? this.mask : "Loading" );
13284 onLoad : function ()
13291 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13292 * @param {HTMLElement} node
13293 * @return {HTMLElement} The template node
13295 findItemFromChild : function(node){
13296 var el = this.dataName ?
13297 this.el.child('.roo-tpl-' + this.dataName,true) :
13300 if(!node || node.parentNode == el){
13303 var p = node.parentNode;
13304 while(p && p != el){
13305 if(p.parentNode == el){
13314 onClick : function(e){
13315 var item = this.findItemFromChild(e.getTarget());
13317 var index = this.indexOf(item);
13318 if(this.onItemClick(item, index, e) !== false){
13319 this.fireEvent("click", this, index, item, e);
13322 this.clearSelections();
13327 onContextMenu : function(e){
13328 var item = this.findItemFromChild(e.getTarget());
13330 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13335 onDblClick : function(e){
13336 var item = this.findItemFromChild(e.getTarget());
13338 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13342 onItemClick : function(item, index, e)
13344 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13347 if (this.toggleSelect) {
13348 var m = this.isSelected(item) ? 'unselect' : 'select';
13351 _t[m](item, true, false);
13354 if(this.multiSelect || this.singleSelect){
13355 if(this.multiSelect && e.shiftKey && this.lastSelection){
13356 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13358 this.select(item, this.multiSelect && e.ctrlKey);
13359 this.lastSelection = item;
13362 if(!this.tickable){
13363 e.preventDefault();
13371 * Get the number of selected nodes.
13374 getSelectionCount : function(){
13375 return this.selections.length;
13379 * Get the currently selected nodes.
13380 * @return {Array} An array of HTMLElements
13382 getSelectedNodes : function(){
13383 return this.selections;
13387 * Get the indexes of the selected nodes.
13390 getSelectedIndexes : function(){
13391 var indexes = [], s = this.selections;
13392 for(var i = 0, len = s.length; i < len; i++){
13393 indexes.push(s[i].nodeIndex);
13399 * Clear all selections
13400 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13402 clearSelections : function(suppressEvent){
13403 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13404 this.cmp.elements = this.selections;
13405 this.cmp.removeClass(this.selectedClass);
13406 this.selections = [];
13407 if(!suppressEvent){
13408 this.fireEvent("selectionchange", this, this.selections);
13414 * Returns true if the passed node is selected
13415 * @param {HTMLElement/Number} node The node or node index
13416 * @return {Boolean}
13418 isSelected : function(node){
13419 var s = this.selections;
13423 node = this.getNode(node);
13424 return s.indexOf(node) !== -1;
13429 * @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
13430 * @param {Boolean} keepExisting (optional) true to keep existing selections
13431 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13433 select : function(nodeInfo, keepExisting, suppressEvent){
13434 if(nodeInfo instanceof Array){
13436 this.clearSelections(true);
13438 for(var i = 0, len = nodeInfo.length; i < len; i++){
13439 this.select(nodeInfo[i], true, true);
13443 var node = this.getNode(nodeInfo);
13444 if(!node || this.isSelected(node)){
13445 return; // already selected.
13448 this.clearSelections(true);
13451 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13452 Roo.fly(node).addClass(this.selectedClass);
13453 this.selections.push(node);
13454 if(!suppressEvent){
13455 this.fireEvent("selectionchange", this, this.selections);
13463 * @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
13464 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13465 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13467 unselect : function(nodeInfo, keepExisting, suppressEvent)
13469 if(nodeInfo instanceof Array){
13470 Roo.each(this.selections, function(s) {
13471 this.unselect(s, nodeInfo);
13475 var node = this.getNode(nodeInfo);
13476 if(!node || !this.isSelected(node)){
13477 //Roo.log("not selected");
13478 return; // not selected.
13482 Roo.each(this.selections, function(s) {
13484 Roo.fly(node).removeClass(this.selectedClass);
13491 this.selections= ns;
13492 this.fireEvent("selectionchange", this, this.selections);
13496 * Gets a template node.
13497 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13498 * @return {HTMLElement} The node or null if it wasn't found
13500 getNode : function(nodeInfo){
13501 if(typeof nodeInfo == "string"){
13502 return document.getElementById(nodeInfo);
13503 }else if(typeof nodeInfo == "number"){
13504 return this.nodes[nodeInfo];
13510 * Gets a range template nodes.
13511 * @param {Number} startIndex
13512 * @param {Number} endIndex
13513 * @return {Array} An array of nodes
13515 getNodes : function(start, end){
13516 var ns = this.nodes;
13517 start = start || 0;
13518 end = typeof end == "undefined" ? ns.length - 1 : end;
13521 for(var i = start; i <= end; i++){
13525 for(var i = start; i >= end; i--){
13533 * Finds the index of the passed node
13534 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13535 * @return {Number} The index of the node or -1
13537 indexOf : function(node){
13538 node = this.getNode(node);
13539 if(typeof node.nodeIndex == "number"){
13540 return node.nodeIndex;
13542 var ns = this.nodes;
13543 for(var i = 0, len = ns.length; i < len; i++){
13554 * based on jquery fullcalendar
13558 Roo.bootstrap = Roo.bootstrap || {};
13560 * @class Roo.bootstrap.Calendar
13561 * @extends Roo.bootstrap.Component
13562 * Bootstrap Calendar class
13563 * @cfg {Boolean} loadMask (true|false) default false
13564 * @cfg {Object} header generate the user specific header of the calendar, default false
13567 * Create a new Container
13568 * @param {Object} config The config object
13573 Roo.bootstrap.Calendar = function(config){
13574 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13578 * Fires when a date is selected
13579 * @param {DatePicker} this
13580 * @param {Date} date The selected date
13584 * @event monthchange
13585 * Fires when the displayed month changes
13586 * @param {DatePicker} this
13587 * @param {Date} date The selected month
13589 'monthchange': true,
13591 * @event evententer
13592 * Fires when mouse over an event
13593 * @param {Calendar} this
13594 * @param {event} Event
13596 'evententer': true,
13598 * @event eventleave
13599 * Fires when the mouse leaves an
13600 * @param {Calendar} this
13603 'eventleave': true,
13605 * @event eventclick
13606 * Fires when the mouse click an
13607 * @param {Calendar} this
13616 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13619 * @cfg {Number} startDay
13620 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13628 getAutoCreate : function(){
13631 var fc_button = function(name, corner, style, content ) {
13632 return Roo.apply({},{
13634 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13636 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13639 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13650 style : 'width:100%',
13657 cls : 'fc-header-left',
13659 fc_button('prev', 'left', 'arrow', '‹' ),
13660 fc_button('next', 'right', 'arrow', '›' ),
13661 { tag: 'span', cls: 'fc-header-space' },
13662 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13670 cls : 'fc-header-center',
13674 cls: 'fc-header-title',
13677 html : 'month / year'
13685 cls : 'fc-header-right',
13687 /* fc_button('month', 'left', '', 'month' ),
13688 fc_button('week', '', '', 'week' ),
13689 fc_button('day', 'right', '', 'day' )
13701 header = this.header;
13704 var cal_heads = function() {
13706 // fixme - handle this.
13708 for (var i =0; i < Date.dayNames.length; i++) {
13709 var d = Date.dayNames[i];
13712 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13713 html : d.substring(0,3)
13717 ret[0].cls += ' fc-first';
13718 ret[6].cls += ' fc-last';
13721 var cal_cell = function(n) {
13724 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13729 cls: 'fc-day-number',
13733 cls: 'fc-day-content',
13737 style: 'position: relative;' // height: 17px;
13749 var cal_rows = function() {
13752 for (var r = 0; r < 6; r++) {
13759 for (var i =0; i < Date.dayNames.length; i++) {
13760 var d = Date.dayNames[i];
13761 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13764 row.cn[0].cls+=' fc-first';
13765 row.cn[0].cn[0].style = 'min-height:90px';
13766 row.cn[6].cls+=' fc-last';
13770 ret[0].cls += ' fc-first';
13771 ret[4].cls += ' fc-prev-last';
13772 ret[5].cls += ' fc-last';
13779 cls: 'fc-border-separate',
13780 style : 'width:100%',
13788 cls : 'fc-first fc-last',
13806 cls : 'fc-content',
13807 style : "position: relative;",
13810 cls : 'fc-view fc-view-month fc-grid',
13811 style : 'position: relative',
13812 unselectable : 'on',
13815 cls : 'fc-event-container',
13816 style : 'position:absolute;z-index:8;top:0;left:0;'
13834 initEvents : function()
13837 throw "can not find store for calendar";
13843 style: "text-align:center",
13847 style: "background-color:white;width:50%;margin:250 auto",
13851 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13862 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13864 var size = this.el.select('.fc-content', true).first().getSize();
13865 this.maskEl.setSize(size.width, size.height);
13866 this.maskEl.enableDisplayMode("block");
13867 if(!this.loadMask){
13868 this.maskEl.hide();
13871 this.store = Roo.factory(this.store, Roo.data);
13872 this.store.on('load', this.onLoad, this);
13873 this.store.on('beforeload', this.onBeforeLoad, this);
13877 this.cells = this.el.select('.fc-day',true);
13878 //Roo.log(this.cells);
13879 this.textNodes = this.el.query('.fc-day-number');
13880 this.cells.addClassOnOver('fc-state-hover');
13882 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13883 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13884 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13885 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13887 this.on('monthchange', this.onMonthChange, this);
13889 this.update(new Date().clearTime());
13892 resize : function() {
13893 var sz = this.el.getSize();
13895 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13896 this.el.select('.fc-day-content div',true).setHeight(34);
13901 showPrevMonth : function(e){
13902 this.update(this.activeDate.add("mo", -1));
13904 showToday : function(e){
13905 this.update(new Date().clearTime());
13908 showNextMonth : function(e){
13909 this.update(this.activeDate.add("mo", 1));
13913 showPrevYear : function(){
13914 this.update(this.activeDate.add("y", -1));
13918 showNextYear : function(){
13919 this.update(this.activeDate.add("y", 1));
13924 update : function(date)
13926 var vd = this.activeDate;
13927 this.activeDate = date;
13928 // if(vd && this.el){
13929 // var t = date.getTime();
13930 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13931 // Roo.log('using add remove');
13933 // this.fireEvent('monthchange', this, date);
13935 // this.cells.removeClass("fc-state-highlight");
13936 // this.cells.each(function(c){
13937 // if(c.dateValue == t){
13938 // c.addClass("fc-state-highlight");
13939 // setTimeout(function(){
13940 // try{c.dom.firstChild.focus();}catch(e){}
13950 var days = date.getDaysInMonth();
13952 var firstOfMonth = date.getFirstDateOfMonth();
13953 var startingPos = firstOfMonth.getDay()-this.startDay;
13955 if(startingPos < this.startDay){
13959 var pm = date.add(Date.MONTH, -1);
13960 var prevStart = pm.getDaysInMonth()-startingPos;
13962 this.cells = this.el.select('.fc-day',true);
13963 this.textNodes = this.el.query('.fc-day-number');
13964 this.cells.addClassOnOver('fc-state-hover');
13966 var cells = this.cells.elements;
13967 var textEls = this.textNodes;
13969 Roo.each(cells, function(cell){
13970 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13973 days += startingPos;
13975 // convert everything to numbers so it's fast
13976 var day = 86400000;
13977 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13980 //Roo.log(prevStart);
13982 var today = new Date().clearTime().getTime();
13983 var sel = date.clearTime().getTime();
13984 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13985 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13986 var ddMatch = this.disabledDatesRE;
13987 var ddText = this.disabledDatesText;
13988 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13989 var ddaysText = this.disabledDaysText;
13990 var format = this.format;
13992 var setCellClass = function(cal, cell){
13996 //Roo.log('set Cell Class');
13998 var t = d.getTime();
14002 cell.dateValue = t;
14004 cell.className += " fc-today";
14005 cell.className += " fc-state-highlight";
14006 cell.title = cal.todayText;
14009 // disable highlight in other month..
14010 //cell.className += " fc-state-highlight";
14015 cell.className = " fc-state-disabled";
14016 cell.title = cal.minText;
14020 cell.className = " fc-state-disabled";
14021 cell.title = cal.maxText;
14025 if(ddays.indexOf(d.getDay()) != -1){
14026 cell.title = ddaysText;
14027 cell.className = " fc-state-disabled";
14030 if(ddMatch && format){
14031 var fvalue = d.dateFormat(format);
14032 if(ddMatch.test(fvalue)){
14033 cell.title = ddText.replace("%0", fvalue);
14034 cell.className = " fc-state-disabled";
14038 if (!cell.initialClassName) {
14039 cell.initialClassName = cell.dom.className;
14042 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14047 for(; i < startingPos; i++) {
14048 textEls[i].innerHTML = (++prevStart);
14049 d.setDate(d.getDate()+1);
14051 cells[i].className = "fc-past fc-other-month";
14052 setCellClass(this, cells[i]);
14057 for(; i < days; i++){
14058 intDay = i - startingPos + 1;
14059 textEls[i].innerHTML = (intDay);
14060 d.setDate(d.getDate()+1);
14062 cells[i].className = ''; // "x-date-active";
14063 setCellClass(this, cells[i]);
14067 for(; i < 42; i++) {
14068 textEls[i].innerHTML = (++extraDays);
14069 d.setDate(d.getDate()+1);
14071 cells[i].className = "fc-future fc-other-month";
14072 setCellClass(this, cells[i]);
14075 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14077 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14079 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14080 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14082 if(totalRows != 6){
14083 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14084 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14087 this.fireEvent('monthchange', this, date);
14091 if(!this.internalRender){
14092 var main = this.el.dom.firstChild;
14093 var w = main.offsetWidth;
14094 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14095 Roo.fly(main).setWidth(w);
14096 this.internalRender = true;
14097 // opera does not respect the auto grow header center column
14098 // then, after it gets a width opera refuses to recalculate
14099 // without a second pass
14100 if(Roo.isOpera && !this.secondPass){
14101 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14102 this.secondPass = true;
14103 this.update.defer(10, this, [date]);
14110 findCell : function(dt) {
14111 dt = dt.clearTime().getTime();
14113 this.cells.each(function(c){
14114 //Roo.log("check " +c.dateValue + '?=' + dt);
14115 if(c.dateValue == dt){
14125 findCells : function(ev) {
14126 var s = ev.start.clone().clearTime().getTime();
14128 var e= ev.end.clone().clearTime().getTime();
14131 this.cells.each(function(c){
14132 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14134 if(c.dateValue > e){
14137 if(c.dateValue < s){
14146 // findBestRow: function(cells)
14150 // for (var i =0 ; i < cells.length;i++) {
14151 // ret = Math.max(cells[i].rows || 0,ret);
14158 addItem : function(ev)
14160 // look for vertical location slot in
14161 var cells = this.findCells(ev);
14163 // ev.row = this.findBestRow(cells);
14165 // work out the location.
14169 for(var i =0; i < cells.length; i++) {
14171 cells[i].row = cells[0].row;
14174 cells[i].row = cells[i].row + 1;
14184 if (crow.start.getY() == cells[i].getY()) {
14186 crow.end = cells[i];
14203 cells[0].events.push(ev);
14205 this.calevents.push(ev);
14208 clearEvents: function() {
14210 if(!this.calevents){
14214 Roo.each(this.cells.elements, function(c){
14220 Roo.each(this.calevents, function(e) {
14221 Roo.each(e.els, function(el) {
14222 el.un('mouseenter' ,this.onEventEnter, this);
14223 el.un('mouseleave' ,this.onEventLeave, this);
14228 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14234 renderEvents: function()
14238 this.cells.each(function(c) {
14247 if(c.row != c.events.length){
14248 r = 4 - (4 - (c.row - c.events.length));
14251 c.events = ev.slice(0, r);
14252 c.more = ev.slice(r);
14254 if(c.more.length && c.more.length == 1){
14255 c.events.push(c.more.pop());
14258 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14262 this.cells.each(function(c) {
14264 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14267 for (var e = 0; e < c.events.length; e++){
14268 var ev = c.events[e];
14269 var rows = ev.rows;
14271 for(var i = 0; i < rows.length; i++) {
14273 // how many rows should it span..
14276 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14277 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14279 unselectable : "on",
14282 cls: 'fc-event-inner',
14286 // cls: 'fc-event-time',
14287 // html : cells.length > 1 ? '' : ev.time
14291 cls: 'fc-event-title',
14292 html : String.format('{0}', ev.title)
14299 cls: 'ui-resizable-handle ui-resizable-e',
14300 html : '  '
14307 cfg.cls += ' fc-event-start';
14309 if ((i+1) == rows.length) {
14310 cfg.cls += ' fc-event-end';
14313 var ctr = _this.el.select('.fc-event-container',true).first();
14314 var cg = ctr.createChild(cfg);
14316 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14317 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14319 var r = (c.more.length) ? 1 : 0;
14320 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14321 cg.setWidth(ebox.right - sbox.x -2);
14323 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14324 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14325 cg.on('click', _this.onEventClick, _this, ev);
14336 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14337 style : 'position: absolute',
14338 unselectable : "on",
14341 cls: 'fc-event-inner',
14345 cls: 'fc-event-title',
14353 cls: 'ui-resizable-handle ui-resizable-e',
14354 html : '  '
14360 var ctr = _this.el.select('.fc-event-container',true).first();
14361 var cg = ctr.createChild(cfg);
14363 var sbox = c.select('.fc-day-content',true).first().getBox();
14364 var ebox = c.select('.fc-day-content',true).first().getBox();
14366 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14367 cg.setWidth(ebox.right - sbox.x -2);
14369 cg.on('click', _this.onMoreEventClick, _this, c.more);
14379 onEventEnter: function (e, el,event,d) {
14380 this.fireEvent('evententer', this, el, event);
14383 onEventLeave: function (e, el,event,d) {
14384 this.fireEvent('eventleave', this, el, event);
14387 onEventClick: function (e, el,event,d) {
14388 this.fireEvent('eventclick', this, el, event);
14391 onMonthChange: function () {
14395 onMoreEventClick: function(e, el, more)
14399 this.calpopover.placement = 'right';
14400 this.calpopover.setTitle('More');
14402 this.calpopover.setContent('');
14404 var ctr = this.calpopover.el.select('.popover-content', true).first();
14406 Roo.each(more, function(m){
14408 cls : 'fc-event-hori fc-event-draggable',
14411 var cg = ctr.createChild(cfg);
14413 cg.on('click', _this.onEventClick, _this, m);
14416 this.calpopover.show(el);
14421 onLoad: function ()
14423 this.calevents = [];
14426 if(this.store.getCount() > 0){
14427 this.store.data.each(function(d){
14430 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14431 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14432 time : d.data.start_time,
14433 title : d.data.title,
14434 description : d.data.description,
14435 venue : d.data.venue
14440 this.renderEvents();
14442 if(this.calevents.length && this.loadMask){
14443 this.maskEl.hide();
14447 onBeforeLoad: function()
14449 this.clearEvents();
14451 this.maskEl.show();
14465 * @class Roo.bootstrap.Popover
14466 * @extends Roo.bootstrap.Component
14467 * Bootstrap Popover class
14468 * @cfg {String} html contents of the popover (or false to use children..)
14469 * @cfg {String} title of popover (or false to hide)
14470 * @cfg {String} placement how it is placed
14471 * @cfg {String} trigger click || hover (or false to trigger manually)
14472 * @cfg {String} over what (parent or false to trigger manually.)
14473 * @cfg {Number} delay - delay before showing
14476 * Create a new Popover
14477 * @param {Object} config The config object
14480 Roo.bootstrap.Popover = function(config){
14481 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14484 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14486 title: 'Fill in a title',
14489 placement : 'right',
14490 trigger : 'hover', // hover
14496 can_build_overlaid : false,
14498 getChildContainer : function()
14500 return this.el.select('.popover-content',true).first();
14503 getAutoCreate : function(){
14504 Roo.log('make popover?');
14506 cls : 'popover roo-dynamic',
14507 style: 'display:block',
14513 cls : 'popover-inner',
14517 cls: 'popover-title',
14521 cls : 'popover-content',
14532 setTitle: function(str)
14534 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14536 setContent: function(str)
14538 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14540 // as it get's added to the bottom of the page.
14541 onRender : function(ct, position)
14543 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14545 var cfg = Roo.apply({}, this.getAutoCreate());
14549 cfg.cls += ' ' + this.cls;
14552 cfg.style = this.style;
14554 Roo.log("adding to ")
14555 this.el = Roo.get(document.body).createChild(cfg, position);
14561 initEvents : function()
14563 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14564 this.el.enableDisplayMode('block');
14566 if (this.over === false) {
14569 if (this.triggers === false) {
14572 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14573 var triggers = this.trigger ? this.trigger.split(' ') : [];
14574 Roo.each(triggers, function(trigger) {
14576 if (trigger == 'click') {
14577 on_el.on('click', this.toggle, this);
14578 } else if (trigger != 'manual') {
14579 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14580 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14582 on_el.on(eventIn ,this.enter, this);
14583 on_el.on(eventOut, this.leave, this);
14594 toggle : function () {
14595 this.hoverState == 'in' ? this.leave() : this.enter();
14598 enter : function () {
14601 clearTimeout(this.timeout);
14603 this.hoverState = 'in';
14605 if (!this.delay || !this.delay.show) {
14610 this.timeout = setTimeout(function () {
14611 if (_t.hoverState == 'in') {
14614 }, this.delay.show)
14616 leave : function() {
14617 clearTimeout(this.timeout);
14619 this.hoverState = 'out';
14621 if (!this.delay || !this.delay.hide) {
14626 this.timeout = setTimeout(function () {
14627 if (_t.hoverState == 'out') {
14630 }, this.delay.hide)
14633 show : function (on_el)
14636 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14639 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14640 if (this.html !== false) {
14641 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14643 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14644 if (!this.title.length) {
14645 this.el.select('.popover-title',true).hide();
14648 var placement = typeof this.placement == 'function' ?
14649 this.placement.call(this, this.el, on_el) :
14652 var autoToken = /\s?auto?\s?/i;
14653 var autoPlace = autoToken.test(placement);
14655 placement = placement.replace(autoToken, '') || 'top';
14659 //this.el.setXY([0,0]);
14661 this.el.dom.style.display='block';
14662 this.el.addClass(placement);
14664 //this.el.appendTo(on_el);
14666 var p = this.getPosition();
14667 var box = this.el.getBox();
14672 var align = Roo.bootstrap.Popover.alignment[placement];
14673 this.el.alignTo(on_el, align[0],align[1]);
14674 //var arrow = this.el.select('.arrow',true).first();
14675 //arrow.set(align[2],
14677 this.el.addClass('in');
14678 this.hoverState = null;
14680 if (this.el.hasClass('fade')) {
14687 this.el.setXY([0,0]);
14688 this.el.removeClass('in');
14695 Roo.bootstrap.Popover.alignment = {
14696 'left' : ['r-l', [-10,0], 'right'],
14697 'right' : ['l-r', [10,0], 'left'],
14698 'bottom' : ['t-b', [0,10], 'top'],
14699 'top' : [ 'b-t', [0,-10], 'bottom']
14710 * @class Roo.bootstrap.Progress
14711 * @extends Roo.bootstrap.Component
14712 * Bootstrap Progress class
14713 * @cfg {Boolean} striped striped of the progress bar
14714 * @cfg {Boolean} active animated of the progress bar
14718 * Create a new Progress
14719 * @param {Object} config The config object
14722 Roo.bootstrap.Progress = function(config){
14723 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14726 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14731 getAutoCreate : function(){
14739 cfg.cls += ' progress-striped';
14743 cfg.cls += ' active';
14762 * @class Roo.bootstrap.ProgressBar
14763 * @extends Roo.bootstrap.Component
14764 * Bootstrap ProgressBar class
14765 * @cfg {Number} aria_valuenow aria-value now
14766 * @cfg {Number} aria_valuemin aria-value min
14767 * @cfg {Number} aria_valuemax aria-value max
14768 * @cfg {String} label label for the progress bar
14769 * @cfg {String} panel (success | info | warning | danger )
14770 * @cfg {String} role role of the progress bar
14771 * @cfg {String} sr_only text
14775 * Create a new ProgressBar
14776 * @param {Object} config The config object
14779 Roo.bootstrap.ProgressBar = function(config){
14780 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14783 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14787 aria_valuemax : 100,
14793 getAutoCreate : function()
14798 cls: 'progress-bar',
14799 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14811 cfg.role = this.role;
14814 if(this.aria_valuenow){
14815 cfg['aria-valuenow'] = this.aria_valuenow;
14818 if(this.aria_valuemin){
14819 cfg['aria-valuemin'] = this.aria_valuemin;
14822 if(this.aria_valuemax){
14823 cfg['aria-valuemax'] = this.aria_valuemax;
14826 if(this.label && !this.sr_only){
14827 cfg.html = this.label;
14831 cfg.cls += ' progress-bar-' + this.panel;
14837 update : function(aria_valuenow)
14839 this.aria_valuenow = aria_valuenow;
14841 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14856 * @class Roo.bootstrap.TabGroup
14857 * @extends Roo.bootstrap.Column
14858 * Bootstrap Column class
14859 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14860 * @cfg {Boolean} carousel true to make the group behave like a carousel
14861 * @cfg {Number} bullets show the panel pointer.. default 0
14862 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14863 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14864 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14867 * Create a new TabGroup
14868 * @param {Object} config The config object
14871 Roo.bootstrap.TabGroup = function(config){
14872 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14874 this.navId = Roo.id();
14877 Roo.bootstrap.TabGroup.register(this);
14881 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14884 transition : false,
14889 slideOnTouch : false,
14891 getAutoCreate : function()
14893 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14895 cfg.cls += ' tab-content';
14897 Roo.log('get auto create...............');
14899 if (this.carousel) {
14900 cfg.cls += ' carousel slide';
14903 cls : 'carousel-inner'
14906 if(this.bullets > 0 && !Roo.isTouch){
14909 cls : 'carousel-bullets',
14913 if(this.bullets_cls){
14914 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14917 for (var i = 0; i < this.bullets; i++){
14919 cls : 'bullet bullet-' + i
14927 cfg.cn[0].cn = bullets;
14934 initEvents: function()
14936 Roo.log('-------- init events on tab group ---------');
14938 if(this.bullets > 0 && !Roo.isTouch){
14944 if(Roo.isTouch && this.slideOnTouch){
14945 this.el.on("touchstart", this.onTouchStart, this);
14948 if(this.autoslide){
14951 this.slideFn = window.setInterval(function() {
14952 _this.showPanelNext();
14958 onTouchStart : function(e, el, o)
14960 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14964 this.showPanelNext();
14967 getChildContainer : function()
14969 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14973 * register a Navigation item
14974 * @param {Roo.bootstrap.NavItem} the navitem to add
14976 register : function(item)
14978 this.tabs.push( item);
14979 item.navId = this.navId; // not really needed..
14983 getActivePanel : function()
14986 Roo.each(this.tabs, function(t) {
14996 getPanelByName : function(n)
14999 Roo.each(this.tabs, function(t) {
15000 if (t.tabId == n) {
15008 indexOfPanel : function(p)
15011 Roo.each(this.tabs, function(t,i) {
15012 if (t.tabId == p.tabId) {
15021 * show a specific panel
15022 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15023 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15025 showPanel : function (pan)
15027 if(this.transition){
15028 Roo.log("waiting for the transitionend");
15032 if (typeof(pan) == 'number') {
15033 pan = this.tabs[pan];
15035 if (typeof(pan) == 'string') {
15036 pan = this.getPanelByName(pan);
15038 if (pan.tabId == this.getActivePanel().tabId) {
15041 var cur = this.getActivePanel();
15043 if (false === cur.fireEvent('beforedeactivate')) {
15047 if(this.bullets > 0 && !Roo.isTouch){
15048 this.setActiveBullet(this.indexOfPanel(pan));
15051 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15053 this.transition = true;
15054 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15055 var lr = dir == 'next' ? 'left' : 'right';
15056 pan.el.addClass(dir); // or prev
15057 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15058 cur.el.addClass(lr); // or right
15059 pan.el.addClass(lr);
15062 cur.el.on('transitionend', function() {
15063 Roo.log("trans end?");
15065 pan.el.removeClass([lr,dir]);
15066 pan.setActive(true);
15068 cur.el.removeClass([lr]);
15069 cur.setActive(false);
15071 _this.transition = false;
15073 }, this, { single: true } );
15078 cur.setActive(false);
15079 pan.setActive(true);
15084 showPanelNext : function()
15086 var i = this.indexOfPanel(this.getActivePanel());
15088 if (i >= this.tabs.length - 1 && !this.autoslide) {
15092 if (i >= this.tabs.length - 1 && this.autoslide) {
15096 this.showPanel(this.tabs[i+1]);
15099 showPanelPrev : function()
15101 var i = this.indexOfPanel(this.getActivePanel());
15103 if (i < 1 && !this.autoslide) {
15107 if (i < 1 && this.autoslide) {
15108 i = this.tabs.length;
15111 this.showPanel(this.tabs[i-1]);
15114 initBullet : function()
15122 for (var i = 0; i < this.bullets; i++){
15123 var bullet = this.el.select('.bullet-' + i, true).first();
15129 bullet.on('click', (function(e, el, o, ii, t){
15131 e.preventDefault();
15133 _this.showPanel(ii);
15135 if(_this.autoslide && _this.slideFn){
15136 clearInterval(_this.slideFn);
15137 _this.slideFn = window.setInterval(function() {
15138 _this.showPanelNext();
15142 }).createDelegate(this, [i, bullet], true));
15146 setActiveBullet : function(i)
15152 Roo.each(this.el.select('.bullet', true).elements, function(el){
15153 el.removeClass('selected');
15156 var bullet = this.el.select('.bullet-' + i, true).first();
15162 bullet.addClass('selected');
15173 Roo.apply(Roo.bootstrap.TabGroup, {
15177 * register a Navigation Group
15178 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15180 register : function(navgrp)
15182 this.groups[navgrp.navId] = navgrp;
15186 * fetch a Navigation Group based on the navigation ID
15187 * if one does not exist , it will get created.
15188 * @param {string} the navgroup to add
15189 * @returns {Roo.bootstrap.NavGroup} the navgroup
15191 get: function(navId) {
15192 if (typeof(this.groups[navId]) == 'undefined') {
15193 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15195 return this.groups[navId] ;
15210 * @class Roo.bootstrap.TabPanel
15211 * @extends Roo.bootstrap.Component
15212 * Bootstrap TabPanel class
15213 * @cfg {Boolean} active panel active
15214 * @cfg {String} html panel content
15215 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15216 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15220 * Create a new TabPanel
15221 * @param {Object} config The config object
15224 Roo.bootstrap.TabPanel = function(config){
15225 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15229 * Fires when the active status changes
15230 * @param {Roo.bootstrap.TabPanel} this
15231 * @param {Boolean} state the new state
15236 * @event beforedeactivate
15237 * Fires before a tab is de-activated - can be used to do validation on a form.
15238 * @param {Roo.bootstrap.TabPanel} this
15239 * @return {Boolean} false if there is an error
15242 'beforedeactivate': true
15245 this.tabId = this.tabId || Roo.id();
15249 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15256 getAutoCreate : function(){
15259 // item is needed for carousel - not sure if it has any effect otherwise
15260 cls: 'tab-pane item',
15261 html: this.html || ''
15265 cfg.cls += ' active';
15269 cfg.tabId = this.tabId;
15276 initEvents: function()
15278 Roo.log('-------- init events on tab panel ---------');
15280 var p = this.parent();
15281 this.navId = this.navId || p.navId;
15283 if (typeof(this.navId) != 'undefined') {
15284 // not really needed.. but just in case.. parent should be a NavGroup.
15285 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15286 Roo.log(['register', tg, this]);
15289 var i = tg.tabs.length - 1;
15291 if(this.active && tg.bullets > 0 && i < tg.bullets){
15292 tg.setActiveBullet(i);
15299 onRender : function(ct, position)
15301 // Roo.log("Call onRender: " + this.xtype);
15303 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15311 setActive: function(state)
15313 Roo.log("panel - set active " + this.tabId + "=" + state);
15315 this.active = state;
15317 this.el.removeClass('active');
15319 } else if (!this.el.hasClass('active')) {
15320 this.el.addClass('active');
15323 this.fireEvent('changed', this, state);
15340 * @class Roo.bootstrap.DateField
15341 * @extends Roo.bootstrap.Input
15342 * Bootstrap DateField class
15343 * @cfg {Number} weekStart default 0
15344 * @cfg {String} viewMode default empty, (months|years)
15345 * @cfg {String} minViewMode default empty, (months|years)
15346 * @cfg {Number} startDate default -Infinity
15347 * @cfg {Number} endDate default Infinity
15348 * @cfg {Boolean} todayHighlight default false
15349 * @cfg {Boolean} todayBtn default false
15350 * @cfg {Boolean} calendarWeeks default false
15351 * @cfg {Object} daysOfWeekDisabled default empty
15352 * @cfg {Boolean} singleMode default false (true | false)
15354 * @cfg {Boolean} keyboardNavigation default true
15355 * @cfg {String} language default en
15358 * Create a new DateField
15359 * @param {Object} config The config object
15362 Roo.bootstrap.DateField = function(config){
15363 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15367 * Fires when this field show.
15368 * @param {Roo.bootstrap.DateField} this
15369 * @param {Mixed} date The date value
15374 * Fires when this field hide.
15375 * @param {Roo.bootstrap.DateField} this
15376 * @param {Mixed} date The date value
15381 * Fires when select a date.
15382 * @param {Roo.bootstrap.DateField} this
15383 * @param {Mixed} date The date value
15389 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15392 * @cfg {String} format
15393 * The default date format string which can be overriden for localization support. The format must be
15394 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15398 * @cfg {String} altFormats
15399 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15400 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15402 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15410 todayHighlight : false,
15416 keyboardNavigation: true,
15418 calendarWeeks: false,
15420 startDate: -Infinity,
15424 daysOfWeekDisabled: [],
15428 singleMode : false,
15430 UTCDate: function()
15432 return new Date(Date.UTC.apply(Date, arguments));
15435 UTCToday: function()
15437 var today = new Date();
15438 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15441 getDate: function() {
15442 var d = this.getUTCDate();
15443 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15446 getUTCDate: function() {
15450 setDate: function(d) {
15451 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15454 setUTCDate: function(d) {
15456 this.setValue(this.formatDate(this.date));
15459 onRender: function(ct, position)
15462 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15464 this.language = this.language || 'en';
15465 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15466 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15468 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15469 this.format = this.format || 'm/d/y';
15470 this.isInline = false;
15471 this.isInput = true;
15472 this.component = this.el.select('.add-on', true).first() || false;
15473 this.component = (this.component && this.component.length === 0) ? false : this.component;
15474 this.hasInput = this.component && this.inputEL().length;
15476 if (typeof(this.minViewMode === 'string')) {
15477 switch (this.minViewMode) {
15479 this.minViewMode = 1;
15482 this.minViewMode = 2;
15485 this.minViewMode = 0;
15490 if (typeof(this.viewMode === 'string')) {
15491 switch (this.viewMode) {
15504 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15506 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15508 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15510 this.picker().on('mousedown', this.onMousedown, this);
15511 this.picker().on('click', this.onClick, this);
15513 this.picker().addClass('datepicker-dropdown');
15515 this.startViewMode = this.viewMode;
15517 if(this.singleMode){
15518 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15519 v.setVisibilityMode(Roo.Element.DISPLAY)
15523 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15524 v.setStyle('width', '189px');
15528 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15529 if(!this.calendarWeeks){
15534 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15535 v.attr('colspan', function(i, val){
15536 return parseInt(val) + 1;
15541 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15543 this.setStartDate(this.startDate);
15544 this.setEndDate(this.endDate);
15546 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15553 if(this.isInline) {
15558 picker : function()
15560 return this.pickerEl;
15561 // return this.el.select('.datepicker', true).first();
15564 fillDow: function()
15566 var dowCnt = this.weekStart;
15575 if(this.calendarWeeks){
15583 while (dowCnt < this.weekStart + 7) {
15587 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15591 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15594 fillMonths: function()
15597 var months = this.picker().select('>.datepicker-months td', true).first();
15599 months.dom.innerHTML = '';
15605 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15608 months.createChild(month);
15615 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;
15617 if (this.date < this.startDate) {
15618 this.viewDate = new Date(this.startDate);
15619 } else if (this.date > this.endDate) {
15620 this.viewDate = new Date(this.endDate);
15622 this.viewDate = new Date(this.date);
15630 var d = new Date(this.viewDate),
15631 year = d.getUTCFullYear(),
15632 month = d.getUTCMonth(),
15633 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15634 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15635 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15636 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15637 currentDate = this.date && this.date.valueOf(),
15638 today = this.UTCToday();
15640 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15642 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15644 // this.picker.select('>tfoot th.today').
15645 // .text(dates[this.language].today)
15646 // .toggle(this.todayBtn !== false);
15648 this.updateNavArrows();
15651 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15653 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15655 prevMonth.setUTCDate(day);
15657 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15659 var nextMonth = new Date(prevMonth);
15661 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15663 nextMonth = nextMonth.valueOf();
15665 var fillMonths = false;
15667 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15669 while(prevMonth.valueOf() < nextMonth) {
15672 if (prevMonth.getUTCDay() === this.weekStart) {
15674 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15682 if(this.calendarWeeks){
15683 // ISO 8601: First week contains first thursday.
15684 // ISO also states week starts on Monday, but we can be more abstract here.
15686 // Start of current week: based on weekstart/current date
15687 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15688 // Thursday of this week
15689 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15690 // First Thursday of year, year from thursday
15691 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15692 // Calendar week: ms between thursdays, div ms per day, div 7 days
15693 calWeek = (th - yth) / 864e5 / 7 + 1;
15695 fillMonths.cn.push({
15703 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15705 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15708 if (this.todayHighlight &&
15709 prevMonth.getUTCFullYear() == today.getFullYear() &&
15710 prevMonth.getUTCMonth() == today.getMonth() &&
15711 prevMonth.getUTCDate() == today.getDate()) {
15712 clsName += ' today';
15715 if (currentDate && prevMonth.valueOf() === currentDate) {
15716 clsName += ' active';
15719 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15720 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15721 clsName += ' disabled';
15724 fillMonths.cn.push({
15726 cls: 'day ' + clsName,
15727 html: prevMonth.getDate()
15730 prevMonth.setDate(prevMonth.getDate()+1);
15733 var currentYear = this.date && this.date.getUTCFullYear();
15734 var currentMonth = this.date && this.date.getUTCMonth();
15736 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15738 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15739 v.removeClass('active');
15741 if(currentYear === year && k === currentMonth){
15742 v.addClass('active');
15745 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15746 v.addClass('disabled');
15752 year = parseInt(year/10, 10) * 10;
15754 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15756 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15759 for (var i = -1; i < 11; i++) {
15760 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15762 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15770 showMode: function(dir)
15773 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15776 Roo.each(this.picker().select('>div',true).elements, function(v){
15777 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15780 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15785 if(this.isInline) return;
15787 this.picker().removeClass(['bottom', 'top']);
15789 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15791 * place to the top of element!
15795 this.picker().addClass('top');
15796 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15801 this.picker().addClass('bottom');
15803 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15806 parseDate : function(value)
15808 if(!value || value instanceof Date){
15811 var v = Date.parseDate(value, this.format);
15812 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15813 v = Date.parseDate(value, 'Y-m-d');
15815 if(!v && this.altFormats){
15816 if(!this.altFormatsArray){
15817 this.altFormatsArray = this.altFormats.split("|");
15819 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15820 v = Date.parseDate(value, this.altFormatsArray[i]);
15826 formatDate : function(date, fmt)
15828 return (!date || !(date instanceof Date)) ?
15829 date : date.dateFormat(fmt || this.format);
15832 onFocus : function()
15834 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15838 onBlur : function()
15840 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15842 var d = this.inputEl().getValue();
15851 this.picker().show();
15855 this.fireEvent('show', this, this.date);
15860 if(this.isInline) return;
15861 this.picker().hide();
15862 this.viewMode = this.startViewMode;
15865 this.fireEvent('hide', this, this.date);
15869 onMousedown: function(e)
15871 e.stopPropagation();
15872 e.preventDefault();
15877 Roo.bootstrap.DateField.superclass.keyup.call(this);
15881 setValue: function(v)
15884 // v can be a string or a date..
15887 var d = new Date(this.parseDate(v) ).clearTime();
15889 if(isNaN(d.getTime())){
15890 this.date = this.viewDate = '';
15891 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15895 v = this.formatDate(d);
15897 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15899 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15903 this.fireEvent('select', this, this.date);
15907 getValue: function()
15909 return this.formatDate(this.date);
15912 fireKey: function(e)
15914 if (!this.picker().isVisible()){
15915 if (e.keyCode == 27) // allow escape to hide and re-show picker
15920 var dateChanged = false,
15922 newDate, newViewDate;
15927 e.preventDefault();
15931 if (!this.keyboardNavigation) break;
15932 dir = e.keyCode == 37 ? -1 : 1;
15935 newDate = this.moveYear(this.date, dir);
15936 newViewDate = this.moveYear(this.viewDate, dir);
15937 } else if (e.shiftKey){
15938 newDate = this.moveMonth(this.date, dir);
15939 newViewDate = this.moveMonth(this.viewDate, dir);
15941 newDate = new Date(this.date);
15942 newDate.setUTCDate(this.date.getUTCDate() + dir);
15943 newViewDate = new Date(this.viewDate);
15944 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15946 if (this.dateWithinRange(newDate)){
15947 this.date = newDate;
15948 this.viewDate = newViewDate;
15949 this.setValue(this.formatDate(this.date));
15951 e.preventDefault();
15952 dateChanged = true;
15957 if (!this.keyboardNavigation) break;
15958 dir = e.keyCode == 38 ? -1 : 1;
15960 newDate = this.moveYear(this.date, dir);
15961 newViewDate = this.moveYear(this.viewDate, dir);
15962 } else if (e.shiftKey){
15963 newDate = this.moveMonth(this.date, dir);
15964 newViewDate = this.moveMonth(this.viewDate, dir);
15966 newDate = new Date(this.date);
15967 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15968 newViewDate = new Date(this.viewDate);
15969 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15971 if (this.dateWithinRange(newDate)){
15972 this.date = newDate;
15973 this.viewDate = newViewDate;
15974 this.setValue(this.formatDate(this.date));
15976 e.preventDefault();
15977 dateChanged = true;
15981 this.setValue(this.formatDate(this.date));
15983 e.preventDefault();
15986 this.setValue(this.formatDate(this.date));
16000 onClick: function(e)
16002 e.stopPropagation();
16003 e.preventDefault();
16005 var target = e.getTarget();
16007 if(target.nodeName.toLowerCase() === 'i'){
16008 target = Roo.get(target).dom.parentNode;
16011 var nodeName = target.nodeName;
16012 var className = target.className;
16013 var html = target.innerHTML;
16014 //Roo.log(nodeName);
16016 switch(nodeName.toLowerCase()) {
16018 switch(className) {
16024 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16025 switch(this.viewMode){
16027 this.viewDate = this.moveMonth(this.viewDate, dir);
16031 this.viewDate = this.moveYear(this.viewDate, dir);
16037 var date = new Date();
16038 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16040 this.setValue(this.formatDate(this.date));
16047 if (className.indexOf('disabled') < 0) {
16048 this.viewDate.setUTCDate(1);
16049 if (className.indexOf('month') > -1) {
16050 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16052 var year = parseInt(html, 10) || 0;
16053 this.viewDate.setUTCFullYear(year);
16057 if(this.singleMode){
16058 this.setValue(this.formatDate(this.viewDate));
16069 //Roo.log(className);
16070 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16071 var day = parseInt(html, 10) || 1;
16072 var year = this.viewDate.getUTCFullYear(),
16073 month = this.viewDate.getUTCMonth();
16075 if (className.indexOf('old') > -1) {
16082 } else if (className.indexOf('new') > -1) {
16090 //Roo.log([year,month,day]);
16091 this.date = this.UTCDate(year, month, day,0,0,0,0);
16092 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16094 //Roo.log(this.formatDate(this.date));
16095 this.setValue(this.formatDate(this.date));
16102 setStartDate: function(startDate)
16104 this.startDate = startDate || -Infinity;
16105 if (this.startDate !== -Infinity) {
16106 this.startDate = this.parseDate(this.startDate);
16109 this.updateNavArrows();
16112 setEndDate: function(endDate)
16114 this.endDate = endDate || Infinity;
16115 if (this.endDate !== Infinity) {
16116 this.endDate = this.parseDate(this.endDate);
16119 this.updateNavArrows();
16122 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16124 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16125 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16126 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16128 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16129 return parseInt(d, 10);
16132 this.updateNavArrows();
16135 updateNavArrows: function()
16137 if(this.singleMode){
16141 var d = new Date(this.viewDate),
16142 year = d.getUTCFullYear(),
16143 month = d.getUTCMonth();
16145 Roo.each(this.picker().select('.prev', true).elements, function(v){
16147 switch (this.viewMode) {
16150 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16156 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16163 Roo.each(this.picker().select('.next', true).elements, function(v){
16165 switch (this.viewMode) {
16168 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16174 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16182 moveMonth: function(date, dir)
16184 if (!dir) return date;
16185 var new_date = new Date(date.valueOf()),
16186 day = new_date.getUTCDate(),
16187 month = new_date.getUTCMonth(),
16188 mag = Math.abs(dir),
16190 dir = dir > 0 ? 1 : -1;
16193 // If going back one month, make sure month is not current month
16194 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16196 return new_date.getUTCMonth() == month;
16198 // If going forward one month, make sure month is as expected
16199 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16201 return new_date.getUTCMonth() != new_month;
16203 new_month = month + dir;
16204 new_date.setUTCMonth(new_month);
16205 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16206 if (new_month < 0 || new_month > 11)
16207 new_month = (new_month + 12) % 12;
16209 // For magnitudes >1, move one month at a time...
16210 for (var i=0; i<mag; i++)
16211 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16212 new_date = this.moveMonth(new_date, dir);
16213 // ...then reset the day, keeping it in the new month
16214 new_month = new_date.getUTCMonth();
16215 new_date.setUTCDate(day);
16217 return new_month != new_date.getUTCMonth();
16220 // Common date-resetting loop -- if date is beyond end of month, make it
16223 new_date.setUTCDate(--day);
16224 new_date.setUTCMonth(new_month);
16229 moveYear: function(date, dir)
16231 return this.moveMonth(date, dir*12);
16234 dateWithinRange: function(date)
16236 return date >= this.startDate && date <= this.endDate;
16242 this.picker().remove();
16247 Roo.apply(Roo.bootstrap.DateField, {
16258 html: '<i class="fa fa-arrow-left"/>'
16268 html: '<i class="fa fa-arrow-right"/>'
16310 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16311 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16312 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16313 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16314 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16327 navFnc: 'FullYear',
16332 navFnc: 'FullYear',
16337 Roo.apply(Roo.bootstrap.DateField, {
16341 cls: 'datepicker dropdown-menu roo-dynamic',
16345 cls: 'datepicker-days',
16349 cls: 'table-condensed',
16351 Roo.bootstrap.DateField.head,
16355 Roo.bootstrap.DateField.footer
16362 cls: 'datepicker-months',
16366 cls: 'table-condensed',
16368 Roo.bootstrap.DateField.head,
16369 Roo.bootstrap.DateField.content,
16370 Roo.bootstrap.DateField.footer
16377 cls: 'datepicker-years',
16381 cls: 'table-condensed',
16383 Roo.bootstrap.DateField.head,
16384 Roo.bootstrap.DateField.content,
16385 Roo.bootstrap.DateField.footer
16404 * @class Roo.bootstrap.TimeField
16405 * @extends Roo.bootstrap.Input
16406 * Bootstrap DateField class
16410 * Create a new TimeField
16411 * @param {Object} config The config object
16414 Roo.bootstrap.TimeField = function(config){
16415 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16419 * Fires when this field show.
16420 * @param {Roo.bootstrap.DateField} thisthis
16421 * @param {Mixed} date The date value
16426 * Fires when this field hide.
16427 * @param {Roo.bootstrap.DateField} this
16428 * @param {Mixed} date The date value
16433 * Fires when select a date.
16434 * @param {Roo.bootstrap.DateField} this
16435 * @param {Mixed} date The date value
16441 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16444 * @cfg {String} format
16445 * The default time format string which can be overriden for localization support. The format must be
16446 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16450 onRender: function(ct, position)
16453 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16455 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16457 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16459 this.pop = this.picker().select('>.datepicker-time',true).first();
16460 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16462 this.picker().on('mousedown', this.onMousedown, this);
16463 this.picker().on('click', this.onClick, this);
16465 this.picker().addClass('datepicker-dropdown');
16470 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16471 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16472 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16473 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16474 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16475 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16479 fireKey: function(e){
16480 if (!this.picker().isVisible()){
16481 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16487 e.preventDefault();
16495 this.onTogglePeriod();
16498 this.onIncrementMinutes();
16501 this.onDecrementMinutes();
16510 onClick: function(e) {
16511 e.stopPropagation();
16512 e.preventDefault();
16515 picker : function()
16517 return this.el.select('.datepicker', true).first();
16520 fillTime: function()
16522 var time = this.pop.select('tbody', true).first();
16524 time.dom.innerHTML = '';
16539 cls: 'hours-up glyphicon glyphicon-chevron-up'
16559 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16580 cls: 'timepicker-hour',
16595 cls: 'timepicker-minute',
16610 cls: 'btn btn-primary period',
16632 cls: 'hours-down glyphicon glyphicon-chevron-down'
16652 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16670 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16677 var hours = this.time.getHours();
16678 var minutes = this.time.getMinutes();
16691 hours = hours - 12;
16695 hours = '0' + hours;
16699 minutes = '0' + minutes;
16702 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16703 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16704 this.pop.select('button', true).first().dom.innerHTML = period;
16710 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16712 var cls = ['bottom'];
16714 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16721 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16726 this.picker().addClass(cls.join('-'));
16730 Roo.each(cls, function(c){
16732 _this.picker().setTop(_this.inputEl().getHeight());
16736 _this.picker().setTop(0 - _this.picker().getHeight());
16741 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16745 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16752 onFocus : function()
16754 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16758 onBlur : function()
16760 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16766 this.picker().show();
16771 this.fireEvent('show', this, this.date);
16776 this.picker().hide();
16779 this.fireEvent('hide', this, this.date);
16782 setTime : function()
16785 this.setValue(this.time.format(this.format));
16787 this.fireEvent('select', this, this.date);
16792 onMousedown: function(e){
16793 e.stopPropagation();
16794 e.preventDefault();
16797 onIncrementHours: function()
16799 Roo.log('onIncrementHours');
16800 this.time = this.time.add(Date.HOUR, 1);
16805 onDecrementHours: function()
16807 Roo.log('onDecrementHours');
16808 this.time = this.time.add(Date.HOUR, -1);
16812 onIncrementMinutes: function()
16814 Roo.log('onIncrementMinutes');
16815 this.time = this.time.add(Date.MINUTE, 1);
16819 onDecrementMinutes: function()
16821 Roo.log('onDecrementMinutes');
16822 this.time = this.time.add(Date.MINUTE, -1);
16826 onTogglePeriod: function()
16828 Roo.log('onTogglePeriod');
16829 this.time = this.time.add(Date.HOUR, 12);
16836 Roo.apply(Roo.bootstrap.TimeField, {
16866 cls: 'btn btn-info ok',
16878 Roo.apply(Roo.bootstrap.TimeField, {
16882 cls: 'datepicker dropdown-menu',
16886 cls: 'datepicker-time',
16890 cls: 'table-condensed',
16892 Roo.bootstrap.TimeField.content,
16893 Roo.bootstrap.TimeField.footer
16912 * @class Roo.bootstrap.MonthField
16913 * @extends Roo.bootstrap.Input
16914 * Bootstrap MonthField class
16916 * @cfg {String} language default en
16919 * Create a new MonthField
16920 * @param {Object} config The config object
16923 Roo.bootstrap.MonthField = function(config){
16924 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16929 * Fires when this field show.
16930 * @param {Roo.bootstrap.MonthField} this
16931 * @param {Mixed} date The date value
16936 * Fires when this field hide.
16937 * @param {Roo.bootstrap.MonthField} this
16938 * @param {Mixed} date The date value
16943 * Fires when select a date.
16944 * @param {Roo.bootstrap.MonthField} this
16945 * @param {String} oldvalue The old value
16946 * @param {String} newvalue The new value
16952 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16954 onRender: function(ct, position)
16957 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16959 this.language = this.language || 'en';
16960 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16961 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16963 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16964 this.isInline = false;
16965 this.isInput = true;
16966 this.component = this.el.select('.add-on', true).first() || false;
16967 this.component = (this.component && this.component.length === 0) ? false : this.component;
16968 this.hasInput = this.component && this.inputEL().length;
16970 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16972 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16974 this.picker().on('mousedown', this.onMousedown, this);
16975 this.picker().on('click', this.onClick, this);
16977 this.picker().addClass('datepicker-dropdown');
16979 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16980 v.setStyle('width', '189px');
16987 if(this.isInline) {
16993 setValue: function(v, suppressEvent)
16995 var o = this.getValue();
16997 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17001 if(suppressEvent !== true){
17002 this.fireEvent('select', this, o, v);
17007 getValue: function()
17012 onClick: function(e)
17014 e.stopPropagation();
17015 e.preventDefault();
17017 var target = e.getTarget();
17019 if(target.nodeName.toLowerCase() === 'i'){
17020 target = Roo.get(target).dom.parentNode;
17023 var nodeName = target.nodeName;
17024 var className = target.className;
17025 var html = target.innerHTML;
17027 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17031 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17033 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17039 picker : function()
17041 return this.pickerEl;
17044 fillMonths: function()
17047 var months = this.picker().select('>.datepicker-months td', true).first();
17049 months.dom.innerHTML = '';
17055 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17058 months.createChild(month);
17067 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17068 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17071 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17072 e.removeClass('active');
17074 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17075 e.addClass('active');
17082 if(this.isInline) return;
17084 this.picker().removeClass(['bottom', 'top']);
17086 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17088 * place to the top of element!
17092 this.picker().addClass('top');
17093 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17098 this.picker().addClass('bottom');
17100 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17103 onFocus : function()
17105 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17109 onBlur : function()
17111 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17113 var d = this.inputEl().getValue();
17122 this.picker().show();
17123 this.picker().select('>.datepicker-months', true).first().show();
17127 this.fireEvent('show', this, this.date);
17132 if(this.isInline) return;
17133 this.picker().hide();
17134 this.fireEvent('hide', this, this.date);
17138 onMousedown: function(e)
17140 e.stopPropagation();
17141 e.preventDefault();
17146 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17150 fireKey: function(e)
17152 if (!this.picker().isVisible()){
17153 if (e.keyCode == 27) // allow escape to hide and re-show picker
17163 e.preventDefault();
17167 dir = e.keyCode == 37 ? -1 : 1;
17169 this.vIndex = this.vIndex + dir;
17171 if(this.vIndex < 0){
17175 if(this.vIndex > 11){
17179 if(isNaN(this.vIndex)){
17183 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17189 dir = e.keyCode == 38 ? -1 : 1;
17191 this.vIndex = this.vIndex + dir * 4;
17193 if(this.vIndex < 0){
17197 if(this.vIndex > 11){
17201 if(isNaN(this.vIndex)){
17205 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17210 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17211 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17215 e.preventDefault();
17218 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17219 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17235 this.picker().remove();
17240 Roo.apply(Roo.bootstrap.MonthField, {
17259 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17260 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17265 Roo.apply(Roo.bootstrap.MonthField, {
17269 cls: 'datepicker dropdown-menu roo-dynamic',
17273 cls: 'datepicker-months',
17277 cls: 'table-condensed',
17279 Roo.bootstrap.DateField.content
17299 * @class Roo.bootstrap.CheckBox
17300 * @extends Roo.bootstrap.Input
17301 * Bootstrap CheckBox class
17303 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17304 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17305 * @cfg {String} boxLabel The text that appears beside the checkbox
17306 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17307 * @cfg {Boolean} checked initnal the element
17308 * @cfg {Boolean} inline inline the element (default false)
17309 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17312 * Create a new CheckBox
17313 * @param {Object} config The config object
17316 Roo.bootstrap.CheckBox = function(config){
17317 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17322 * Fires when the element is checked or unchecked.
17323 * @param {Roo.bootstrap.CheckBox} this This input
17324 * @param {Boolean} checked The new checked value
17331 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17333 inputType: 'checkbox',
17341 getAutoCreate : function()
17343 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17349 cfg.cls = 'form-group ' + this.inputType; //input-group
17352 cfg.cls += ' ' + this.inputType + '-inline';
17358 type : this.inputType,
17359 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17360 cls : 'roo-' + this.inputType, //'form-box',
17361 placeholder : this.placeholder || ''
17365 if (this.weight) { // Validity check?
17366 cfg.cls += " " + this.inputType + "-" + this.weight;
17369 if (this.disabled) {
17370 input.disabled=true;
17374 input.checked = this.checked;
17378 input.name = this.name;
17382 input.cls += ' input-' + this.size;
17387 ['xs','sm','md','lg'].map(function(size){
17388 if (settings[size]) {
17389 cfg.cls += ' col-' + size + '-' + settings[size];
17393 var inputblock = input;
17395 if (this.before || this.after) {
17398 cls : 'input-group',
17403 inputblock.cn.push({
17405 cls : 'input-group-addon',
17410 inputblock.cn.push(input);
17413 inputblock.cn.push({
17415 cls : 'input-group-addon',
17422 if (align ==='left' && this.fieldLabel.length) {
17423 Roo.log("left and has label");
17429 cls : 'control-label col-md-' + this.labelWidth,
17430 html : this.fieldLabel
17434 cls : "col-md-" + (12 - this.labelWidth),
17441 } else if ( this.fieldLabel.length) {
17446 tag: this.boxLabel ? 'span' : 'label',
17448 cls: 'control-label box-input-label',
17449 //cls : 'input-group-addon',
17450 html : this.fieldLabel
17460 Roo.log(" no label && no align");
17461 cfg.cn = [ inputblock ] ;
17466 var boxLabelCfg = {
17468 //'for': id, // box label is handled by onclick - so no for...
17470 html: this.boxLabel
17474 boxLabelCfg.tooltip = this.tooltip;
17477 cfg.cn.push(boxLabelCfg);
17487 * return the real input element.
17489 inputEl: function ()
17491 return this.el.select('input.roo-' + this.inputType,true).first();
17494 labelEl: function()
17496 return this.el.select('label.control-label',true).first();
17498 /* depricated... */
17502 return this.labelEl();
17505 initEvents : function()
17507 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17509 this.inputEl().on('click', this.onClick, this);
17511 if (this.boxLabel) {
17512 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17515 this.startValue = this.getValue();
17518 Roo.bootstrap.CheckBox.register(this);
17522 onClick : function()
17524 this.setChecked(!this.checked);
17527 setChecked : function(state,suppressEvent)
17529 this.startValue = this.getValue();
17531 if(this.inputType == 'radio'){
17533 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17534 e.dom.checked = false;
17537 this.inputEl().dom.checked = true;
17539 this.inputEl().dom.value = this.inputValue;
17541 if(suppressEvent !== true){
17542 this.fireEvent('check', this, true);
17550 this.checked = state;
17552 this.inputEl().dom.checked = state;
17554 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17556 if(suppressEvent !== true){
17557 this.fireEvent('check', this, state);
17563 getValue : function()
17565 if(this.inputType == 'radio'){
17566 return this.getGroupValue();
17569 return this.inputEl().getValue();
17573 getGroupValue : function()
17575 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17579 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17582 setValue : function(v,suppressEvent)
17584 if(this.inputType == 'radio'){
17585 this.setGroupValue(v, suppressEvent);
17589 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17594 setGroupValue : function(v, suppressEvent)
17596 this.startValue = this.getValue();
17598 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17599 e.dom.checked = false;
17601 if(e.dom.value == v){
17602 e.dom.checked = true;
17606 if(suppressEvent !== true){
17607 this.fireEvent('check', this, true);
17615 validate : function()
17619 (this.inputType == 'radio' && this.validateRadio()) ||
17620 (this.inputType == 'checkbox' && this.validateCheckbox())
17626 this.markInvalid();
17630 validateRadio : function()
17634 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17635 if(!e.dom.checked){
17647 validateCheckbox : function()
17650 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17653 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17661 for(var i in group){
17666 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17673 * Mark this field as valid
17675 markValid : function()
17677 if(this.allowBlank){
17683 this.fireEvent('valid', this);
17685 if(this.inputType == 'radio'){
17686 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17687 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17688 e.findParent('.form-group', false, true).addClass(_this.validClass);
17695 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17696 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17700 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17706 for(var i in group){
17707 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17708 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17713 * Mark this field as invalid
17714 * @param {String} msg The validation message
17716 markInvalid : function(msg)
17718 if(this.allowBlank){
17724 this.fireEvent('invalid', this, msg);
17726 if(this.inputType == 'radio'){
17727 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17728 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17729 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17736 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17737 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17741 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17747 for(var i in group){
17748 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17749 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17756 Roo.apply(Roo.bootstrap.CheckBox, {
17761 * register a CheckBox Group
17762 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17764 register : function(checkbox)
17766 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17767 this.groups[checkbox.groupId] = {};
17770 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17774 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17778 * fetch a CheckBox Group based on the group ID
17779 * @param {string} the group ID
17780 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17782 get: function(groupId) {
17783 if (typeof(this.groups[groupId]) == 'undefined') {
17787 return this.groups[groupId] ;
17799 *<div class="radio">
17801 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17802 Option one is this and that—be sure to include why it's great
17809 *<label class="radio-inline">fieldLabel</label>
17810 *<label class="radio-inline">
17811 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17819 * @class Roo.bootstrap.Radio
17820 * @extends Roo.bootstrap.CheckBox
17821 * Bootstrap Radio class
17824 * Create a new Radio
17825 * @param {Object} config The config object
17828 Roo.bootstrap.Radio = function(config){
17829 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17833 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17835 inputType: 'radio',
17839 getAutoCreate : function()
17841 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17842 align = align || 'left'; // default...
17849 tag : this.inline ? 'span' : 'div',
17854 var inline = this.inline ? ' radio-inline' : '';
17858 // does not need for, as we wrap the input with it..
17860 cls : 'control-label box-label' + inline,
17863 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17867 //cls : 'control-label' + inline,
17868 html : this.fieldLabel,
17869 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17878 type : this.inputType,
17879 //value : (!this.checked) ? this.valueOff : this.inputValue,
17880 value : this.inputValue,
17882 placeholder : this.placeholder || '' // ?? needed????
17885 if (this.weight) { // Validity check?
17886 input.cls += " radio-" + this.weight;
17888 if (this.disabled) {
17889 input.disabled=true;
17893 input.checked = this.checked;
17897 input.name = this.name;
17901 input.cls += ' input-' + this.size;
17904 //?? can span's inline have a width??
17907 ['xs','sm','md','lg'].map(function(size){
17908 if (settings[size]) {
17909 cfg.cls += ' col-' + size + '-' + settings[size];
17913 var inputblock = input;
17915 if (this.before || this.after) {
17918 cls : 'input-group',
17923 inputblock.cn.push({
17925 cls : 'input-group-addon',
17929 inputblock.cn.push(input);
17931 inputblock.cn.push({
17933 cls : 'input-group-addon',
17941 if (this.fieldLabel && this.fieldLabel.length) {
17942 cfg.cn.push(fieldLabel);
17945 // normal bootstrap puts the input inside the label.
17946 // however with our styled version - it has to go after the input.
17948 //lbl.cn.push(inputblock);
17952 cls: 'radio' + inline,
17959 cfg.cn.push( lblwrap);
17964 html: this.boxLabel
17973 initEvents : function()
17975 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17977 this.inputEl().on('click', this.onClick, this);
17978 if (this.boxLabel) {
17979 Roo.log('find label')
17980 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17985 inputEl: function ()
17987 return this.el.select('input.roo-radio',true).first();
17989 onClick : function()
17992 this.setChecked(true);
17995 setChecked : function(state,suppressEvent)
17998 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17999 v.dom.checked = false;
18002 Roo.log(this.inputEl().dom);
18003 this.checked = state;
18004 this.inputEl().dom.checked = state;
18006 if(suppressEvent !== true){
18007 this.fireEvent('check', this, state);
18010 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18014 getGroupValue : function()
18017 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18018 if(v.dom.checked == true){
18019 value = v.dom.value;
18027 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18028 * @return {Mixed} value The field value
18030 getValue : function(){
18031 return this.getGroupValue();
18037 //<script type="text/javascript">
18040 * Based Ext JS Library 1.1.1
18041 * Copyright(c) 2006-2007, Ext JS, LLC.
18047 * @class Roo.HtmlEditorCore
18048 * @extends Roo.Component
18049 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18051 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18054 Roo.HtmlEditorCore = function(config){
18057 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18062 * @event initialize
18063 * Fires when the editor is fully initialized (including the iframe)
18064 * @param {Roo.HtmlEditorCore} this
18069 * Fires when the editor is first receives the focus. Any insertion must wait
18070 * until after this event.
18071 * @param {Roo.HtmlEditorCore} this
18075 * @event beforesync
18076 * Fires before the textarea is updated with content from the editor iframe. Return false
18077 * to cancel the sync.
18078 * @param {Roo.HtmlEditorCore} this
18079 * @param {String} html
18083 * @event beforepush
18084 * Fires before the iframe editor is updated with content from the textarea. Return false
18085 * to cancel the push.
18086 * @param {Roo.HtmlEditorCore} this
18087 * @param {String} html
18092 * Fires when the textarea is updated with content from the editor iframe.
18093 * @param {Roo.HtmlEditorCore} this
18094 * @param {String} html
18099 * Fires when the iframe editor is updated with content from the textarea.
18100 * @param {Roo.HtmlEditorCore} this
18101 * @param {String} html
18106 * @event editorevent
18107 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18108 * @param {Roo.HtmlEditorCore} this
18114 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18116 // defaults : white / black...
18117 this.applyBlacklists();
18124 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18128 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18134 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18139 * @cfg {Number} height (in pixels)
18143 * @cfg {Number} width (in pixels)
18148 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18151 stylesheets: false,
18156 // private properties
18157 validationEvent : false,
18159 initialized : false,
18161 sourceEditMode : false,
18162 onFocus : Roo.emptyFn,
18164 hideMode:'offsets',
18168 // blacklist + whitelisted elements..
18175 * Protected method that will not generally be called directly. It
18176 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18177 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18179 getDocMarkup : function(){
18183 // inherit styels from page...??
18184 if (this.stylesheets === false) {
18186 Roo.get(document.head).select('style').each(function(node) {
18187 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18190 Roo.get(document.head).select('link').each(function(node) {
18191 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18194 } else if (!this.stylesheets.length) {
18196 st = '<style type="text/css">' +
18197 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18203 st += '<style type="text/css">' +
18204 'IMG { cursor: pointer } ' +
18208 return '<html><head>' + st +
18209 //<style type="text/css">' +
18210 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18212 ' </head><body class="roo-htmleditor-body"></body></html>';
18216 onRender : function(ct, position)
18219 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18220 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18223 this.el.dom.style.border = '0 none';
18224 this.el.dom.setAttribute('tabIndex', -1);
18225 this.el.addClass('x-hidden hide');
18229 if(Roo.isIE){ // fix IE 1px bogus margin
18230 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18234 this.frameId = Roo.id();
18238 var iframe = this.owner.wrap.createChild({
18240 cls: 'form-control', // bootstrap..
18242 name: this.frameId,
18243 frameBorder : 'no',
18244 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18249 this.iframe = iframe.dom;
18251 this.assignDocWin();
18253 this.doc.designMode = 'on';
18256 this.doc.write(this.getDocMarkup());
18260 var task = { // must defer to wait for browser to be ready
18262 //console.log("run task?" + this.doc.readyState);
18263 this.assignDocWin();
18264 if(this.doc.body || this.doc.readyState == 'complete'){
18266 this.doc.designMode="on";
18270 Roo.TaskMgr.stop(task);
18271 this.initEditor.defer(10, this);
18278 Roo.TaskMgr.start(task);
18283 onResize : function(w, h)
18285 Roo.log('resize: ' +w + ',' + h );
18286 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18290 if(typeof w == 'number'){
18292 this.iframe.style.width = w + 'px';
18294 if(typeof h == 'number'){
18296 this.iframe.style.height = h + 'px';
18298 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18305 * Toggles the editor between standard and source edit mode.
18306 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18308 toggleSourceEdit : function(sourceEditMode){
18310 this.sourceEditMode = sourceEditMode === true;
18312 if(this.sourceEditMode){
18314 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18317 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18318 //this.iframe.className = '';
18321 //this.setSize(this.owner.wrap.getSize());
18322 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18329 * Protected method that will not generally be called directly. If you need/want
18330 * custom HTML cleanup, this is the method you should override.
18331 * @param {String} html The HTML to be cleaned
18332 * return {String} The cleaned HTML
18334 cleanHtml : function(html){
18335 html = String(html);
18336 if(html.length > 5){
18337 if(Roo.isSafari){ // strip safari nonsense
18338 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18341 if(html == ' '){
18348 * HTML Editor -> Textarea
18349 * Protected method that will not generally be called directly. Syncs the contents
18350 * of the editor iframe with the textarea.
18352 syncValue : function(){
18353 if(this.initialized){
18354 var bd = (this.doc.body || this.doc.documentElement);
18355 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18356 var html = bd.innerHTML;
18358 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18359 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18361 html = '<div style="'+m[0]+'">' + html + '</div>';
18364 html = this.cleanHtml(html);
18365 // fix up the special chars.. normaly like back quotes in word...
18366 // however we do not want to do this with chinese..
18367 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18368 var cc = b.charCodeAt();
18370 (cc >= 0x4E00 && cc < 0xA000 ) ||
18371 (cc >= 0x3400 && cc < 0x4E00 ) ||
18372 (cc >= 0xf900 && cc < 0xfb00 )
18378 if(this.owner.fireEvent('beforesync', this, html) !== false){
18379 this.el.dom.value = html;
18380 this.owner.fireEvent('sync', this, html);
18386 * Protected method that will not generally be called directly. Pushes the value of the textarea
18387 * into the iframe editor.
18389 pushValue : function(){
18390 if(this.initialized){
18391 var v = this.el.dom.value.trim();
18393 // if(v.length < 1){
18397 if(this.owner.fireEvent('beforepush', this, v) !== false){
18398 var d = (this.doc.body || this.doc.documentElement);
18400 this.cleanUpPaste();
18401 this.el.dom.value = d.innerHTML;
18402 this.owner.fireEvent('push', this, v);
18408 deferFocus : function(){
18409 this.focus.defer(10, this);
18413 focus : function(){
18414 if(this.win && !this.sourceEditMode){
18421 assignDocWin: function()
18423 var iframe = this.iframe;
18426 this.doc = iframe.contentWindow.document;
18427 this.win = iframe.contentWindow;
18429 // if (!Roo.get(this.frameId)) {
18432 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18433 // this.win = Roo.get(this.frameId).dom.contentWindow;
18435 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18439 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18440 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18445 initEditor : function(){
18446 //console.log("INIT EDITOR");
18447 this.assignDocWin();
18451 this.doc.designMode="on";
18453 this.doc.write(this.getDocMarkup());
18456 var dbody = (this.doc.body || this.doc.documentElement);
18457 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18458 // this copies styles from the containing element into thsi one..
18459 // not sure why we need all of this..
18460 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18462 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18463 //ss['background-attachment'] = 'fixed'; // w3c
18464 dbody.bgProperties = 'fixed'; // ie
18465 //Roo.DomHelper.applyStyles(dbody, ss);
18466 Roo.EventManager.on(this.doc, {
18467 //'mousedown': this.onEditorEvent,
18468 'mouseup': this.onEditorEvent,
18469 'dblclick': this.onEditorEvent,
18470 'click': this.onEditorEvent,
18471 'keyup': this.onEditorEvent,
18476 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18478 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18479 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18481 this.initialized = true;
18483 this.owner.fireEvent('initialize', this);
18488 onDestroy : function(){
18494 //for (var i =0; i < this.toolbars.length;i++) {
18495 // // fixme - ask toolbars for heights?
18496 // this.toolbars[i].onDestroy();
18499 //this.wrap.dom.innerHTML = '';
18500 //this.wrap.remove();
18505 onFirstFocus : function(){
18507 this.assignDocWin();
18510 this.activated = true;
18513 if(Roo.isGecko){ // prevent silly gecko errors
18515 var s = this.win.getSelection();
18516 if(!s.focusNode || s.focusNode.nodeType != 3){
18517 var r = s.getRangeAt(0);
18518 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18523 this.execCmd('useCSS', true);
18524 this.execCmd('styleWithCSS', false);
18527 this.owner.fireEvent('activate', this);
18531 adjustFont: function(btn){
18532 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18533 //if(Roo.isSafari){ // safari
18536 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18537 if(Roo.isSafari){ // safari
18538 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18539 v = (v < 10) ? 10 : v;
18540 v = (v > 48) ? 48 : v;
18541 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18546 v = Math.max(1, v+adjust);
18548 this.execCmd('FontSize', v );
18551 onEditorEvent : function(e)
18553 this.owner.fireEvent('editorevent', this, e);
18554 // this.updateToolbar();
18555 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18558 insertTag : function(tg)
18560 // could be a bit smarter... -> wrap the current selected tRoo..
18561 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18563 range = this.createRange(this.getSelection());
18564 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18565 wrappingNode.appendChild(range.extractContents());
18566 range.insertNode(wrappingNode);
18573 this.execCmd("formatblock", tg);
18577 insertText : function(txt)
18581 var range = this.createRange();
18582 range.deleteContents();
18583 //alert(Sender.getAttribute('label'));
18585 range.insertNode(this.doc.createTextNode(txt));
18591 * Executes a Midas editor command on the editor document and performs necessary focus and
18592 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18593 * @param {String} cmd The Midas command
18594 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18596 relayCmd : function(cmd, value){
18598 this.execCmd(cmd, value);
18599 this.owner.fireEvent('editorevent', this);
18600 //this.updateToolbar();
18601 this.owner.deferFocus();
18605 * Executes a Midas editor command directly on the editor document.
18606 * For visual commands, you should use {@link #relayCmd} instead.
18607 * <b>This should only be called after the editor is initialized.</b>
18608 * @param {String} cmd The Midas command
18609 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18611 execCmd : function(cmd, value){
18612 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18619 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18621 * @param {String} text | dom node..
18623 insertAtCursor : function(text)
18628 if(!this.activated){
18634 var r = this.doc.selection.createRange();
18645 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18649 // from jquery ui (MIT licenced)
18651 var win = this.win;
18653 if (win.getSelection && win.getSelection().getRangeAt) {
18654 range = win.getSelection().getRangeAt(0);
18655 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18656 range.insertNode(node);
18657 } else if (win.document.selection && win.document.selection.createRange) {
18658 // no firefox support
18659 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18660 win.document.selection.createRange().pasteHTML(txt);
18662 // no firefox support
18663 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18664 this.execCmd('InsertHTML', txt);
18673 mozKeyPress : function(e){
18675 var c = e.getCharCode(), cmd;
18678 c = String.fromCharCode(c).toLowerCase();
18692 this.cleanUpPaste.defer(100, this);
18700 e.preventDefault();
18708 fixKeys : function(){ // load time branching for fastest keydown performance
18710 return function(e){
18711 var k = e.getKey(), r;
18714 r = this.doc.selection.createRange();
18717 r.pasteHTML('    ');
18724 r = this.doc.selection.createRange();
18726 var target = r.parentElement();
18727 if(!target || target.tagName.toLowerCase() != 'li'){
18729 r.pasteHTML('<br />');
18735 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18736 this.cleanUpPaste.defer(100, this);
18742 }else if(Roo.isOpera){
18743 return function(e){
18744 var k = e.getKey();
18748 this.execCmd('InsertHTML','    ');
18751 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18752 this.cleanUpPaste.defer(100, this);
18757 }else if(Roo.isSafari){
18758 return function(e){
18759 var k = e.getKey();
18763 this.execCmd('InsertText','\t');
18767 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18768 this.cleanUpPaste.defer(100, this);
18776 getAllAncestors: function()
18778 var p = this.getSelectedNode();
18781 a.push(p); // push blank onto stack..
18782 p = this.getParentElement();
18786 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18790 a.push(this.doc.body);
18794 lastSelNode : false,
18797 getSelection : function()
18799 this.assignDocWin();
18800 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18803 getSelectedNode: function()
18805 // this may only work on Gecko!!!
18807 // should we cache this!!!!
18812 var range = this.createRange(this.getSelection()).cloneRange();
18815 var parent = range.parentElement();
18817 var testRange = range.duplicate();
18818 testRange.moveToElementText(parent);
18819 if (testRange.inRange(range)) {
18822 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18825 parent = parent.parentElement;
18830 // is ancestor a text element.
18831 var ac = range.commonAncestorContainer;
18832 if (ac.nodeType == 3) {
18833 ac = ac.parentNode;
18836 var ar = ac.childNodes;
18839 var other_nodes = [];
18840 var has_other_nodes = false;
18841 for (var i=0;i<ar.length;i++) {
18842 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18845 // fullly contained node.
18847 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18852 // probably selected..
18853 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18854 other_nodes.push(ar[i]);
18858 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18863 has_other_nodes = true;
18865 if (!nodes.length && other_nodes.length) {
18866 nodes= other_nodes;
18868 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18874 createRange: function(sel)
18876 // this has strange effects when using with
18877 // top toolbar - not sure if it's a great idea.
18878 //this.editor.contentWindow.focus();
18879 if (typeof sel != "undefined") {
18881 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18883 return this.doc.createRange();
18886 return this.doc.createRange();
18889 getParentElement: function()
18892 this.assignDocWin();
18893 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18895 var range = this.createRange(sel);
18898 var p = range.commonAncestorContainer;
18899 while (p.nodeType == 3) { // text node
18910 * Range intersection.. the hard stuff...
18914 * [ -- selected range --- ]
18918 * if end is before start or hits it. fail.
18919 * if start is after end or hits it fail.
18921 * if either hits (but other is outside. - then it's not
18927 // @see http://www.thismuchiknow.co.uk/?p=64.
18928 rangeIntersectsNode : function(range, node)
18930 var nodeRange = node.ownerDocument.createRange();
18932 nodeRange.selectNode(node);
18934 nodeRange.selectNodeContents(node);
18937 var rangeStartRange = range.cloneRange();
18938 rangeStartRange.collapse(true);
18940 var rangeEndRange = range.cloneRange();
18941 rangeEndRange.collapse(false);
18943 var nodeStartRange = nodeRange.cloneRange();
18944 nodeStartRange.collapse(true);
18946 var nodeEndRange = nodeRange.cloneRange();
18947 nodeEndRange.collapse(false);
18949 return rangeStartRange.compareBoundaryPoints(
18950 Range.START_TO_START, nodeEndRange) == -1 &&
18951 rangeEndRange.compareBoundaryPoints(
18952 Range.START_TO_START, nodeStartRange) == 1;
18956 rangeCompareNode : function(range, node)
18958 var nodeRange = node.ownerDocument.createRange();
18960 nodeRange.selectNode(node);
18962 nodeRange.selectNodeContents(node);
18966 range.collapse(true);
18968 nodeRange.collapse(true);
18970 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18971 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18973 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18975 var nodeIsBefore = ss == 1;
18976 var nodeIsAfter = ee == -1;
18978 if (nodeIsBefore && nodeIsAfter)
18980 if (!nodeIsBefore && nodeIsAfter)
18981 return 1; //right trailed.
18983 if (nodeIsBefore && !nodeIsAfter)
18984 return 2; // left trailed.
18989 // private? - in a new class?
18990 cleanUpPaste : function()
18992 // cleans up the whole document..
18993 Roo.log('cleanuppaste');
18995 this.cleanUpChildren(this.doc.body);
18996 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18997 if (clean != this.doc.body.innerHTML) {
18998 this.doc.body.innerHTML = clean;
19003 cleanWordChars : function(input) {// change the chars to hex code
19004 var he = Roo.HtmlEditorCore;
19006 var output = input;
19007 Roo.each(he.swapCodes, function(sw) {
19008 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19010 output = output.replace(swapper, sw[1]);
19017 cleanUpChildren : function (n)
19019 if (!n.childNodes.length) {
19022 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19023 this.cleanUpChild(n.childNodes[i]);
19030 cleanUpChild : function (node)
19033 //console.log(node);
19034 if (node.nodeName == "#text") {
19035 // clean up silly Windows -- stuff?
19038 if (node.nodeName == "#comment") {
19039 node.parentNode.removeChild(node);
19040 // clean up silly Windows -- stuff?
19043 var lcname = node.tagName.toLowerCase();
19044 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19045 // whitelist of tags..
19047 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19049 node.parentNode.removeChild(node);
19054 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19056 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19057 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19059 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19060 // remove_keep_children = true;
19063 if (remove_keep_children) {
19064 this.cleanUpChildren(node);
19065 // inserts everything just before this node...
19066 while (node.childNodes.length) {
19067 var cn = node.childNodes[0];
19068 node.removeChild(cn);
19069 node.parentNode.insertBefore(cn, node);
19071 node.parentNode.removeChild(node);
19075 if (!node.attributes || !node.attributes.length) {
19076 this.cleanUpChildren(node);
19080 function cleanAttr(n,v)
19083 if (v.match(/^\./) || v.match(/^\//)) {
19086 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19089 if (v.match(/^#/)) {
19092 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19093 node.removeAttribute(n);
19097 var cwhite = this.cwhite;
19098 var cblack = this.cblack;
19100 function cleanStyle(n,v)
19102 if (v.match(/expression/)) { //XSS?? should we even bother..
19103 node.removeAttribute(n);
19107 var parts = v.split(/;/);
19110 Roo.each(parts, function(p) {
19111 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19115 var l = p.split(':').shift().replace(/\s+/g,'');
19116 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19118 if ( cwhite.length && cblack.indexOf(l) > -1) {
19119 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19120 //node.removeAttribute(n);
19124 // only allow 'c whitelisted system attributes'
19125 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19126 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19127 //node.removeAttribute(n);
19137 if (clean.length) {
19138 node.setAttribute(n, clean.join(';'));
19140 node.removeAttribute(n);
19146 for (var i = node.attributes.length-1; i > -1 ; i--) {
19147 var a = node.attributes[i];
19150 if (a.name.toLowerCase().substr(0,2)=='on') {
19151 node.removeAttribute(a.name);
19154 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19155 node.removeAttribute(a.name);
19158 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19159 cleanAttr(a.name,a.value); // fixme..
19162 if (a.name == 'style') {
19163 cleanStyle(a.name,a.value);
19166 /// clean up MS crap..
19167 // tecnically this should be a list of valid class'es..
19170 if (a.name == 'class') {
19171 if (a.value.match(/^Mso/)) {
19172 node.className = '';
19175 if (a.value.match(/body/)) {
19176 node.className = '';
19187 this.cleanUpChildren(node);
19193 * Clean up MS wordisms...
19195 cleanWord : function(node)
19200 this.cleanWord(this.doc.body);
19203 if (node.nodeName == "#text") {
19204 // clean up silly Windows -- stuff?
19207 if (node.nodeName == "#comment") {
19208 node.parentNode.removeChild(node);
19209 // clean up silly Windows -- stuff?
19213 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19214 node.parentNode.removeChild(node);
19218 // remove - but keep children..
19219 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19220 while (node.childNodes.length) {
19221 var cn = node.childNodes[0];
19222 node.removeChild(cn);
19223 node.parentNode.insertBefore(cn, node);
19225 node.parentNode.removeChild(node);
19226 this.iterateChildren(node, this.cleanWord);
19230 if (node.className.length) {
19232 var cn = node.className.split(/\W+/);
19234 Roo.each(cn, function(cls) {
19235 if (cls.match(/Mso[a-zA-Z]+/)) {
19240 node.className = cna.length ? cna.join(' ') : '';
19242 node.removeAttribute("class");
19246 if (node.hasAttribute("lang")) {
19247 node.removeAttribute("lang");
19250 if (node.hasAttribute("style")) {
19252 var styles = node.getAttribute("style").split(";");
19254 Roo.each(styles, function(s) {
19255 if (!s.match(/:/)) {
19258 var kv = s.split(":");
19259 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19262 // what ever is left... we allow.
19265 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19266 if (!nstyle.length) {
19267 node.removeAttribute('style');
19270 this.iterateChildren(node, this.cleanWord);
19276 * iterateChildren of a Node, calling fn each time, using this as the scole..
19277 * @param {DomNode} node node to iterate children of.
19278 * @param {Function} fn method of this class to call on each item.
19280 iterateChildren : function(node, fn)
19282 if (!node.childNodes.length) {
19285 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19286 fn.call(this, node.childNodes[i])
19292 * cleanTableWidths.
19294 * Quite often pasting from word etc.. results in tables with column and widths.
19295 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19298 cleanTableWidths : function(node)
19303 this.cleanTableWidths(this.doc.body);
19308 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19311 Roo.log(node.tagName);
19312 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19313 this.iterateChildren(node, this.cleanTableWidths);
19316 if (node.hasAttribute('width')) {
19317 node.removeAttribute('width');
19321 if (node.hasAttribute("style")) {
19324 var styles = node.getAttribute("style").split(";");
19326 Roo.each(styles, function(s) {
19327 if (!s.match(/:/)) {
19330 var kv = s.split(":");
19331 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
19334 // what ever is left... we allow.
19337 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19338 if (!nstyle.length) {
19339 node.removeAttribute('style');
19343 this.iterateChildren(node, this.cleanTableWidths);
19351 domToHTML : function(currentElement, depth, nopadtext) {
19353 depth = depth || 0;
19354 nopadtext = nopadtext || false;
19356 if (!currentElement) {
19357 return this.domToHTML(this.doc.body);
19360 //Roo.log(currentElement);
19362 var allText = false;
19363 var nodeName = currentElement.nodeName;
19364 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19366 if (nodeName == '#text') {
19368 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19373 if (nodeName != 'BODY') {
19376 // Prints the node tagName, such as <A>, <IMG>, etc
19379 for(i = 0; i < currentElement.attributes.length;i++) {
19381 var aname = currentElement.attributes.item(i).name;
19382 if (!currentElement.attributes.item(i).value.length) {
19385 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19388 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19397 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19400 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19405 // Traverse the tree
19407 var currentElementChild = currentElement.childNodes.item(i);
19408 var allText = true;
19409 var innerHTML = '';
19411 while (currentElementChild) {
19412 // Formatting code (indent the tree so it looks nice on the screen)
19413 var nopad = nopadtext;
19414 if (lastnode == 'SPAN') {
19418 if (currentElementChild.nodeName == '#text') {
19419 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19420 toadd = nopadtext ? toadd : toadd.trim();
19421 if (!nopad && toadd.length > 80) {
19422 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19424 innerHTML += toadd;
19427 currentElementChild = currentElement.childNodes.item(i);
19433 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19435 // Recursively traverse the tree structure of the child node
19436 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19437 lastnode = currentElementChild.nodeName;
19439 currentElementChild=currentElement.childNodes.item(i);
19445 // The remaining code is mostly for formatting the tree
19446 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19451 ret+= "</"+tagName+">";
19457 applyBlacklists : function()
19459 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19460 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19464 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19465 if (b.indexOf(tag) > -1) {
19468 this.white.push(tag);
19472 Roo.each(w, function(tag) {
19473 if (b.indexOf(tag) > -1) {
19476 if (this.white.indexOf(tag) > -1) {
19479 this.white.push(tag);
19484 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19485 if (w.indexOf(tag) > -1) {
19488 this.black.push(tag);
19492 Roo.each(b, function(tag) {
19493 if (w.indexOf(tag) > -1) {
19496 if (this.black.indexOf(tag) > -1) {
19499 this.black.push(tag);
19504 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19505 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19509 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19510 if (b.indexOf(tag) > -1) {
19513 this.cwhite.push(tag);
19517 Roo.each(w, function(tag) {
19518 if (b.indexOf(tag) > -1) {
19521 if (this.cwhite.indexOf(tag) > -1) {
19524 this.cwhite.push(tag);
19529 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19530 if (w.indexOf(tag) > -1) {
19533 this.cblack.push(tag);
19537 Roo.each(b, function(tag) {
19538 if (w.indexOf(tag) > -1) {
19541 if (this.cblack.indexOf(tag) > -1) {
19544 this.cblack.push(tag);
19549 setStylesheets : function(stylesheets)
19551 if(typeof(stylesheets) == 'string'){
19552 Roo.get(this.iframe.contentDocument.head).createChild({
19554 rel : 'stylesheet',
19563 Roo.each(stylesheets, function(s) {
19568 Roo.get(_this.iframe.contentDocument.head).createChild({
19570 rel : 'stylesheet',
19579 removeStylesheets : function()
19583 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19588 // hide stuff that is not compatible
19602 * @event specialkey
19606 * @cfg {String} fieldClass @hide
19609 * @cfg {String} focusClass @hide
19612 * @cfg {String} autoCreate @hide
19615 * @cfg {String} inputType @hide
19618 * @cfg {String} invalidClass @hide
19621 * @cfg {String} invalidText @hide
19624 * @cfg {String} msgFx @hide
19627 * @cfg {String} validateOnBlur @hide
19631 Roo.HtmlEditorCore.white = [
19632 'area', 'br', 'img', 'input', 'hr', 'wbr',
19634 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19635 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19636 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19637 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19638 'table', 'ul', 'xmp',
19640 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19643 'dir', 'menu', 'ol', 'ul', 'dl',
19649 Roo.HtmlEditorCore.black = [
19650 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19652 'base', 'basefont', 'bgsound', 'blink', 'body',
19653 'frame', 'frameset', 'head', 'html', 'ilayer',
19654 'iframe', 'layer', 'link', 'meta', 'object',
19655 'script', 'style' ,'title', 'xml' // clean later..
19657 Roo.HtmlEditorCore.clean = [
19658 'script', 'style', 'title', 'xml'
19660 Roo.HtmlEditorCore.remove = [
19665 Roo.HtmlEditorCore.ablack = [
19669 Roo.HtmlEditorCore.aclean = [
19670 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19674 Roo.HtmlEditorCore.pwhite= [
19675 'http', 'https', 'mailto'
19678 // white listed style attributes.
19679 Roo.HtmlEditorCore.cwhite= [
19680 // 'text-align', /// default is to allow most things..
19686 // black listed style attributes.
19687 Roo.HtmlEditorCore.cblack= [
19688 // 'font-size' -- this can be set by the project
19692 Roo.HtmlEditorCore.swapCodes =[
19711 * @class Roo.bootstrap.HtmlEditor
19712 * @extends Roo.bootstrap.TextArea
19713 * Bootstrap HtmlEditor class
19716 * Create a new HtmlEditor
19717 * @param {Object} config The config object
19720 Roo.bootstrap.HtmlEditor = function(config){
19721 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19722 if (!this.toolbars) {
19723 this.toolbars = [];
19725 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19728 * @event initialize
19729 * Fires when the editor is fully initialized (including the iframe)
19730 * @param {HtmlEditor} this
19735 * Fires when the editor is first receives the focus. Any insertion must wait
19736 * until after this event.
19737 * @param {HtmlEditor} this
19741 * @event beforesync
19742 * Fires before the textarea is updated with content from the editor iframe. Return false
19743 * to cancel the sync.
19744 * @param {HtmlEditor} this
19745 * @param {String} html
19749 * @event beforepush
19750 * Fires before the iframe editor is updated with content from the textarea. Return false
19751 * to cancel the push.
19752 * @param {HtmlEditor} this
19753 * @param {String} html
19758 * Fires when the textarea is updated with content from the editor iframe.
19759 * @param {HtmlEditor} this
19760 * @param {String} html
19765 * Fires when the iframe editor is updated with content from the textarea.
19766 * @param {HtmlEditor} this
19767 * @param {String} html
19771 * @event editmodechange
19772 * Fires when the editor switches edit modes
19773 * @param {HtmlEditor} this
19774 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19776 editmodechange: true,
19778 * @event editorevent
19779 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19780 * @param {HtmlEditor} this
19784 * @event firstfocus
19785 * Fires when on first focus - needed by toolbars..
19786 * @param {HtmlEditor} this
19791 * Auto save the htmlEditor value as a file into Events
19792 * @param {HtmlEditor} this
19796 * @event savedpreview
19797 * preview the saved version of htmlEditor
19798 * @param {HtmlEditor} this
19805 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19809 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19814 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19819 * @cfg {Number} height (in pixels)
19823 * @cfg {Number} width (in pixels)
19828 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19831 stylesheets: false,
19836 // private properties
19837 validationEvent : false,
19839 initialized : false,
19842 onFocus : Roo.emptyFn,
19844 hideMode:'offsets',
19847 tbContainer : false,
19849 toolbarContainer :function() {
19850 return this.wrap.select('.x-html-editor-tb',true).first();
19854 * Protected method that will not generally be called directly. It
19855 * is called when the editor creates its toolbar. Override this method if you need to
19856 * add custom toolbar buttons.
19857 * @param {HtmlEditor} editor
19859 createToolbar : function(){
19861 Roo.log("create toolbars");
19863 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19864 this.toolbars[0].render(this.toolbarContainer());
19868 // if (!editor.toolbars || !editor.toolbars.length) {
19869 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19872 // for (var i =0 ; i < editor.toolbars.length;i++) {
19873 // editor.toolbars[i] = Roo.factory(
19874 // typeof(editor.toolbars[i]) == 'string' ?
19875 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19876 // Roo.bootstrap.HtmlEditor);
19877 // editor.toolbars[i].init(editor);
19883 onRender : function(ct, position)
19885 // Roo.log("Call onRender: " + this.xtype);
19887 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19889 this.wrap = this.inputEl().wrap({
19890 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19893 this.editorcore.onRender(ct, position);
19895 if (this.resizable) {
19896 this.resizeEl = new Roo.Resizable(this.wrap, {
19900 minHeight : this.height,
19901 height: this.height,
19902 handles : this.resizable,
19905 resize : function(r, w, h) {
19906 _t.onResize(w,h); // -something
19912 this.createToolbar(this);
19915 if(!this.width && this.resizable){
19916 this.setSize(this.wrap.getSize());
19918 if (this.resizeEl) {
19919 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19920 // should trigger onReize..
19926 onResize : function(w, h)
19928 Roo.log('resize: ' +w + ',' + h );
19929 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19933 if(this.inputEl() ){
19934 if(typeof w == 'number'){
19935 var aw = w - this.wrap.getFrameWidth('lr');
19936 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19939 if(typeof h == 'number'){
19940 var tbh = -11; // fixme it needs to tool bar size!
19941 for (var i =0; i < this.toolbars.length;i++) {
19942 // fixme - ask toolbars for heights?
19943 tbh += this.toolbars[i].el.getHeight();
19944 //if (this.toolbars[i].footer) {
19945 // tbh += this.toolbars[i].footer.el.getHeight();
19953 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19954 ah -= 5; // knock a few pixes off for look..
19955 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19959 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19960 this.editorcore.onResize(ew,eh);
19965 * Toggles the editor between standard and source edit mode.
19966 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19968 toggleSourceEdit : function(sourceEditMode)
19970 this.editorcore.toggleSourceEdit(sourceEditMode);
19972 if(this.editorcore.sourceEditMode){
19973 Roo.log('editor - showing textarea');
19976 // Roo.log(this.syncValue());
19978 this.inputEl().removeClass(['hide', 'x-hidden']);
19979 this.inputEl().dom.removeAttribute('tabIndex');
19980 this.inputEl().focus();
19982 Roo.log('editor - hiding textarea');
19984 // Roo.log(this.pushValue());
19987 this.inputEl().addClass(['hide', 'x-hidden']);
19988 this.inputEl().dom.setAttribute('tabIndex', -1);
19989 //this.deferFocus();
19992 if(this.resizable){
19993 this.setSize(this.wrap.getSize());
19996 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19999 // private (for BoxComponent)
20000 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20002 // private (for BoxComponent)
20003 getResizeEl : function(){
20007 // private (for BoxComponent)
20008 getPositionEl : function(){
20013 initEvents : function(){
20014 this.originalValue = this.getValue();
20018 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20021 // markInvalid : Roo.emptyFn,
20023 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20026 // clearInvalid : Roo.emptyFn,
20028 setValue : function(v){
20029 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20030 this.editorcore.pushValue();
20035 deferFocus : function(){
20036 this.focus.defer(10, this);
20040 focus : function(){
20041 this.editorcore.focus();
20047 onDestroy : function(){
20053 for (var i =0; i < this.toolbars.length;i++) {
20054 // fixme - ask toolbars for heights?
20055 this.toolbars[i].onDestroy();
20058 this.wrap.dom.innerHTML = '';
20059 this.wrap.remove();
20064 onFirstFocus : function(){
20065 //Roo.log("onFirstFocus");
20066 this.editorcore.onFirstFocus();
20067 for (var i =0; i < this.toolbars.length;i++) {
20068 this.toolbars[i].onFirstFocus();
20074 syncValue : function()
20076 this.editorcore.syncValue();
20079 pushValue : function()
20081 this.editorcore.pushValue();
20085 // hide stuff that is not compatible
20099 * @event specialkey
20103 * @cfg {String} fieldClass @hide
20106 * @cfg {String} focusClass @hide
20109 * @cfg {String} autoCreate @hide
20112 * @cfg {String} inputType @hide
20115 * @cfg {String} invalidClass @hide
20118 * @cfg {String} invalidText @hide
20121 * @cfg {String} msgFx @hide
20124 * @cfg {String} validateOnBlur @hide
20133 Roo.namespace('Roo.bootstrap.htmleditor');
20135 * @class Roo.bootstrap.HtmlEditorToolbar1
20140 new Roo.bootstrap.HtmlEditor({
20143 new Roo.bootstrap.HtmlEditorToolbar1({
20144 disable : { fonts: 1 , format: 1, ..., ... , ...],
20150 * @cfg {Object} disable List of elements to disable..
20151 * @cfg {Array} btns List of additional buttons.
20155 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20158 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20161 Roo.apply(this, config);
20163 // default disabled, based on 'good practice'..
20164 this.disable = this.disable || {};
20165 Roo.applyIf(this.disable, {
20168 specialElements : true
20170 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20172 this.editor = config.editor;
20173 this.editorcore = config.editor.editorcore;
20175 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20177 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20178 // dont call parent... till later.
20180 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20185 editorcore : false,
20190 "h1","h2","h3","h4","h5","h6",
20192 "abbr", "acronym", "address", "cite", "samp", "var",
20196 onRender : function(ct, position)
20198 // Roo.log("Call onRender: " + this.xtype);
20200 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20202 this.el.dom.style.marginBottom = '0';
20204 var editorcore = this.editorcore;
20205 var editor= this.editor;
20208 var btn = function(id,cmd , toggle, handler){
20210 var event = toggle ? 'toggle' : 'click';
20215 xns: Roo.bootstrap,
20218 enableToggle:toggle !== false,
20220 pressed : toggle ? false : null,
20223 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20224 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20233 xns: Roo.bootstrap,
20234 glyphicon : 'font',
20238 xns: Roo.bootstrap,
20242 Roo.each(this.formats, function(f) {
20243 style.menu.items.push({
20245 xns: Roo.bootstrap,
20246 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20251 editorcore.insertTag(this.tagname);
20258 children.push(style);
20261 btn('bold',false,true);
20262 btn('italic',false,true);
20263 btn('align-left', 'justifyleft',true);
20264 btn('align-center', 'justifycenter',true);
20265 btn('align-right' , 'justifyright',true);
20266 btn('link', false, false, function(btn) {
20267 //Roo.log("create link?");
20268 var url = prompt(this.createLinkText, this.defaultLinkValue);
20269 if(url && url != 'http:/'+'/'){
20270 this.editorcore.relayCmd('createlink', url);
20273 btn('list','insertunorderedlist',true);
20274 btn('pencil', false,true, function(btn){
20277 this.toggleSourceEdit(btn.pressed);
20283 xns: Roo.bootstrap,
20288 xns: Roo.bootstrap,
20293 cog.menu.items.push({
20295 xns: Roo.bootstrap,
20296 html : Clean styles,
20301 editorcore.insertTag(this.tagname);
20310 this.xtype = 'NavSimplebar';
20312 for(var i=0;i< children.length;i++) {
20314 this.buttons.add(this.addxtypeChild(children[i]));
20318 editor.on('editorevent', this.updateToolbar, this);
20320 onBtnClick : function(id)
20322 this.editorcore.relayCmd(id);
20323 this.editorcore.focus();
20327 * Protected method that will not generally be called directly. It triggers
20328 * a toolbar update by reading the markup state of the current selection in the editor.
20330 updateToolbar: function(){
20332 if(!this.editorcore.activated){
20333 this.editor.onFirstFocus(); // is this neeed?
20337 var btns = this.buttons;
20338 var doc = this.editorcore.doc;
20339 btns.get('bold').setActive(doc.queryCommandState('bold'));
20340 btns.get('italic').setActive(doc.queryCommandState('italic'));
20341 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20343 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20344 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20345 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20347 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20348 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20351 var ans = this.editorcore.getAllAncestors();
20352 if (this.formatCombo) {
20355 var store = this.formatCombo.store;
20356 this.formatCombo.setValue("");
20357 for (var i =0; i < ans.length;i++) {
20358 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20360 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20368 // hides menus... - so this cant be on a menu...
20369 Roo.bootstrap.MenuMgr.hideAll();
20371 Roo.bootstrap.MenuMgr.hideAll();
20372 //this.editorsyncValue();
20374 onFirstFocus: function() {
20375 this.buttons.each(function(item){
20379 toggleSourceEdit : function(sourceEditMode){
20382 if(sourceEditMode){
20383 Roo.log("disabling buttons");
20384 this.buttons.each( function(item){
20385 if(item.cmd != 'pencil'){
20391 Roo.log("enabling buttons");
20392 if(this.editorcore.initialized){
20393 this.buttons.each( function(item){
20399 Roo.log("calling toggole on editor");
20400 // tell the editor that it's been pressed..
20401 this.editor.toggleSourceEdit(sourceEditMode);
20411 * @class Roo.bootstrap.Table.AbstractSelectionModel
20412 * @extends Roo.util.Observable
20413 * Abstract base class for grid SelectionModels. It provides the interface that should be
20414 * implemented by descendant classes. This class should not be directly instantiated.
20417 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20418 this.locked = false;
20419 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20423 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20424 /** @ignore Called by the grid automatically. Do not call directly. */
20425 init : function(grid){
20431 * Locks the selections.
20434 this.locked = true;
20438 * Unlocks the selections.
20440 unlock : function(){
20441 this.locked = false;
20445 * Returns true if the selections are locked.
20446 * @return {Boolean}
20448 isLocked : function(){
20449 return this.locked;
20453 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20454 * @class Roo.bootstrap.Table.RowSelectionModel
20455 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20456 * It supports multiple selections and keyboard selection/navigation.
20458 * @param {Object} config
20461 Roo.bootstrap.Table.RowSelectionModel = function(config){
20462 Roo.apply(this, config);
20463 this.selections = new Roo.util.MixedCollection(false, function(o){
20468 this.lastActive = false;
20472 * @event selectionchange
20473 * Fires when the selection changes
20474 * @param {SelectionModel} this
20476 "selectionchange" : true,
20478 * @event afterselectionchange
20479 * Fires after the selection changes (eg. by key press or clicking)
20480 * @param {SelectionModel} this
20482 "afterselectionchange" : true,
20484 * @event beforerowselect
20485 * Fires when a row is selected being selected, return false to cancel.
20486 * @param {SelectionModel} this
20487 * @param {Number} rowIndex The selected index
20488 * @param {Boolean} keepExisting False if other selections will be cleared
20490 "beforerowselect" : true,
20493 * Fires when a row is selected.
20494 * @param {SelectionModel} this
20495 * @param {Number} rowIndex The selected index
20496 * @param {Roo.data.Record} r The record
20498 "rowselect" : true,
20500 * @event rowdeselect
20501 * Fires when a row is deselected.
20502 * @param {SelectionModel} this
20503 * @param {Number} rowIndex The selected index
20505 "rowdeselect" : true
20507 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20508 this.locked = false;
20511 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20513 * @cfg {Boolean} singleSelect
20514 * True to allow selection of only one row at a time (defaults to false)
20516 singleSelect : false,
20519 initEvents : function(){
20521 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20522 this.grid.on("mousedown", this.handleMouseDown, this);
20523 }else{ // allow click to work like normal
20524 this.grid.on("rowclick", this.handleDragableRowClick, this);
20527 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20528 "up" : function(e){
20530 this.selectPrevious(e.shiftKey);
20531 }else if(this.last !== false && this.lastActive !== false){
20532 var last = this.last;
20533 this.selectRange(this.last, this.lastActive-1);
20534 this.grid.getView().focusRow(this.lastActive);
20535 if(last !== false){
20539 this.selectFirstRow();
20541 this.fireEvent("afterselectionchange", this);
20543 "down" : function(e){
20545 this.selectNext(e.shiftKey);
20546 }else if(this.last !== false && this.lastActive !== false){
20547 var last = this.last;
20548 this.selectRange(this.last, this.lastActive+1);
20549 this.grid.getView().focusRow(this.lastActive);
20550 if(last !== false){
20554 this.selectFirstRow();
20556 this.fireEvent("afterselectionchange", this);
20561 var view = this.grid.view;
20562 view.on("refresh", this.onRefresh, this);
20563 view.on("rowupdated", this.onRowUpdated, this);
20564 view.on("rowremoved", this.onRemove, this);
20568 onRefresh : function(){
20569 var ds = this.grid.dataSource, i, v = this.grid.view;
20570 var s = this.selections;
20571 s.each(function(r){
20572 if((i = ds.indexOfId(r.id)) != -1){
20581 onRemove : function(v, index, r){
20582 this.selections.remove(r);
20586 onRowUpdated : function(v, index, r){
20587 if(this.isSelected(r)){
20588 v.onRowSelect(index);
20594 * @param {Array} records The records to select
20595 * @param {Boolean} keepExisting (optional) True to keep existing selections
20597 selectRecords : function(records, keepExisting){
20599 this.clearSelections();
20601 var ds = this.grid.dataSource;
20602 for(var i = 0, len = records.length; i < len; i++){
20603 this.selectRow(ds.indexOf(records[i]), true);
20608 * Gets the number of selected rows.
20611 getCount : function(){
20612 return this.selections.length;
20616 * Selects the first row in the grid.
20618 selectFirstRow : function(){
20623 * Select the last row.
20624 * @param {Boolean} keepExisting (optional) True to keep existing selections
20626 selectLastRow : function(keepExisting){
20627 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20631 * Selects the row immediately following the last selected row.
20632 * @param {Boolean} keepExisting (optional) True to keep existing selections
20634 selectNext : function(keepExisting){
20635 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20636 this.selectRow(this.last+1, keepExisting);
20637 this.grid.getView().focusRow(this.last);
20642 * Selects the row that precedes the last selected row.
20643 * @param {Boolean} keepExisting (optional) True to keep existing selections
20645 selectPrevious : function(keepExisting){
20647 this.selectRow(this.last-1, keepExisting);
20648 this.grid.getView().focusRow(this.last);
20653 * Returns the selected records
20654 * @return {Array} Array of selected records
20656 getSelections : function(){
20657 return [].concat(this.selections.items);
20661 * Returns the first selected record.
20664 getSelected : function(){
20665 return this.selections.itemAt(0);
20670 * Clears all selections.
20672 clearSelections : function(fast){
20673 if(this.locked) return;
20675 var ds = this.grid.dataSource;
20676 var s = this.selections;
20677 s.each(function(r){
20678 this.deselectRow(ds.indexOfId(r.id));
20682 this.selections.clear();
20689 * Selects all rows.
20691 selectAll : function(){
20692 if(this.locked) return;
20693 this.selections.clear();
20694 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20695 this.selectRow(i, true);
20700 * Returns True if there is a selection.
20701 * @return {Boolean}
20703 hasSelection : function(){
20704 return this.selections.length > 0;
20708 * Returns True if the specified row is selected.
20709 * @param {Number/Record} record The record or index of the record to check
20710 * @return {Boolean}
20712 isSelected : function(index){
20713 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20714 return (r && this.selections.key(r.id) ? true : false);
20718 * Returns True if the specified record id is selected.
20719 * @param {String} id The id of record to check
20720 * @return {Boolean}
20722 isIdSelected : function(id){
20723 return (this.selections.key(id) ? true : false);
20727 handleMouseDown : function(e, t){
20728 var view = this.grid.getView(), rowIndex;
20729 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20732 if(e.shiftKey && this.last !== false){
20733 var last = this.last;
20734 this.selectRange(last, rowIndex, e.ctrlKey);
20735 this.last = last; // reset the last
20736 view.focusRow(rowIndex);
20738 var isSelected = this.isSelected(rowIndex);
20739 if(e.button !== 0 && isSelected){
20740 view.focusRow(rowIndex);
20741 }else if(e.ctrlKey && isSelected){
20742 this.deselectRow(rowIndex);
20743 }else if(!isSelected){
20744 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20745 view.focusRow(rowIndex);
20748 this.fireEvent("afterselectionchange", this);
20751 handleDragableRowClick : function(grid, rowIndex, e)
20753 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20754 this.selectRow(rowIndex, false);
20755 grid.view.focusRow(rowIndex);
20756 this.fireEvent("afterselectionchange", this);
20761 * Selects multiple rows.
20762 * @param {Array} rows Array of the indexes of the row to select
20763 * @param {Boolean} keepExisting (optional) True to keep existing selections
20765 selectRows : function(rows, keepExisting){
20767 this.clearSelections();
20769 for(var i = 0, len = rows.length; i < len; i++){
20770 this.selectRow(rows[i], true);
20775 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20776 * @param {Number} startRow The index of the first row in the range
20777 * @param {Number} endRow The index of the last row in the range
20778 * @param {Boolean} keepExisting (optional) True to retain existing selections
20780 selectRange : function(startRow, endRow, keepExisting){
20781 if(this.locked) return;
20783 this.clearSelections();
20785 if(startRow <= endRow){
20786 for(var i = startRow; i <= endRow; i++){
20787 this.selectRow(i, true);
20790 for(var i = startRow; i >= endRow; i--){
20791 this.selectRow(i, true);
20797 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20798 * @param {Number} startRow The index of the first row in the range
20799 * @param {Number} endRow The index of the last row in the range
20801 deselectRange : function(startRow, endRow, preventViewNotify){
20802 if(this.locked) return;
20803 for(var i = startRow; i <= endRow; i++){
20804 this.deselectRow(i, preventViewNotify);
20810 * @param {Number} row The index of the row to select
20811 * @param {Boolean} keepExisting (optional) True to keep existing selections
20813 selectRow : function(index, keepExisting, preventViewNotify){
20814 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20815 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20816 if(!keepExisting || this.singleSelect){
20817 this.clearSelections();
20819 var r = this.grid.dataSource.getAt(index);
20820 this.selections.add(r);
20821 this.last = this.lastActive = index;
20822 if(!preventViewNotify){
20823 this.grid.getView().onRowSelect(index);
20825 this.fireEvent("rowselect", this, index, r);
20826 this.fireEvent("selectionchange", this);
20832 * @param {Number} row The index of the row to deselect
20834 deselectRow : function(index, preventViewNotify){
20835 if(this.locked) return;
20836 if(this.last == index){
20839 if(this.lastActive == index){
20840 this.lastActive = false;
20842 var r = this.grid.dataSource.getAt(index);
20843 this.selections.remove(r);
20844 if(!preventViewNotify){
20845 this.grid.getView().onRowDeselect(index);
20847 this.fireEvent("rowdeselect", this, index);
20848 this.fireEvent("selectionchange", this);
20852 restoreLast : function(){
20854 this.last = this._last;
20859 acceptsNav : function(row, col, cm){
20860 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20864 onEditorKey : function(field, e){
20865 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20870 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20872 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20874 }else if(k == e.ENTER && !e.ctrlKey){
20878 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20880 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20882 }else if(k == e.ESC){
20886 g.startEditing(newCell[0], newCell[1]);
20891 * Ext JS Library 1.1.1
20892 * Copyright(c) 2006-2007, Ext JS, LLC.
20894 * Originally Released Under LGPL - original licence link has changed is not relivant.
20897 * <script type="text/javascript">
20901 * @class Roo.bootstrap.PagingToolbar
20903 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20905 * Create a new PagingToolbar
20906 * @param {Object} config The config object
20908 Roo.bootstrap.PagingToolbar = function(config)
20910 // old args format still supported... - xtype is prefered..
20911 // created from xtype...
20912 var ds = config.dataSource;
20913 this.toolbarItems = [];
20914 if (config.items) {
20915 this.toolbarItems = config.items;
20916 // config.items = [];
20919 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20926 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20930 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20932 * @cfg {Roo.data.Store} dataSource
20933 * The underlying data store providing the paged data
20936 * @cfg {String/HTMLElement/Element} container
20937 * container The id or element that will contain the toolbar
20940 * @cfg {Boolean} displayInfo
20941 * True to display the displayMsg (defaults to false)
20944 * @cfg {Number} pageSize
20945 * The number of records to display per page (defaults to 20)
20949 * @cfg {String} displayMsg
20950 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20952 displayMsg : 'Displaying {0} - {1} of {2}',
20954 * @cfg {String} emptyMsg
20955 * The message to display when no records are found (defaults to "No data to display")
20957 emptyMsg : 'No data to display',
20959 * Customizable piece of the default paging text (defaults to "Page")
20962 beforePageText : "Page",
20964 * Customizable piece of the default paging text (defaults to "of %0")
20967 afterPageText : "of {0}",
20969 * Customizable piece of the default paging text (defaults to "First Page")
20972 firstText : "First Page",
20974 * Customizable piece of the default paging text (defaults to "Previous Page")
20977 prevText : "Previous Page",
20979 * Customizable piece of the default paging text (defaults to "Next Page")
20982 nextText : "Next Page",
20984 * Customizable piece of the default paging text (defaults to "Last Page")
20987 lastText : "Last Page",
20989 * Customizable piece of the default paging text (defaults to "Refresh")
20992 refreshText : "Refresh",
20996 onRender : function(ct, position)
20998 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20999 this.navgroup.parentId = this.id;
21000 this.navgroup.onRender(this.el, null);
21001 // add the buttons to the navgroup
21003 if(this.displayInfo){
21004 Roo.log(this.el.select('ul.navbar-nav',true).first());
21005 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21006 this.displayEl = this.el.select('.x-paging-info', true).first();
21007 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21008 // this.displayEl = navel.el.select('span',true).first();
21014 Roo.each(_this.buttons, function(e){
21015 Roo.factory(e).onRender(_this.el, null);
21019 Roo.each(_this.toolbarItems, function(e) {
21020 _this.navgroup.addItem(e);
21024 this.first = this.navgroup.addItem({
21025 tooltip: this.firstText,
21027 icon : 'fa fa-backward',
21029 preventDefault: true,
21030 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21033 this.prev = this.navgroup.addItem({
21034 tooltip: this.prevText,
21036 icon : 'fa fa-step-backward',
21038 preventDefault: true,
21039 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21041 //this.addSeparator();
21044 var field = this.navgroup.addItem( {
21046 cls : 'x-paging-position',
21048 html : this.beforePageText +
21049 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21050 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21053 this.field = field.el.select('input', true).first();
21054 this.field.on("keydown", this.onPagingKeydown, this);
21055 this.field.on("focus", function(){this.dom.select();});
21058 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21059 //this.field.setHeight(18);
21060 //this.addSeparator();
21061 this.next = this.navgroup.addItem({
21062 tooltip: this.nextText,
21064 html : ' <i class="fa fa-step-forward">',
21066 preventDefault: true,
21067 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21069 this.last = this.navgroup.addItem({
21070 tooltip: this.lastText,
21071 icon : 'fa fa-forward',
21074 preventDefault: true,
21075 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21077 //this.addSeparator();
21078 this.loading = this.navgroup.addItem({
21079 tooltip: this.refreshText,
21080 icon: 'fa fa-refresh',
21081 preventDefault: true,
21082 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21088 updateInfo : function(){
21089 if(this.displayEl){
21090 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21091 var msg = count == 0 ?
21095 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21097 this.displayEl.update(msg);
21102 onLoad : function(ds, r, o){
21103 this.cursor = o.params ? o.params.start : 0;
21104 var d = this.getPageData(),
21108 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21109 this.field.dom.value = ap;
21110 this.first.setDisabled(ap == 1);
21111 this.prev.setDisabled(ap == 1);
21112 this.next.setDisabled(ap == ps);
21113 this.last.setDisabled(ap == ps);
21114 this.loading.enable();
21119 getPageData : function(){
21120 var total = this.ds.getTotalCount();
21123 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21124 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21129 onLoadError : function(){
21130 this.loading.enable();
21134 onPagingKeydown : function(e){
21135 var k = e.getKey();
21136 var d = this.getPageData();
21138 var v = this.field.dom.value, pageNum;
21139 if(!v || isNaN(pageNum = parseInt(v, 10))){
21140 this.field.dom.value = d.activePage;
21143 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21144 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21147 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))
21149 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21150 this.field.dom.value = pageNum;
21151 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21154 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21156 var v = this.field.dom.value, pageNum;
21157 var increment = (e.shiftKey) ? 10 : 1;
21158 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21160 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21161 this.field.dom.value = d.activePage;
21164 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21166 this.field.dom.value = parseInt(v, 10) + increment;
21167 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21168 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21175 beforeLoad : function(){
21177 this.loading.disable();
21182 onClick : function(which){
21191 ds.load({params:{start: 0, limit: this.pageSize}});
21194 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21197 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21200 var total = ds.getTotalCount();
21201 var extra = total % this.pageSize;
21202 var lastStart = extra ? (total - extra) : total-this.pageSize;
21203 ds.load({params:{start: lastStart, limit: this.pageSize}});
21206 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21212 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21213 * @param {Roo.data.Store} store The data store to unbind
21215 unbind : function(ds){
21216 ds.un("beforeload", this.beforeLoad, this);
21217 ds.un("load", this.onLoad, this);
21218 ds.un("loadexception", this.onLoadError, this);
21219 ds.un("remove", this.updateInfo, this);
21220 ds.un("add", this.updateInfo, this);
21221 this.ds = undefined;
21225 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21226 * @param {Roo.data.Store} store The data store to bind
21228 bind : function(ds){
21229 ds.on("beforeload", this.beforeLoad, this);
21230 ds.on("load", this.onLoad, this);
21231 ds.on("loadexception", this.onLoadError, this);
21232 ds.on("remove", this.updateInfo, this);
21233 ds.on("add", this.updateInfo, this);
21244 * @class Roo.bootstrap.MessageBar
21245 * @extends Roo.bootstrap.Component
21246 * Bootstrap MessageBar class
21247 * @cfg {String} html contents of the MessageBar
21248 * @cfg {String} weight (info | success | warning | danger) default info
21249 * @cfg {String} beforeClass insert the bar before the given class
21250 * @cfg {Boolean} closable (true | false) default false
21251 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21254 * Create a new Element
21255 * @param {Object} config The config object
21258 Roo.bootstrap.MessageBar = function(config){
21259 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21262 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21268 beforeClass: 'bootstrap-sticky-wrap',
21270 getAutoCreate : function(){
21274 cls: 'alert alert-dismissable alert-' + this.weight,
21279 html: this.html || ''
21285 cfg.cls += ' alert-messages-fixed';
21299 onRender : function(ct, position)
21301 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21304 var cfg = Roo.apply({}, this.getAutoCreate());
21308 cfg.cls += ' ' + this.cls;
21311 cfg.style = this.style;
21313 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21315 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21318 this.el.select('>button.close').on('click', this.hide, this);
21324 if (!this.rendered) {
21330 this.fireEvent('show', this);
21336 if (!this.rendered) {
21342 this.fireEvent('hide', this);
21345 update : function()
21347 // var e = this.el.dom.firstChild;
21349 // if(this.closable){
21350 // e = e.nextSibling;
21353 // e.data = this.html || '';
21355 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21371 * @class Roo.bootstrap.Graph
21372 * @extends Roo.bootstrap.Component
21373 * Bootstrap Graph class
21377 @cfg {String} graphtype bar | vbar | pie
21378 @cfg {number} g_x coodinator | centre x (pie)
21379 @cfg {number} g_y coodinator | centre y (pie)
21380 @cfg {number} g_r radius (pie)
21381 @cfg {number} g_height height of the chart (respected by all elements in the set)
21382 @cfg {number} g_width width of the chart (respected by all elements in the set)
21383 @cfg {Object} title The title of the chart
21386 -opts (object) options for the chart
21388 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21389 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21391 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.
21392 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21394 o stretch (boolean)
21396 -opts (object) options for the pie
21399 o startAngle (number)
21400 o endAngle (number)
21404 * Create a new Input
21405 * @param {Object} config The config object
21408 Roo.bootstrap.Graph = function(config){
21409 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21415 * The img click event for the img.
21416 * @param {Roo.EventObject} e
21422 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21433 //g_colors: this.colors,
21440 getAutoCreate : function(){
21451 onRender : function(ct,position){
21452 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21453 this.raphael = Raphael(this.el.dom);
21455 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21456 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21457 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21458 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21460 r.text(160, 10, "Single Series Chart").attr(txtattr);
21461 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21462 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21463 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21465 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21466 r.barchart(330, 10, 300, 220, data1);
21467 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21468 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21471 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21472 // r.barchart(30, 30, 560, 250, xdata, {
21473 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21474 // axis : "0 0 1 1",
21475 // axisxlabels : xdata
21476 // //yvalues : cols,
21479 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21481 // this.load(null,xdata,{
21482 // axis : "0 0 1 1",
21483 // axisxlabels : xdata
21488 load : function(graphtype,xdata,opts){
21489 this.raphael.clear();
21491 graphtype = this.graphtype;
21496 var r = this.raphael,
21497 fin = function () {
21498 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21500 fout = function () {
21501 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21503 pfin = function() {
21504 this.sector.stop();
21505 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21508 this.label[0].stop();
21509 this.label[0].attr({ r: 7.5 });
21510 this.label[1].attr({ "font-weight": 800 });
21513 pfout = function() {
21514 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21517 this.label[0].animate({ r: 5 }, 500, "bounce");
21518 this.label[1].attr({ "font-weight": 400 });
21524 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21527 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21530 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21531 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21533 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21540 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21545 setTitle: function(o)
21550 initEvents: function() {
21553 this.el.on('click', this.onClick, this);
21557 onClick : function(e)
21559 Roo.log('img onclick');
21560 this.fireEvent('click', this, e);
21572 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21575 * @class Roo.bootstrap.dash.NumberBox
21576 * @extends Roo.bootstrap.Component
21577 * Bootstrap NumberBox class
21578 * @cfg {String} headline Box headline
21579 * @cfg {String} content Box content
21580 * @cfg {String} icon Box icon
21581 * @cfg {String} footer Footer text
21582 * @cfg {String} fhref Footer href
21585 * Create a new NumberBox
21586 * @param {Object} config The config object
21590 Roo.bootstrap.dash.NumberBox = function(config){
21591 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21595 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21604 getAutoCreate : function(){
21608 cls : 'small-box ',
21616 cls : 'roo-headline',
21617 html : this.headline
21621 cls : 'roo-content',
21622 html : this.content
21636 cls : 'ion ' + this.icon
21645 cls : 'small-box-footer',
21646 href : this.fhref || '#',
21650 cfg.cn.push(footer);
21657 onRender : function(ct,position){
21658 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21665 setHeadline: function (value)
21667 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21670 setFooter: function (value, href)
21672 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21675 this.el.select('a.small-box-footer',true).first().attr('href', href);
21680 setContent: function (value)
21682 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21685 initEvents: function()
21699 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21702 * @class Roo.bootstrap.dash.TabBox
21703 * @extends Roo.bootstrap.Component
21704 * Bootstrap TabBox class
21705 * @cfg {String} title Title of the TabBox
21706 * @cfg {String} icon Icon of the TabBox
21707 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21708 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21711 * Create a new TabBox
21712 * @param {Object} config The config object
21716 Roo.bootstrap.dash.TabBox = function(config){
21717 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21722 * When a pane is added
21723 * @param {Roo.bootstrap.dash.TabPane} pane
21727 * @event activatepane
21728 * When a pane is activated
21729 * @param {Roo.bootstrap.dash.TabPane} pane
21731 "activatepane" : true
21739 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21744 tabScrollable : false,
21746 getChildContainer : function()
21748 return this.el.select('.tab-content', true).first();
21751 getAutoCreate : function(){
21755 cls: 'pull-left header',
21763 cls: 'fa ' + this.icon
21769 cls: 'nav nav-tabs pull-right',
21775 if(this.tabScrollable){
21782 cls: 'nav nav-tabs pull-right',
21793 cls: 'nav-tabs-custom',
21798 cls: 'tab-content no-padding',
21806 initEvents : function()
21808 //Roo.log('add add pane handler');
21809 this.on('addpane', this.onAddPane, this);
21812 * Updates the box title
21813 * @param {String} html to set the title to.
21815 setTitle : function(value)
21817 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21819 onAddPane : function(pane)
21821 this.panes.push(pane);
21822 //Roo.log('addpane');
21824 // tabs are rendere left to right..
21825 if(!this.showtabs){
21829 var ctr = this.el.select('.nav-tabs', true).first();
21832 var existing = ctr.select('.nav-tab',true);
21833 var qty = existing.getCount();;
21836 var tab = ctr.createChild({
21838 cls : 'nav-tab' + (qty ? '' : ' active'),
21846 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21849 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21851 pane.el.addClass('active');
21856 onTabClick : function(ev,un,ob,pane)
21858 //Roo.log('tab - prev default');
21859 ev.preventDefault();
21862 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21863 pane.tab.addClass('active');
21864 //Roo.log(pane.title);
21865 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21866 // technically we should have a deactivate event.. but maybe add later.
21867 // and it should not de-activate the selected tab...
21868 this.fireEvent('activatepane', pane);
21869 pane.el.addClass('active');
21870 pane.fireEvent('activate');
21875 getActivePane : function()
21878 Roo.each(this.panes, function(p) {
21879 if(p.el.hasClass('active')){
21900 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21902 * @class Roo.bootstrap.TabPane
21903 * @extends Roo.bootstrap.Component
21904 * Bootstrap TabPane class
21905 * @cfg {Boolean} active (false | true) Default false
21906 * @cfg {String} title title of panel
21910 * Create a new TabPane
21911 * @param {Object} config The config object
21914 Roo.bootstrap.dash.TabPane = function(config){
21915 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21921 * When a pane is activated
21922 * @param {Roo.bootstrap.dash.TabPane} pane
21929 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21934 // the tabBox that this is attached to.
21937 getAutoCreate : function()
21945 cfg.cls += ' active';
21950 initEvents : function()
21952 //Roo.log('trigger add pane handler');
21953 this.parent().fireEvent('addpane', this)
21957 * Updates the tab title
21958 * @param {String} html to set the title to.
21960 setTitle: function(str)
21966 this.tab.select('a', true).first().dom.innerHTML = str;
21983 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21986 * @class Roo.bootstrap.menu.Menu
21987 * @extends Roo.bootstrap.Component
21988 * Bootstrap Menu class - container for Menu
21989 * @cfg {String} html Text of the menu
21990 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21991 * @cfg {String} icon Font awesome icon
21992 * @cfg {String} pos Menu align to (top | bottom) default bottom
21996 * Create a new Menu
21997 * @param {Object} config The config object
22001 Roo.bootstrap.menu.Menu = function(config){
22002 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22006 * @event beforeshow
22007 * Fires before this menu is displayed
22008 * @param {Roo.bootstrap.menu.Menu} this
22012 * @event beforehide
22013 * Fires before this menu is hidden
22014 * @param {Roo.bootstrap.menu.Menu} this
22019 * Fires after this menu is displayed
22020 * @param {Roo.bootstrap.menu.Menu} this
22025 * Fires after this menu is hidden
22026 * @param {Roo.bootstrap.menu.Menu} this
22031 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22032 * @param {Roo.bootstrap.menu.Menu} this
22033 * @param {Roo.EventObject} e
22040 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22044 weight : 'default',
22049 getChildContainer : function() {
22050 if(this.isSubMenu){
22054 return this.el.select('ul.dropdown-menu', true).first();
22057 getAutoCreate : function()
22062 cls : 'roo-menu-text',
22070 cls : 'fa ' + this.icon
22081 cls : 'dropdown-button btn btn-' + this.weight,
22086 cls : 'dropdown-toggle btn btn-' + this.weight,
22096 cls : 'dropdown-menu'
22102 if(this.pos == 'top'){
22103 cfg.cls += ' dropup';
22106 if(this.isSubMenu){
22109 cls : 'dropdown-menu'
22116 onRender : function(ct, position)
22118 this.isSubMenu = ct.hasClass('dropdown-submenu');
22120 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22123 initEvents : function()
22125 if(this.isSubMenu){
22129 this.hidden = true;
22131 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22132 this.triggerEl.on('click', this.onTriggerPress, this);
22134 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22135 this.buttonEl.on('click', this.onClick, this);
22141 if(this.isSubMenu){
22145 return this.el.select('ul.dropdown-menu', true).first();
22148 onClick : function(e)
22150 this.fireEvent("click", this, e);
22153 onTriggerPress : function(e)
22155 if (this.isVisible()) {
22162 isVisible : function(){
22163 return !this.hidden;
22168 this.fireEvent("beforeshow", this);
22170 this.hidden = false;
22171 this.el.addClass('open');
22173 Roo.get(document).on("mouseup", this.onMouseUp, this);
22175 this.fireEvent("show", this);
22182 this.fireEvent("beforehide", this);
22184 this.hidden = true;
22185 this.el.removeClass('open');
22187 Roo.get(document).un("mouseup", this.onMouseUp);
22189 this.fireEvent("hide", this);
22192 onMouseUp : function()
22206 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22209 * @class Roo.bootstrap.menu.Item
22210 * @extends Roo.bootstrap.Component
22211 * Bootstrap MenuItem class
22212 * @cfg {Boolean} submenu (true | false) default false
22213 * @cfg {String} html text of the item
22214 * @cfg {String} href the link
22215 * @cfg {Boolean} disable (true | false) default false
22216 * @cfg {Boolean} preventDefault (true | false) default true
22217 * @cfg {String} icon Font awesome icon
22218 * @cfg {String} pos Submenu align to (left | right) default right
22222 * Create a new Item
22223 * @param {Object} config The config object
22227 Roo.bootstrap.menu.Item = function(config){
22228 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22232 * Fires when the mouse is hovering over this menu
22233 * @param {Roo.bootstrap.menu.Item} this
22234 * @param {Roo.EventObject} e
22239 * Fires when the mouse exits this menu
22240 * @param {Roo.bootstrap.menu.Item} this
22241 * @param {Roo.EventObject} e
22247 * The raw click event for the entire grid.
22248 * @param {Roo.EventObject} e
22254 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22259 preventDefault: true,
22264 getAutoCreate : function()
22269 cls : 'roo-menu-item-text',
22277 cls : 'fa ' + this.icon
22286 href : this.href || '#',
22293 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22297 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22299 if(this.pos == 'left'){
22300 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22307 initEvents : function()
22309 this.el.on('mouseover', this.onMouseOver, this);
22310 this.el.on('mouseout', this.onMouseOut, this);
22312 this.el.select('a', true).first().on('click', this.onClick, this);
22316 onClick : function(e)
22318 if(this.preventDefault){
22319 e.preventDefault();
22322 this.fireEvent("click", this, e);
22325 onMouseOver : function(e)
22327 if(this.submenu && this.pos == 'left'){
22328 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22331 this.fireEvent("mouseover", this, e);
22334 onMouseOut : function(e)
22336 this.fireEvent("mouseout", this, e);
22348 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22351 * @class Roo.bootstrap.menu.Separator
22352 * @extends Roo.bootstrap.Component
22353 * Bootstrap Separator class
22356 * Create a new Separator
22357 * @param {Object} config The config object
22361 Roo.bootstrap.menu.Separator = function(config){
22362 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22365 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22367 getAutoCreate : function(){
22388 * @class Roo.bootstrap.Tooltip
22389 * Bootstrap Tooltip class
22390 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22391 * to determine which dom element triggers the tooltip.
22393 * It needs to add support for additional attributes like tooltip-position
22396 * Create a new Toolti
22397 * @param {Object} config The config object
22400 Roo.bootstrap.Tooltip = function(config){
22401 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22404 Roo.apply(Roo.bootstrap.Tooltip, {
22406 * @function init initialize tooltip monitoring.
22410 currentTip : false,
22411 currentRegion : false,
22417 Roo.get(document).on('mouseover', this.enter ,this);
22418 Roo.get(document).on('mouseout', this.leave, this);
22421 this.currentTip = new Roo.bootstrap.Tooltip();
22424 enter : function(ev)
22426 var dom = ev.getTarget();
22428 //Roo.log(['enter',dom]);
22429 var el = Roo.fly(dom);
22430 if (this.currentEl) {
22432 //Roo.log(this.currentEl);
22433 //Roo.log(this.currentEl.contains(dom));
22434 if (this.currentEl == el) {
22437 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22445 if (this.currentTip.el) {
22446 this.currentTip.el.hide(); // force hiding...
22451 // you can not look for children, as if el is the body.. then everythign is the child..
22452 if (!el.attr('tooltip')) { //
22453 if (!el.select("[tooltip]").elements.length) {
22456 // is the mouse over this child...?
22457 bindEl = el.select("[tooltip]").first();
22458 var xy = ev.getXY();
22459 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22460 //Roo.log("not in region.");
22463 //Roo.log("child element over..");
22466 this.currentEl = bindEl;
22467 this.currentTip.bind(bindEl);
22468 this.currentRegion = Roo.lib.Region.getRegion(dom);
22469 this.currentTip.enter();
22472 leave : function(ev)
22474 var dom = ev.getTarget();
22475 //Roo.log(['leave',dom]);
22476 if (!this.currentEl) {
22481 if (dom != this.currentEl.dom) {
22484 var xy = ev.getXY();
22485 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22488 // only activate leave if mouse cursor is outside... bounding box..
22493 if (this.currentTip) {
22494 this.currentTip.leave();
22496 //Roo.log('clear currentEl');
22497 this.currentEl = false;
22502 'left' : ['r-l', [-2,0], 'right'],
22503 'right' : ['l-r', [2,0], 'left'],
22504 'bottom' : ['t-b', [0,2], 'top'],
22505 'top' : [ 'b-t', [0,-2], 'bottom']
22511 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22516 delay : null, // can be { show : 300 , hide: 500}
22520 hoverState : null, //???
22522 placement : 'bottom',
22524 getAutoCreate : function(){
22531 cls : 'tooltip-arrow'
22534 cls : 'tooltip-inner'
22541 bind : function(el)
22547 enter : function () {
22549 if (this.timeout != null) {
22550 clearTimeout(this.timeout);
22553 this.hoverState = 'in';
22554 //Roo.log("enter - show");
22555 if (!this.delay || !this.delay.show) {
22560 this.timeout = setTimeout(function () {
22561 if (_t.hoverState == 'in') {
22564 }, this.delay.show);
22568 clearTimeout(this.timeout);
22570 this.hoverState = 'out';
22571 if (!this.delay || !this.delay.hide) {
22577 this.timeout = setTimeout(function () {
22578 //Roo.log("leave - timeout");
22580 if (_t.hoverState == 'out') {
22582 Roo.bootstrap.Tooltip.currentEl = false;
22590 this.render(document.body);
22593 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22595 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22597 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22599 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22601 var placement = typeof this.placement == 'function' ?
22602 this.placement.call(this, this.el, on_el) :
22605 var autoToken = /\s?auto?\s?/i;
22606 var autoPlace = autoToken.test(placement);
22608 placement = placement.replace(autoToken, '') || 'top';
22612 //this.el.setXY([0,0]);
22614 //this.el.dom.style.display='block';
22615 this.el.addClass(placement);
22617 //this.el.appendTo(on_el);
22619 var p = this.getPosition();
22620 var box = this.el.getBox();
22625 var align = Roo.bootstrap.Tooltip.alignment[placement];
22626 this.el.alignTo(this.bindEl, align[0],align[1]);
22627 //var arrow = this.el.select('.arrow',true).first();
22628 //arrow.set(align[2],
22630 this.el.addClass('in fade');
22631 this.hoverState = null;
22633 if (this.el.hasClass('fade')) {
22644 //this.el.setXY([0,0]);
22645 this.el.removeClass('in');
22661 * @class Roo.bootstrap.LocationPicker
22662 * @extends Roo.bootstrap.Component
22663 * Bootstrap LocationPicker class
22664 * @cfg {Number} latitude Position when init default 0
22665 * @cfg {Number} longitude Position when init default 0
22666 * @cfg {Number} zoom default 15
22667 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22668 * @cfg {Boolean} mapTypeControl default false
22669 * @cfg {Boolean} disableDoubleClickZoom default false
22670 * @cfg {Boolean} scrollwheel default true
22671 * @cfg {Boolean} streetViewControl default false
22672 * @cfg {Number} radius default 0
22673 * @cfg {String} locationName
22674 * @cfg {Boolean} draggable default true
22675 * @cfg {Boolean} enableAutocomplete default false
22676 * @cfg {Boolean} enableReverseGeocode default true
22677 * @cfg {String} markerTitle
22680 * Create a new LocationPicker
22681 * @param {Object} config The config object
22685 Roo.bootstrap.LocationPicker = function(config){
22687 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22692 * Fires when the picker initialized.
22693 * @param {Roo.bootstrap.LocationPicker} this
22694 * @param {Google Location} location
22698 * @event positionchanged
22699 * Fires when the picker position changed.
22700 * @param {Roo.bootstrap.LocationPicker} this
22701 * @param {Google Location} location
22703 positionchanged : true,
22706 * Fires when the map resize.
22707 * @param {Roo.bootstrap.LocationPicker} this
22712 * Fires when the map show.
22713 * @param {Roo.bootstrap.LocationPicker} this
22718 * Fires when the map hide.
22719 * @param {Roo.bootstrap.LocationPicker} this
22724 * Fires when click the map.
22725 * @param {Roo.bootstrap.LocationPicker} this
22726 * @param {Map event} e
22730 * @event mapRightClick
22731 * Fires when right click the map.
22732 * @param {Roo.bootstrap.LocationPicker} this
22733 * @param {Map event} e
22735 mapRightClick : true,
22737 * @event markerClick
22738 * Fires when click the marker.
22739 * @param {Roo.bootstrap.LocationPicker} this
22740 * @param {Map event} e
22742 markerClick : true,
22744 * @event markerRightClick
22745 * Fires when right click the marker.
22746 * @param {Roo.bootstrap.LocationPicker} this
22747 * @param {Map event} e
22749 markerRightClick : true,
22751 * @event OverlayViewDraw
22752 * Fires when OverlayView Draw
22753 * @param {Roo.bootstrap.LocationPicker} this
22755 OverlayViewDraw : true,
22757 * @event OverlayViewOnAdd
22758 * Fires when OverlayView Draw
22759 * @param {Roo.bootstrap.LocationPicker} this
22761 OverlayViewOnAdd : true,
22763 * @event OverlayViewOnRemove
22764 * Fires when OverlayView Draw
22765 * @param {Roo.bootstrap.LocationPicker} this
22767 OverlayViewOnRemove : true,
22769 * @event OverlayViewShow
22770 * Fires when OverlayView Draw
22771 * @param {Roo.bootstrap.LocationPicker} this
22772 * @param {Pixel} cpx
22774 OverlayViewShow : true,
22776 * @event OverlayViewHide
22777 * Fires when OverlayView Draw
22778 * @param {Roo.bootstrap.LocationPicker} this
22780 OverlayViewHide : true
22785 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22787 gMapContext: false,
22793 mapTypeControl: false,
22794 disableDoubleClickZoom: false,
22796 streetViewControl: false,
22800 enableAutocomplete: false,
22801 enableReverseGeocode: true,
22804 getAutoCreate: function()
22809 cls: 'roo-location-picker'
22815 initEvents: function(ct, position)
22817 if(!this.el.getWidth() || this.isApplied()){
22821 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22826 initial: function()
22828 if(!this.mapTypeId){
22829 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22832 this.gMapContext = this.GMapContext();
22834 this.initOverlayView();
22836 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22840 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22841 _this.setPosition(_this.gMapContext.marker.position);
22844 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22845 _this.fireEvent('mapClick', this, event);
22849 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22850 _this.fireEvent('mapRightClick', this, event);
22854 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22855 _this.fireEvent('markerClick', this, event);
22859 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22860 _this.fireEvent('markerRightClick', this, event);
22864 this.setPosition(this.gMapContext.location);
22866 this.fireEvent('initial', this, this.gMapContext.location);
22869 initOverlayView: function()
22873 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22877 _this.fireEvent('OverlayViewDraw', _this);
22882 _this.fireEvent('OverlayViewOnAdd', _this);
22885 onRemove: function()
22887 _this.fireEvent('OverlayViewOnRemove', _this);
22890 show: function(cpx)
22892 _this.fireEvent('OverlayViewShow', _this, cpx);
22897 _this.fireEvent('OverlayViewHide', _this);
22903 fromLatLngToContainerPixel: function(event)
22905 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22908 isApplied: function()
22910 return this.getGmapContext() == false ? false : true;
22913 getGmapContext: function()
22915 return this.gMapContext
22918 GMapContext: function()
22920 var position = new google.maps.LatLng(this.latitude, this.longitude);
22922 var _map = new google.maps.Map(this.el.dom, {
22925 mapTypeId: this.mapTypeId,
22926 mapTypeControl: this.mapTypeControl,
22927 disableDoubleClickZoom: this.disableDoubleClickZoom,
22928 scrollwheel: this.scrollwheel,
22929 streetViewControl: this.streetViewControl,
22930 locationName: this.locationName,
22931 draggable: this.draggable,
22932 enableAutocomplete: this.enableAutocomplete,
22933 enableReverseGeocode: this.enableReverseGeocode
22936 var _marker = new google.maps.Marker({
22937 position: position,
22939 title: this.markerTitle,
22940 draggable: this.draggable
22947 location: position,
22948 radius: this.radius,
22949 locationName: this.locationName,
22950 addressComponents: {
22951 formatted_address: null,
22952 addressLine1: null,
22953 addressLine2: null,
22955 streetNumber: null,
22959 stateOrProvince: null
22962 domContainer: this.el.dom,
22963 geodecoder: new google.maps.Geocoder()
22967 drawCircle: function(center, radius, options)
22969 if (this.gMapContext.circle != null) {
22970 this.gMapContext.circle.setMap(null);
22974 options = Roo.apply({}, options, {
22975 strokeColor: "#0000FF",
22976 strokeOpacity: .35,
22978 fillColor: "#0000FF",
22982 options.map = this.gMapContext.map;
22983 options.radius = radius;
22984 options.center = center;
22985 this.gMapContext.circle = new google.maps.Circle(options);
22986 return this.gMapContext.circle;
22992 setPosition: function(location)
22994 this.gMapContext.location = location;
22995 this.gMapContext.marker.setPosition(location);
22996 this.gMapContext.map.panTo(location);
22997 this.drawCircle(location, this.gMapContext.radius, {});
23001 if (this.gMapContext.settings.enableReverseGeocode) {
23002 this.gMapContext.geodecoder.geocode({
23003 latLng: this.gMapContext.location
23004 }, function(results, status) {
23006 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23007 _this.gMapContext.locationName = results[0].formatted_address;
23008 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23010 _this.fireEvent('positionchanged', this, location);
23017 this.fireEvent('positionchanged', this, location);
23022 google.maps.event.trigger(this.gMapContext.map, "resize");
23024 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23026 this.fireEvent('resize', this);
23029 setPositionByLatLng: function(latitude, longitude)
23031 this.setPosition(new google.maps.LatLng(latitude, longitude));
23034 getCurrentPosition: function()
23037 latitude: this.gMapContext.location.lat(),
23038 longitude: this.gMapContext.location.lng()
23042 getAddressName: function()
23044 return this.gMapContext.locationName;
23047 getAddressComponents: function()
23049 return this.gMapContext.addressComponents;
23052 address_component_from_google_geocode: function(address_components)
23056 for (var i = 0; i < address_components.length; i++) {
23057 var component = address_components[i];
23058 if (component.types.indexOf("postal_code") >= 0) {
23059 result.postalCode = component.short_name;
23060 } else if (component.types.indexOf("street_number") >= 0) {
23061 result.streetNumber = component.short_name;
23062 } else if (component.types.indexOf("route") >= 0) {
23063 result.streetName = component.short_name;
23064 } else if (component.types.indexOf("neighborhood") >= 0) {
23065 result.city = component.short_name;
23066 } else if (component.types.indexOf("locality") >= 0) {
23067 result.city = component.short_name;
23068 } else if (component.types.indexOf("sublocality") >= 0) {
23069 result.district = component.short_name;
23070 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23071 result.stateOrProvince = component.short_name;
23072 } else if (component.types.indexOf("country") >= 0) {
23073 result.country = component.short_name;
23077 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23078 result.addressLine2 = "";
23082 setZoomLevel: function(zoom)
23084 this.gMapContext.map.setZoom(zoom);
23097 this.fireEvent('show', this);
23108 this.fireEvent('hide', this);
23113 Roo.apply(Roo.bootstrap.LocationPicker, {
23115 OverlayView : function(map, options)
23117 options = options || {};
23131 * @class Roo.bootstrap.Alert
23132 * @extends Roo.bootstrap.Component
23133 * Bootstrap Alert class
23134 * @cfg {String} title The title of alert
23135 * @cfg {String} html The content of alert
23136 * @cfg {String} weight ( success | info | warning | danger )
23137 * @cfg {String} faicon font-awesomeicon
23140 * Create a new alert
23141 * @param {Object} config The config object
23145 Roo.bootstrap.Alert = function(config){
23146 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23150 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23157 getAutoCreate : function()
23166 cls : 'roo-alert-icon'
23171 cls : 'roo-alert-title',
23176 cls : 'roo-alert-text',
23183 cfg.cn[0].cls += ' fa ' + this.faicon;
23187 cfg.cls += ' alert-' + this.weight;
23193 initEvents: function()
23195 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23198 setTitle : function(str)
23200 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23203 setText : function(str)
23205 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23208 setWeight : function(weight)
23211 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23214 this.weight = weight;
23216 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23219 setIcon : function(icon)
23222 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23227 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);