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.
1329 * @cfg {String} xsUrl xs image source
1330 * @cfg {String} smUrl sm image source
1331 * @cfg {String} mdUrl md image source
1332 * @cfg {String} lgUrl lg image source
1335 * Create a new Input
1336 * @param {Object} config The config object
1339 Roo.bootstrap.Img = function(config){
1340 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1346 * The img click event for the img.
1347 * @param {Roo.EventObject} e
1353 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1355 imgResponsive: true,
1365 getAutoCreate : function()
1367 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1368 return this.createSingleImg();
1373 cls: 'roo-image-responsive-group',
1378 Roo.each(['xsUrl', 'smUrl', 'mdUrl', 'lgUrl'], function(size){
1385 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1386 html: _this.html || cfg.html,
1390 img.cls += ' roo-image-responsive-' + size;
1392 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1393 cfg.cls += ' img-' + _this.border;
1397 cfg.alt = _this.alt;
1410 a.target = _this.target;
1414 cfg.cn.push((_this.href) ? a : img);
1421 createSingleImg : function()
1425 cls: (this.imgResponsive) ? 'img-responsive' : '',
1429 cfg.html = this.html || cfg.html;
1431 cfg.src = this.src || cfg.src;
1433 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1434 cfg.cls += ' img-' + this.border;
1451 a.target = this.target;
1456 return (this.href) ? a : cfg;
1459 initEvents: function() {
1462 this.el.on('click', this.onClick, this);
1466 onClick : function(e)
1468 Roo.log('img onclick');
1469 this.fireEvent('click', this, e);
1483 * @class Roo.bootstrap.Link
1484 * @extends Roo.bootstrap.Component
1485 * Bootstrap Link Class
1486 * @cfg {String} alt image alternative text
1487 * @cfg {String} href a tag href
1488 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1489 * @cfg {String} html the content of the link.
1490 * @cfg {String} anchor name for the anchor link
1492 * @cfg {Boolean} preventDefault (true | false) default false
1496 * Create a new Input
1497 * @param {Object} config The config object
1500 Roo.bootstrap.Link = function(config){
1501 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1507 * The img click event for the img.
1508 * @param {Roo.EventObject} e
1514 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1518 preventDefault: false,
1522 getAutoCreate : function()
1528 // anchor's do not require html/href...
1529 if (this.anchor === false) {
1530 cfg.html = this.html || '';
1531 cfg.href = this.href || '#';
1533 cfg.name = this.anchor;
1534 if (this.html !== false) {
1535 cfg.html = this.html;
1537 if (this.href !== false) {
1538 cfg.href = this.href;
1542 if(this.alt !== false){
1547 if(this.target !== false) {
1548 cfg.target = this.target;
1554 initEvents: function() {
1556 if(!this.href || this.preventDefault){
1557 this.el.on('click', this.onClick, this);
1561 onClick : function(e)
1563 if(this.preventDefault){
1566 //Roo.log('img onclick');
1567 this.fireEvent('click', this, e);
1580 * @class Roo.bootstrap.Header
1581 * @extends Roo.bootstrap.Component
1582 * Bootstrap Header class
1583 * @cfg {String} html content of header
1584 * @cfg {Number} level (1|2|3|4|5|6) default 1
1587 * Create a new Header
1588 * @param {Object} config The config object
1592 Roo.bootstrap.Header = function(config){
1593 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1596 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1604 getAutoCreate : function(){
1609 tag: 'h' + (1 *this.level),
1610 html: this.html || ''
1622 * Ext JS Library 1.1.1
1623 * Copyright(c) 2006-2007, Ext JS, LLC.
1625 * Originally Released Under LGPL - original licence link has changed is not relivant.
1628 * <script type="text/javascript">
1632 * @class Roo.bootstrap.MenuMgr
1633 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1636 Roo.bootstrap.MenuMgr = function(){
1637 var menus, active, groups = {}, attached = false, lastShow = new Date();
1639 // private - called when first menu is created
1642 active = new Roo.util.MixedCollection();
1643 Roo.get(document).addKeyListener(27, function(){
1644 if(active.length > 0){
1652 if(active && active.length > 0){
1653 var c = active.clone();
1663 if(active.length < 1){
1664 Roo.get(document).un("mouseup", onMouseDown);
1672 var last = active.last();
1673 lastShow = new Date();
1676 Roo.get(document).on("mouseup", onMouseDown);
1681 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1682 m.parentMenu.activeChild = m;
1683 }else if(last && last.isVisible()){
1684 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1689 function onBeforeHide(m){
1691 m.activeChild.hide();
1693 if(m.autoHideTimer){
1694 clearTimeout(m.autoHideTimer);
1695 delete m.autoHideTimer;
1700 function onBeforeShow(m){
1701 var pm = m.parentMenu;
1702 if(!pm && !m.allowOtherMenus){
1704 }else if(pm && pm.activeChild && active != m){
1705 pm.activeChild.hide();
1709 // private this should really trigger on mouseup..
1710 function onMouseDown(e){
1711 Roo.log("on Mouse Up");
1712 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1722 function onBeforeCheck(mi, state){
1724 var g = groups[mi.group];
1725 for(var i = 0, l = g.length; i < l; i++){
1727 g[i].setChecked(false);
1736 * Hides all menus that are currently visible
1738 hideAll : function(){
1743 register : function(menu){
1747 menus[menu.id] = menu;
1748 menu.on("beforehide", onBeforeHide);
1749 menu.on("hide", onHide);
1750 menu.on("beforeshow", onBeforeShow);
1751 menu.on("show", onShow);
1753 if(g && menu.events["checkchange"]){
1757 groups[g].push(menu);
1758 menu.on("checkchange", onCheck);
1763 * Returns a {@link Roo.menu.Menu} object
1764 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1765 * be used to generate and return a new Menu instance.
1767 get : function(menu){
1768 if(typeof menu == "string"){ // menu id
1770 }else if(menu.events){ // menu instance
1773 /*else if(typeof menu.length == 'number'){ // array of menu items?
1774 return new Roo.bootstrap.Menu({items:menu});
1775 }else{ // otherwise, must be a config
1776 return new Roo.bootstrap.Menu(menu);
1783 unregister : function(menu){
1784 delete menus[menu.id];
1785 menu.un("beforehide", onBeforeHide);
1786 menu.un("hide", onHide);
1787 menu.un("beforeshow", onBeforeShow);
1788 menu.un("show", onShow);
1790 if(g && menu.events["checkchange"]){
1791 groups[g].remove(menu);
1792 menu.un("checkchange", onCheck);
1797 registerCheckable : function(menuItem){
1798 var g = menuItem.group;
1803 groups[g].push(menuItem);
1804 menuItem.on("beforecheckchange", onBeforeCheck);
1809 unregisterCheckable : function(menuItem){
1810 var g = menuItem.group;
1812 groups[g].remove(menuItem);
1813 menuItem.un("beforecheckchange", onBeforeCheck);
1825 * @class Roo.bootstrap.Menu
1826 * @extends Roo.bootstrap.Component
1827 * Bootstrap Menu class - container for MenuItems
1828 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1832 * @param {Object} config The config object
1836 Roo.bootstrap.Menu = function(config){
1837 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1838 if (this.registerMenu) {
1839 Roo.bootstrap.MenuMgr.register(this);
1844 * Fires before this menu is displayed
1845 * @param {Roo.menu.Menu} this
1850 * Fires before this menu is hidden
1851 * @param {Roo.menu.Menu} this
1856 * Fires after this menu is displayed
1857 * @param {Roo.menu.Menu} this
1862 * Fires after this menu is hidden
1863 * @param {Roo.menu.Menu} this
1868 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1869 * @param {Roo.menu.Menu} this
1870 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1871 * @param {Roo.EventObject} e
1876 * Fires when the mouse is hovering over this menu
1877 * @param {Roo.menu.Menu} this
1878 * @param {Roo.EventObject} e
1879 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1884 * Fires when the mouse exits this menu
1885 * @param {Roo.menu.Menu} this
1886 * @param {Roo.EventObject} e
1887 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1892 * Fires when a menu item contained in this menu is clicked
1893 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1894 * @param {Roo.EventObject} e
1898 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1901 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1905 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1908 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1910 registerMenu : true,
1912 menuItems :false, // stores the menu items..
1918 getChildContainer : function() {
1922 getAutoCreate : function(){
1924 //if (['right'].indexOf(this.align)!==-1) {
1925 // cfg.cn[1].cls += ' pull-right'
1931 cls : 'dropdown-menu' ,
1932 style : 'z-index:1000'
1936 if (this.type === 'submenu') {
1937 cfg.cls = 'submenu active';
1939 if (this.type === 'treeview') {
1940 cfg.cls = 'treeview-menu';
1945 initEvents : function() {
1947 // Roo.log("ADD event");
1948 // Roo.log(this.triggerEl.dom);
1949 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1951 this.triggerEl.addClass('dropdown-toggle');
1952 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1954 this.el.on("mouseover", this.onMouseOver, this);
1955 this.el.on("mouseout", this.onMouseOut, this);
1959 findTargetItem : function(e){
1960 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1964 //Roo.log(t); Roo.log(t.id);
1966 //Roo.log(this.menuitems);
1967 return this.menuitems.get(t.id);
1969 //return this.items.get(t.menuItemId);
1974 onClick : function(e){
1975 Roo.log("menu.onClick");
1976 var t = this.findTargetItem(e);
1977 if(!t || t.isContainer){
1982 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1983 if(t == this.activeItem && t.shouldDeactivate(e)){
1984 this.activeItem.deactivate();
1985 delete this.activeItem;
1989 this.setActiveItem(t, true);
1997 Roo.log('pass click event');
2001 this.fireEvent("click", this, t, e);
2005 onMouseOver : function(e){
2006 var t = this.findTargetItem(e);
2009 // if(t.canActivate && !t.disabled){
2010 // this.setActiveItem(t, true);
2014 this.fireEvent("mouseover", this, e, t);
2016 isVisible : function(){
2017 return !this.hidden;
2019 onMouseOut : function(e){
2020 var t = this.findTargetItem(e);
2023 // if(t == this.activeItem && t.shouldDeactivate(e)){
2024 // this.activeItem.deactivate();
2025 // delete this.activeItem;
2028 this.fireEvent("mouseout", this, e, t);
2033 * Displays this menu relative to another element
2034 * @param {String/HTMLElement/Roo.Element} element The element to align to
2035 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2036 * the element (defaults to this.defaultAlign)
2037 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2039 show : function(el, pos, parentMenu){
2040 this.parentMenu = parentMenu;
2044 this.fireEvent("beforeshow", this);
2045 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2048 * Displays this menu at a specific xy position
2049 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2050 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2052 showAt : function(xy, parentMenu, /* private: */_e){
2053 this.parentMenu = parentMenu;
2058 this.fireEvent("beforeshow", this);
2059 //xy = this.el.adjustForConstraints(xy);
2063 this.hideMenuItems();
2064 this.hidden = false;
2065 this.triggerEl.addClass('open');
2067 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2068 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2073 this.fireEvent("show", this);
2079 this.doFocus.defer(50, this);
2083 doFocus : function(){
2085 this.focusEl.focus();
2090 * Hides this menu and optionally all parent menus
2091 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2093 hide : function(deep){
2095 this.hideMenuItems();
2096 if(this.el && this.isVisible()){
2097 this.fireEvent("beforehide", this);
2098 if(this.activeItem){
2099 this.activeItem.deactivate();
2100 this.activeItem = null;
2102 this.triggerEl.removeClass('open');;
2104 this.fireEvent("hide", this);
2106 if(deep === true && this.parentMenu){
2107 this.parentMenu.hide(true);
2111 onTriggerPress : function(e)
2114 Roo.log('trigger press');
2115 //Roo.log(e.getTarget());
2116 // Roo.log(this.triggerEl.dom);
2117 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2121 if (this.isVisible()) {
2126 this.show(this.triggerEl, false, false);
2135 hideMenuItems : function()
2137 //$(backdrop).remove()
2138 Roo.select('.open',true).each(function(aa) {
2140 aa.removeClass('open');
2141 //var parent = getParent($(this))
2142 //var relatedTarget = { relatedTarget: this }
2144 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2145 //if (e.isDefaultPrevented()) return
2146 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2149 addxtypeChild : function (tree, cntr) {
2150 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2152 this.menuitems.add(comp);
2173 * @class Roo.bootstrap.MenuItem
2174 * @extends Roo.bootstrap.Component
2175 * Bootstrap MenuItem class
2176 * @cfg {String} html the menu label
2177 * @cfg {String} href the link
2178 * @cfg {Boolean} preventDefault (true | false) default true
2179 * @cfg {Boolean} isContainer (true | false) default false
2183 * Create a new MenuItem
2184 * @param {Object} config The config object
2188 Roo.bootstrap.MenuItem = function(config){
2189 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2194 * The raw click event for the entire grid.
2195 * @param {Roo.bootstrap.MenuItem} this
2196 * @param {Roo.EventObject} e
2202 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2206 preventDefault: true,
2207 isContainer : false,
2209 getAutoCreate : function(){
2211 if(this.isContainer){
2214 cls: 'dropdown-menu-item'
2220 cls: 'dropdown-menu-item',
2229 if (this.parent().type == 'treeview') {
2230 cfg.cls = 'treeview-menu';
2233 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2234 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2238 initEvents: function() {
2240 //this.el.select('a').on('click', this.onClick, this);
2243 onClick : function(e)
2245 Roo.log('item on click ');
2246 //if(this.preventDefault){
2247 // e.preventDefault();
2249 //this.parent().hideMenuItems();
2251 this.fireEvent('click', this, e);
2270 * @class Roo.bootstrap.MenuSeparator
2271 * @extends Roo.bootstrap.Component
2272 * Bootstrap MenuSeparator class
2275 * Create a new MenuItem
2276 * @param {Object} config The config object
2280 Roo.bootstrap.MenuSeparator = function(config){
2281 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2284 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2286 getAutoCreate : function(){
2305 * @class Roo.bootstrap.Modal
2306 * @extends Roo.bootstrap.Component
2307 * Bootstrap Modal class
2308 * @cfg {String} title Title of dialog
2309 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2310 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2311 * @cfg {Boolean} specificTitle default false
2312 * @cfg {Array} buttons Array of buttons or standard button set..
2313 * @cfg {String} buttonPosition (left|right|center) default right
2314 * @cfg {Boolean} animate default true
2315 * @cfg {Boolean} allow_close default true
2318 * Create a new Modal Dialog
2319 * @param {Object} config The config object
2322 Roo.bootstrap.Modal = function(config){
2323 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2328 * The raw btnclick event for the button
2329 * @param {Roo.EventObject} e
2333 this.buttons = this.buttons || [];
2336 this.tmpl = Roo.factory(this.tmpl);
2341 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2343 title : 'test dialog',
2353 specificTitle: false,
2355 buttonPosition: 'right',
2369 onRender : function(ct, position)
2371 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2374 var cfg = Roo.apply({}, this.getAutoCreate());
2377 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2379 //if (!cfg.name.length) {
2383 cfg.cls += ' ' + this.cls;
2386 cfg.style = this.style;
2388 this.el = Roo.get(document.body).createChild(cfg, position);
2390 //var type = this.el.dom.type;
2395 if(this.tabIndex !== undefined){
2396 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2400 this.bodyEl = this.el.select('.modal-body',true).first();
2401 this.closeEl = this.el.select('.modal-header .close', true).first();
2402 this.footerEl = this.el.select('.modal-footer',true).first();
2403 this.titleEl = this.el.select('.modal-title',true).first();
2407 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2408 this.maskEl.enableDisplayMode("block");
2410 //this.el.addClass("x-dlg-modal");
2412 if (this.buttons.length) {
2413 Roo.each(this.buttons, function(bb) {
2414 b = Roo.apply({}, bb);
2415 b.xns = b.xns || Roo.bootstrap;
2416 b.xtype = b.xtype || 'Button';
2417 if (typeof(b.listeners) == 'undefined') {
2418 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2421 var btn = Roo.factory(b);
2423 btn.onRender(this.el.select('.modal-footer div').first());
2427 // render the children.
2430 if(typeof(this.items) != 'undefined'){
2431 var items = this.items;
2434 for(var i =0;i < items.length;i++) {
2435 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2439 this.items = nitems;
2441 // where are these used - they used to be body/close/footer
2445 //this.el.addClass([this.fieldClass, this.cls]);
2448 getAutoCreate : function(){
2453 html : this.html || ''
2458 cls : 'modal-title',
2462 if(this.specificTitle){
2468 if (this.allow_close) {
2479 style : 'display: none',
2482 cls: "modal-dialog",
2485 cls : "modal-content",
2488 cls : 'modal-header',
2493 cls : 'modal-footer',
2497 cls: 'btn-' + this.buttonPosition
2514 modal.cls += ' fade';
2520 getChildContainer : function() {
2525 getButtonContainer : function() {
2526 return this.el.select('.modal-footer div',true).first();
2529 initEvents : function()
2531 if (this.allow_close) {
2532 this.closeEl.on('click', this.hide, this);
2538 if (!this.rendered) {
2542 this.el.setStyle('display', 'block');
2546 (function(){ _this.el.addClass('in'); }).defer(50);
2548 this.el.addClass('in');
2551 // not sure how we can show data in here..
2553 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2556 Roo.get(document.body).addClass("x-body-masked");
2557 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2559 this.el.setStyle('zIndex', '10001');
2561 this.fireEvent('show', this);
2568 Roo.get(document.body).removeClass("x-body-masked");
2569 this.el.removeClass('in');
2573 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2575 this.el.setStyle('display', 'none');
2578 this.fireEvent('hide', this);
2581 addButton : function(str, cb)
2585 var b = Roo.apply({}, { html : str } );
2586 b.xns = b.xns || Roo.bootstrap;
2587 b.xtype = b.xtype || 'Button';
2588 if (typeof(b.listeners) == 'undefined') {
2589 b.listeners = { click : cb.createDelegate(this) };
2592 var btn = Roo.factory(b);
2594 btn.onRender(this.el.select('.modal-footer div').first());
2600 setDefaultButton : function(btn)
2602 //this.el.select('.modal-footer').()
2604 resizeTo: function(w,h)
2608 setContentSize : function(w, h)
2612 onButtonClick: function(btn,e)
2615 this.fireEvent('btnclick', btn.name, e);
2618 * Set the title of the Dialog
2619 * @param {String} str new Title
2621 setTitle: function(str) {
2622 this.titleEl.dom.innerHTML = str;
2625 * Set the body of the Dialog
2626 * @param {String} str new Title
2628 setBody: function(str) {
2629 this.bodyEl.dom.innerHTML = str;
2632 * Set the body of the Dialog using the template
2633 * @param {Obj} data - apply this data to the template and replace the body contents.
2635 applyBody: function(obj)
2638 Roo.log("Error - using apply Body without a template");
2641 this.tmpl.overwrite(this.bodyEl, obj);
2647 Roo.apply(Roo.bootstrap.Modal, {
2649 * Button config that displays a single OK button
2658 * Button config that displays Yes and No buttons
2674 * Button config that displays OK and Cancel buttons
2689 * Button config that displays Yes, No and Cancel buttons
2712 * messagebox - can be used as a replace
2716 * @class Roo.MessageBox
2717 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2721 Roo.Msg.alert('Status', 'Changes saved successfully.');
2723 // Prompt for user data:
2724 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2726 // process text value...
2730 // Show a dialog using config options:
2732 title:'Save Changes?',
2733 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2734 buttons: Roo.Msg.YESNOCANCEL,
2741 Roo.bootstrap.MessageBox = function(){
2742 var dlg, opt, mask, waitTimer;
2743 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2744 var buttons, activeTextEl, bwidth;
2748 var handleButton = function(button){
2750 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2754 var handleHide = function(){
2756 dlg.el.removeClass(opt.cls);
2759 // Roo.TaskMgr.stop(waitTimer);
2760 // waitTimer = null;
2765 var updateButtons = function(b){
2768 buttons["ok"].hide();
2769 buttons["cancel"].hide();
2770 buttons["yes"].hide();
2771 buttons["no"].hide();
2772 //dlg.footer.dom.style.display = 'none';
2775 dlg.footerEl.dom.style.display = '';
2776 for(var k in buttons){
2777 if(typeof buttons[k] != "function"){
2780 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2781 width += buttons[k].el.getWidth()+15;
2791 var handleEsc = function(d, k, e){
2792 if(opt && opt.closable !== false){
2802 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2803 * @return {Roo.BasicDialog} The BasicDialog element
2805 getDialog : function(){
2807 dlg = new Roo.bootstrap.Modal( {
2810 //constraintoviewport:false,
2812 //collapsible : false,
2817 //buttonAlign:"center",
2818 closeClick : function(){
2819 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2822 handleButton("cancel");
2827 dlg.on("hide", handleHide);
2829 //dlg.addKeyListener(27, handleEsc);
2831 this.buttons = buttons;
2832 var bt = this.buttonText;
2833 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2834 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2835 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2836 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2838 bodyEl = dlg.bodyEl.createChild({
2840 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2841 '<textarea class="roo-mb-textarea"></textarea>' +
2842 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2844 msgEl = bodyEl.dom.firstChild;
2845 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2846 textboxEl.enableDisplayMode();
2847 textboxEl.addKeyListener([10,13], function(){
2848 if(dlg.isVisible() && opt && opt.buttons){
2851 }else if(opt.buttons.yes){
2852 handleButton("yes");
2856 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2857 textareaEl.enableDisplayMode();
2858 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2859 progressEl.enableDisplayMode();
2860 var pf = progressEl.dom.firstChild;
2862 pp = Roo.get(pf.firstChild);
2863 pp.setHeight(pf.offsetHeight);
2871 * Updates the message box body text
2872 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2873 * the XHTML-compliant non-breaking space character '&#160;')
2874 * @return {Roo.MessageBox} This message box
2876 updateText : function(text){
2877 if(!dlg.isVisible() && !opt.width){
2878 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2880 msgEl.innerHTML = text || ' ';
2882 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2883 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2885 Math.min(opt.width || cw , this.maxWidth),
2886 Math.max(opt.minWidth || this.minWidth, bwidth)
2889 activeTextEl.setWidth(w);
2891 if(dlg.isVisible()){
2892 dlg.fixedcenter = false;
2894 // to big, make it scroll. = But as usual stupid IE does not support
2897 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2898 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2899 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2901 bodyEl.dom.style.height = '';
2902 bodyEl.dom.style.overflowY = '';
2905 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2907 bodyEl.dom.style.overflowX = '';
2910 dlg.setContentSize(w, bodyEl.getHeight());
2911 if(dlg.isVisible()){
2912 dlg.fixedcenter = true;
2918 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2919 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2920 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2921 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2922 * @return {Roo.MessageBox} This message box
2924 updateProgress : function(value, text){
2926 this.updateText(text);
2928 if (pp) { // weird bug on my firefox - for some reason this is not defined
2929 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2935 * Returns true if the message box is currently displayed
2936 * @return {Boolean} True if the message box is visible, else false
2938 isVisible : function(){
2939 return dlg && dlg.isVisible();
2943 * Hides the message box if it is displayed
2946 if(this.isVisible()){
2952 * Displays a new message box, or reinitializes an existing message box, based on the config options
2953 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2954 * The following config object properties are supported:
2956 Property Type Description
2957 ---------- --------------- ------------------------------------------------------------------------------------
2958 animEl String/Element An id or Element from which the message box should animate as it opens and
2959 closes (defaults to undefined)
2960 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2961 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2962 closable Boolean False to hide the top-right close button (defaults to true). Note that
2963 progress and wait dialogs will ignore this property and always hide the
2964 close button as they can only be closed programmatically.
2965 cls String A custom CSS class to apply to the message box element
2966 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2967 displayed (defaults to 75)
2968 fn Function A callback function to execute after closing the dialog. The arguments to the
2969 function will be btn (the name of the button that was clicked, if applicable,
2970 e.g. "ok"), and text (the value of the active text field, if applicable).
2971 Progress and wait dialogs will ignore this option since they do not respond to
2972 user actions and can only be closed programmatically, so any required function
2973 should be called by the same code after it closes the dialog.
2974 icon String A CSS class that provides a background image to be used as an icon for
2975 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2976 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2977 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2978 modal Boolean False to allow user interaction with the page while the message box is
2979 displayed (defaults to true)
2980 msg String A string that will replace the existing message box body text (defaults
2981 to the XHTML-compliant non-breaking space character ' ')
2982 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2983 progress Boolean True to display a progress bar (defaults to false)
2984 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2985 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2986 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2987 title String The title text
2988 value String The string value to set into the active textbox element if displayed
2989 wait Boolean True to display a progress bar (defaults to false)
2990 width Number The width of the dialog in pixels
2997 msg: 'Please enter your address:',
2999 buttons: Roo.MessageBox.OKCANCEL,
3002 animEl: 'addAddressBtn'
3005 * @param {Object} config Configuration options
3006 * @return {Roo.MessageBox} This message box
3008 show : function(options)
3011 // this causes nightmares if you show one dialog after another
3012 // especially on callbacks..
3014 if(this.isVisible()){
3017 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3018 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3019 Roo.log("New Dialog Message:" + options.msg )
3020 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3021 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3024 var d = this.getDialog();
3026 d.setTitle(opt.title || " ");
3027 d.closeEl.setDisplayed(opt.closable !== false);
3028 activeTextEl = textboxEl;
3029 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3034 textareaEl.setHeight(typeof opt.multiline == "number" ?
3035 opt.multiline : this.defaultTextHeight);
3036 activeTextEl = textareaEl;
3045 progressEl.setDisplayed(opt.progress === true);
3046 this.updateProgress(0);
3047 activeTextEl.dom.value = opt.value || "";
3049 dlg.setDefaultButton(activeTextEl);
3051 var bs = opt.buttons;
3055 }else if(bs && bs.yes){
3056 db = buttons["yes"];
3058 dlg.setDefaultButton(db);
3060 bwidth = updateButtons(opt.buttons);
3061 this.updateText(opt.msg);
3063 d.el.addClass(opt.cls);
3065 d.proxyDrag = opt.proxyDrag === true;
3066 d.modal = opt.modal !== false;
3067 d.mask = opt.modal !== false ? mask : false;
3069 // force it to the end of the z-index stack so it gets a cursor in FF
3070 document.body.appendChild(dlg.el.dom);
3071 d.animateTarget = null;
3072 d.show(options.animEl);
3078 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3079 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3080 * and closing the message box when the process is complete.
3081 * @param {String} title The title bar text
3082 * @param {String} msg The message box body text
3083 * @return {Roo.MessageBox} This message box
3085 progress : function(title, msg){
3092 minWidth: this.minProgressWidth,
3099 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3100 * If a callback function is passed it will be called after the user clicks the button, and the
3101 * id of the button that was clicked will be passed as the only parameter to the callback
3102 * (could also be the top-right close button).
3103 * @param {String} title The title bar text
3104 * @param {String} msg The message box body text
3105 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3106 * @param {Object} scope (optional) The scope of the callback function
3107 * @return {Roo.MessageBox} This message box
3109 alert : function(title, msg, fn, scope){
3122 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3123 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3124 * You are responsible for closing the message box when the process is complete.
3125 * @param {String} msg The message box body text
3126 * @param {String} title (optional) The title bar text
3127 * @return {Roo.MessageBox} This message box
3129 wait : function(msg, title){
3140 waitTimer = Roo.TaskMgr.start({
3142 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3150 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3151 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3152 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3153 * @param {String} title The title bar text
3154 * @param {String} msg The message box body text
3155 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3156 * @param {Object} scope (optional) The scope of the callback function
3157 * @return {Roo.MessageBox} This message box
3159 confirm : function(title, msg, fn, scope){
3163 buttons: this.YESNO,
3172 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3173 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3174 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3175 * (could also be the top-right close button) and the text that was entered will be passed as the two
3176 * parameters to the callback.
3177 * @param {String} title The title bar text
3178 * @param {String} msg The message box body text
3179 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3180 * @param {Object} scope (optional) The scope of the callback function
3181 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3182 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3183 * @return {Roo.MessageBox} This message box
3185 prompt : function(title, msg, fn, scope, multiline){
3189 buttons: this.OKCANCEL,
3194 multiline: multiline,
3201 * Button config that displays a single OK button
3206 * Button config that displays Yes and No buttons
3209 YESNO : {yes:true, no:true},
3211 * Button config that displays OK and Cancel buttons
3214 OKCANCEL : {ok:true, cancel:true},
3216 * Button config that displays Yes, No and Cancel buttons
3219 YESNOCANCEL : {yes:true, no:true, cancel:true},
3222 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3225 defaultTextHeight : 75,
3227 * The maximum width in pixels of the message box (defaults to 600)
3232 * The minimum width in pixels of the message box (defaults to 100)
3237 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3238 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3241 minProgressWidth : 250,
3243 * An object containing the default button text strings that can be overriden for localized language support.
3244 * Supported properties are: ok, cancel, yes and no.
3245 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3258 * Shorthand for {@link Roo.MessageBox}
3260 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3261 Roo.Msg = Roo.Msg || Roo.MessageBox;
3270 * @class Roo.bootstrap.Navbar
3271 * @extends Roo.bootstrap.Component
3272 * Bootstrap Navbar class
3275 * Create a new Navbar
3276 * @param {Object} config The config object
3280 Roo.bootstrap.Navbar = function(config){
3281 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3285 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3294 getAutoCreate : function(){
3297 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3301 initEvents :function ()
3303 //Roo.log(this.el.select('.navbar-toggle',true));
3304 this.el.select('.navbar-toggle',true).on('click', function() {
3305 // Roo.log('click');
3306 this.el.select('.navbar-collapse',true).toggleClass('in');
3314 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3316 var size = this.el.getSize();
3317 this.maskEl.setSize(size.width, size.height);
3318 this.maskEl.enableDisplayMode("block");
3327 getChildContainer : function()
3329 if (this.el.select('.collapse').getCount()) {
3330 return this.el.select('.collapse',true).first();
3363 * @class Roo.bootstrap.NavSimplebar
3364 * @extends Roo.bootstrap.Navbar
3365 * Bootstrap Sidebar class
3367 * @cfg {Boolean} inverse is inverted color
3369 * @cfg {String} type (nav | pills | tabs)
3370 * @cfg {Boolean} arrangement stacked | justified
3371 * @cfg {String} align (left | right) alignment
3373 * @cfg {Boolean} main (true|false) main nav bar? default false
3374 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3376 * @cfg {String} tag (header|footer|nav|div) default is nav
3382 * Create a new Sidebar
3383 * @param {Object} config The config object
3387 Roo.bootstrap.NavSimplebar = function(config){
3388 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3391 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3407 getAutoCreate : function(){
3411 tag : this.tag || 'div',
3424 this.type = this.type || 'nav';
3425 if (['tabs','pills'].indexOf(this.type)!==-1) {
3426 cfg.cn[0].cls += ' nav-' + this.type
3430 if (this.type!=='nav') {
3431 Roo.log('nav type must be nav/tabs/pills')
3433 cfg.cn[0].cls += ' navbar-nav'
3439 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3440 cfg.cn[0].cls += ' nav-' + this.arrangement;
3444 if (this.align === 'right') {
3445 cfg.cn[0].cls += ' navbar-right';
3449 cfg.cls += ' navbar-inverse';
3476 * @class Roo.bootstrap.NavHeaderbar
3477 * @extends Roo.bootstrap.NavSimplebar
3478 * Bootstrap Sidebar class
3480 * @cfg {String} brand what is brand
3481 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3482 * @cfg {String} brand_href href of the brand
3483 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3484 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3485 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3486 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3489 * Create a new Sidebar
3490 * @param {Object} config The config object
3494 Roo.bootstrap.NavHeaderbar = function(config){
3495 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3499 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3506 desktopCenter : false,
3509 getAutoCreate : function(){
3512 tag: this.nav || 'nav',
3519 if (this.desktopCenter) {
3520 cn.push({cls : 'container', cn : []});
3527 cls: 'navbar-header',
3532 cls: 'navbar-toggle',
3533 'data-toggle': 'collapse',
3538 html: 'Toggle navigation'
3560 cls: 'collapse navbar-collapse',
3564 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3566 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3567 cfg.cls += ' navbar-' + this.position;
3569 // tag can override this..
3571 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3574 if (this.brand !== '') {
3577 href: this.brand_href ? this.brand_href : '#',
3578 cls: 'navbar-brand',
3586 cfg.cls += ' main-nav';
3594 getHeaderChildContainer : function()
3596 if (this.el.select('.navbar-header').getCount()) {
3597 return this.el.select('.navbar-header',true).first();
3600 return this.getChildContainer();
3604 initEvents : function()
3606 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3608 if (this.autohide) {
3613 Roo.get(document).on('scroll',function(e) {
3614 var ns = Roo.get(document).getScroll().top;
3615 var os = prevScroll;
3619 ft.removeClass('slideDown');
3620 ft.addClass('slideUp');
3623 ft.removeClass('slideUp');
3624 ft.addClass('slideDown');
3645 * @class Roo.bootstrap.NavSidebar
3646 * @extends Roo.bootstrap.Navbar
3647 * Bootstrap Sidebar class
3650 * Create a new Sidebar
3651 * @param {Object} config The config object
3655 Roo.bootstrap.NavSidebar = function(config){
3656 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3659 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3661 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3663 getAutoCreate : function(){
3668 cls: 'sidebar sidebar-nav'
3690 * @class Roo.bootstrap.NavGroup
3691 * @extends Roo.bootstrap.Component
3692 * Bootstrap NavGroup class
3693 * @cfg {String} align (left|right)
3694 * @cfg {Boolean} inverse
3695 * @cfg {String} type (nav|pills|tab) default nav
3696 * @cfg {String} navId - reference Id for navbar.
3700 * Create a new nav group
3701 * @param {Object} config The config object
3704 Roo.bootstrap.NavGroup = function(config){
3705 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3708 Roo.bootstrap.NavGroup.register(this);
3712 * Fires when the active item changes
3713 * @param {Roo.bootstrap.NavGroup} this
3714 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3715 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3722 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3733 getAutoCreate : function()
3735 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3742 if (['tabs','pills'].indexOf(this.type)!==-1) {
3743 cfg.cls += ' nav-' + this.type
3745 if (this.type!=='nav') {
3746 Roo.log('nav type must be nav/tabs/pills')
3748 cfg.cls += ' navbar-nav'
3751 if (this.parent().sidebar) {
3754 cls: 'dashboard-menu sidebar-menu'
3760 if (this.form === true) {
3766 if (this.align === 'right') {
3767 cfg.cls += ' navbar-right';
3769 cfg.cls += ' navbar-left';
3773 if (this.align === 'right') {
3774 cfg.cls += ' navbar-right';
3778 cfg.cls += ' navbar-inverse';
3786 * sets the active Navigation item
3787 * @param {Roo.bootstrap.NavItem} the new current navitem
3789 setActiveItem : function(item)
3792 Roo.each(this.navItems, function(v){
3797 v.setActive(false, true);
3804 item.setActive(true, true);
3805 this.fireEvent('changed', this, item, prev);
3810 * gets the active Navigation item
3811 * @return {Roo.bootstrap.NavItem} the current navitem
3813 getActive : function()
3817 Roo.each(this.navItems, function(v){
3828 indexOfNav : function()
3832 Roo.each(this.navItems, function(v,i){
3843 * adds a Navigation item
3844 * @param {Roo.bootstrap.NavItem} the navitem to add
3846 addItem : function(cfg)
3848 var cn = new Roo.bootstrap.NavItem(cfg);
3850 cn.parentId = this.id;
3851 cn.onRender(this.el, null);
3855 * register a Navigation item
3856 * @param {Roo.bootstrap.NavItem} the navitem to add
3858 register : function(item)
3860 this.navItems.push( item);
3861 item.navId = this.navId;
3866 * clear all the Navigation item
3869 clearAll : function()
3872 this.el.dom.innerHTML = '';
3875 getNavItem: function(tabId)
3878 Roo.each(this.navItems, function(e) {
3879 if (e.tabId == tabId) {
3889 setActiveNext : function()
3891 var i = this.indexOfNav(this.getActive());
3892 if (i > this.navItems.length) {
3895 this.setActiveItem(this.navItems[i+1]);
3897 setActivePrev : function()
3899 var i = this.indexOfNav(this.getActive());
3903 this.setActiveItem(this.navItems[i-1]);
3905 clearWasActive : function(except) {
3906 Roo.each(this.navItems, function(e) {
3907 if (e.tabId != except.tabId && e.was_active) {
3908 e.was_active = false;
3915 getWasActive : function ()
3918 Roo.each(this.navItems, function(e) {
3933 Roo.apply(Roo.bootstrap.NavGroup, {
3937 * register a Navigation Group
3938 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3940 register : function(navgrp)
3942 this.groups[navgrp.navId] = navgrp;
3946 * fetch a Navigation Group based on the navigation ID
3947 * @param {string} the navgroup to add
3948 * @returns {Roo.bootstrap.NavGroup} the navgroup
3950 get: function(navId) {
3951 if (typeof(this.groups[navId]) == 'undefined') {
3953 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3955 return this.groups[navId] ;
3970 * @class Roo.bootstrap.NavItem
3971 * @extends Roo.bootstrap.Component
3972 * Bootstrap Navbar.NavItem class
3973 * @cfg {String} href link to
3974 * @cfg {String} html content of button
3975 * @cfg {String} badge text inside badge
3976 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3977 * @cfg {String} glyphicon name of glyphicon
3978 * @cfg {String} icon name of font awesome icon
3979 * @cfg {Boolean} active Is item active
3980 * @cfg {Boolean} disabled Is item disabled
3982 * @cfg {Boolean} preventDefault (true | false) default false
3983 * @cfg {String} tabId the tab that this item activates.
3984 * @cfg {String} tagtype (a|span) render as a href or span?
3985 * @cfg {Boolean} animateRef (true|false) link to element default false
3988 * Create a new Navbar Item
3989 * @param {Object} config The config object
3991 Roo.bootstrap.NavItem = function(config){
3992 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3997 * The raw click event for the entire grid.
3998 * @param {Roo.EventObject} e
4003 * Fires when the active item active state changes
4004 * @param {Roo.bootstrap.NavItem} this
4005 * @param {boolean} state the new state
4011 * Fires when scroll to element
4012 * @param {Roo.bootstrap.NavItem} this
4013 * @param {Object} options
4014 * @param {Roo.EventObject} e
4022 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4030 preventDefault : false,
4037 getAutoCreate : function(){
4045 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4047 if (this.disabled) {
4048 cfg.cls += ' disabled';
4051 if (this.href || this.html || this.glyphicon || this.icon) {
4055 href : this.href || "#",
4056 html: this.html || ''
4061 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4064 if(this.glyphicon) {
4065 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4070 cfg.cn[0].html += " <span class='caret'></span>";
4074 if (this.badge !== '') {
4076 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4084 initEvents: function()
4086 if (typeof (this.menu) != 'undefined') {
4087 this.menu.parentType = this.xtype;
4088 this.menu.triggerEl = this.el;
4089 this.menu = this.addxtype(Roo.apply({}, this.menu));
4092 this.el.select('a',true).on('click', this.onClick, this);
4094 if(this.tagtype == 'span'){
4095 this.el.select('span',true).on('click', this.onClick, this);
4098 // at this point parent should be available..
4099 this.parent().register(this);
4102 onClick : function(e)
4105 this.preventDefault ||
4112 if (this.disabled) {
4116 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4117 if (tg && tg.transition) {
4118 Roo.log("waiting for the transitionend");
4124 //Roo.log("fire event clicked");
4125 if(this.fireEvent('click', this, e) === false){
4129 if(this.tagtype == 'span'){
4133 //Roo.log(this.href);
4134 var ael = this.el.select('a',true).first();
4137 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4138 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4139 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4140 return; // ignore... - it's a 'hash' to another page.
4144 this.scrollToElement(e);
4148 var p = this.parent();
4150 if (['tabs','pills'].indexOf(p.type)!==-1) {
4151 if (typeof(p.setActiveItem) !== 'undefined') {
4152 p.setActiveItem(this);
4156 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4157 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4158 // remove the collapsed menu expand...
4159 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4163 isActive: function () {
4166 setActive : function(state, fire, is_was_active)
4168 if (this.active && !state & this.navId) {
4169 this.was_active = true;
4170 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4172 nv.clearWasActive(this);
4176 this.active = state;
4179 this.el.removeClass('active');
4180 } else if (!this.el.hasClass('active')) {
4181 this.el.addClass('active');
4184 this.fireEvent('changed', this, state);
4187 // show a panel if it's registered and related..
4189 if (!this.navId || !this.tabId || !state || is_was_active) {
4193 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4197 var pan = tg.getPanelByName(this.tabId);
4201 // if we can not flip to new panel - go back to old nav highlight..
4202 if (false == tg.showPanel(pan)) {
4203 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4205 var onav = nv.getWasActive();
4207 onav.setActive(true, false, true);
4216 // this should not be here...
4217 setDisabled : function(state)
4219 this.disabled = state;
4221 this.el.removeClass('disabled');
4222 } else if (!this.el.hasClass('disabled')) {
4223 this.el.addClass('disabled');
4229 * Fetch the element to display the tooltip on.
4230 * @return {Roo.Element} defaults to this.el
4232 tooltipEl : function()
4234 return this.el.select('' + this.tagtype + '', true).first();
4237 scrollToElement : function(e)
4239 var c = document.body;
4242 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4244 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4245 c = document.documentElement;
4248 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4254 var o = target.calcOffsetsTo(c);
4261 this.fireEvent('scrollto', this, options, e);
4263 Roo.get(c).scrollTo('top', options.value, true);
4276 * <span> icon </span>
4277 * <span> text </span>
4278 * <span>badge </span>
4282 * @class Roo.bootstrap.NavSidebarItem
4283 * @extends Roo.bootstrap.NavItem
4284 * Bootstrap Navbar.NavSidebarItem class
4286 * Create a new Navbar Button
4287 * @param {Object} config The config object
4289 Roo.bootstrap.NavSidebarItem = function(config){
4290 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4295 * The raw click event for the entire grid.
4296 * @param {Roo.EventObject} e
4301 * Fires when the active item active state changes
4302 * @param {Roo.bootstrap.NavSidebarItem} this
4303 * @param {boolean} state the new state
4311 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4314 getAutoCreate : function(){
4319 href : this.href || '#',
4331 html : this.html || ''
4336 cfg.cls += ' active';
4340 if (this.glyphicon || this.icon) {
4341 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4342 a.cn.push({ tag : 'i', cls : c }) ;
4347 if (this.badge !== '') {
4348 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4352 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4353 a.cls += 'dropdown-toggle treeview' ;
4377 * @class Roo.bootstrap.Row
4378 * @extends Roo.bootstrap.Component
4379 * Bootstrap Row class (contains columns...)
4383 * @param {Object} config The config object
4386 Roo.bootstrap.Row = function(config){
4387 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4390 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4392 getAutoCreate : function(){
4411 * @class Roo.bootstrap.Element
4412 * @extends Roo.bootstrap.Component
4413 * Bootstrap Element class
4414 * @cfg {String} html contents of the element
4415 * @cfg {String} tag tag of the element
4416 * @cfg {String} cls class of the element
4417 * @cfg {Boolean} preventDefault (true|false) default false
4418 * @cfg {Boolean} clickable (true|false) default false
4421 * Create a new Element
4422 * @param {Object} config The config object
4425 Roo.bootstrap.Element = function(config){
4426 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4432 * When a element is chick
4433 * @param {Roo.bootstrap.Element} this
4434 * @param {Roo.EventObject} e
4440 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4445 preventDefault: false,
4448 getAutoCreate : function(){
4459 initEvents: function()
4461 Roo.bootstrap.Element.superclass.initEvents.call(this);
4464 this.el.on('click', this.onClick, this);
4469 onClick : function(e)
4471 if(this.preventDefault){
4475 this.fireEvent('click', this, e);
4478 getValue : function()
4480 return this.el.dom.innerHTML;
4483 setValue : function(value)
4485 this.el.dom.innerHTML = value;
4500 * @class Roo.bootstrap.Pagination
4501 * @extends Roo.bootstrap.Component
4502 * Bootstrap Pagination class
4503 * @cfg {String} size xs | sm | md | lg
4504 * @cfg {Boolean} inverse false | true
4507 * Create a new Pagination
4508 * @param {Object} config The config object
4511 Roo.bootstrap.Pagination = function(config){
4512 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4515 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4521 getAutoCreate : function(){
4527 cfg.cls += ' inverse';
4533 cfg.cls += " " + this.cls;
4551 * @class Roo.bootstrap.PaginationItem
4552 * @extends Roo.bootstrap.Component
4553 * Bootstrap PaginationItem class
4554 * @cfg {String} html text
4555 * @cfg {String} href the link
4556 * @cfg {Boolean} preventDefault (true | false) default true
4557 * @cfg {Boolean} active (true | false) default false
4558 * @cfg {Boolean} disabled default false
4562 * Create a new PaginationItem
4563 * @param {Object} config The config object
4567 Roo.bootstrap.PaginationItem = function(config){
4568 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4573 * The raw click event for the entire grid.
4574 * @param {Roo.EventObject} e
4580 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4584 preventDefault: true,
4589 getAutoCreate : function(){
4595 href : this.href ? this.href : '#',
4596 html : this.html ? this.html : ''
4606 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4610 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4616 initEvents: function() {
4618 this.el.on('click', this.onClick, this);
4621 onClick : function(e)
4623 Roo.log('PaginationItem on click ');
4624 if(this.preventDefault){
4632 this.fireEvent('click', this, e);
4648 * @class Roo.bootstrap.Slider
4649 * @extends Roo.bootstrap.Component
4650 * Bootstrap Slider class
4653 * Create a new Slider
4654 * @param {Object} config The config object
4657 Roo.bootstrap.Slider = function(config){
4658 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4661 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4663 getAutoCreate : function(){
4667 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4671 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4683 * Ext JS Library 1.1.1
4684 * Copyright(c) 2006-2007, Ext JS, LLC.
4686 * Originally Released Under LGPL - original licence link has changed is not relivant.
4689 * <script type="text/javascript">
4694 * @class Roo.grid.ColumnModel
4695 * @extends Roo.util.Observable
4696 * This is the default implementation of a ColumnModel used by the Grid. It defines
4697 * the columns in the grid.
4700 var colModel = new Roo.grid.ColumnModel([
4701 {header: "Ticker", width: 60, sortable: true, locked: true},
4702 {header: "Company Name", width: 150, sortable: true},
4703 {header: "Market Cap.", width: 100, sortable: true},
4704 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4705 {header: "Employees", width: 100, sortable: true, resizable: false}
4710 * The config options listed for this class are options which may appear in each
4711 * individual column definition.
4712 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4714 * @param {Object} config An Array of column config objects. See this class's
4715 * config objects for details.
4717 Roo.grid.ColumnModel = function(config){
4719 * The config passed into the constructor
4721 this.config = config;
4724 // if no id, create one
4725 // if the column does not have a dataIndex mapping,
4726 // map it to the order it is in the config
4727 for(var i = 0, len = config.length; i < len; i++){
4729 if(typeof c.dataIndex == "undefined"){
4732 if(typeof c.renderer == "string"){
4733 c.renderer = Roo.util.Format[c.renderer];
4735 if(typeof c.id == "undefined"){
4738 if(c.editor && c.editor.xtype){
4739 c.editor = Roo.factory(c.editor, Roo.grid);
4741 if(c.editor && c.editor.isFormField){
4742 c.editor = new Roo.grid.GridEditor(c.editor);
4744 this.lookup[c.id] = c;
4748 * The width of columns which have no width specified (defaults to 100)
4751 this.defaultWidth = 100;
4754 * Default sortable of columns which have no sortable specified (defaults to false)
4757 this.defaultSortable = false;
4761 * @event widthchange
4762 * Fires when the width of a column changes.
4763 * @param {ColumnModel} this
4764 * @param {Number} columnIndex The column index
4765 * @param {Number} newWidth The new width
4767 "widthchange": true,
4769 * @event headerchange
4770 * Fires when the text of a header changes.
4771 * @param {ColumnModel} this
4772 * @param {Number} columnIndex The column index
4773 * @param {Number} newText The new header text
4775 "headerchange": true,
4777 * @event hiddenchange
4778 * Fires when a column is hidden or "unhidden".
4779 * @param {ColumnModel} this
4780 * @param {Number} columnIndex The column index
4781 * @param {Boolean} hidden true if hidden, false otherwise
4783 "hiddenchange": true,
4785 * @event columnmoved
4786 * Fires when a column is moved.
4787 * @param {ColumnModel} this
4788 * @param {Number} oldIndex
4789 * @param {Number} newIndex
4791 "columnmoved" : true,
4793 * @event columlockchange
4794 * Fires when a column's locked state is changed
4795 * @param {ColumnModel} this
4796 * @param {Number} colIndex
4797 * @param {Boolean} locked true if locked
4799 "columnlockchange" : true
4801 Roo.grid.ColumnModel.superclass.constructor.call(this);
4803 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4805 * @cfg {String} header The header text to display in the Grid view.
4808 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4809 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4810 * specified, the column's index is used as an index into the Record's data Array.
4813 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4814 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4817 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4818 * Defaults to the value of the {@link #defaultSortable} property.
4819 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4822 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4825 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4828 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4831 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4834 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4835 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4836 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4837 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4840 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4843 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4846 * @cfg {String} cursor (Optional)
4849 * @cfg {String} tooltip (Optional)
4852 * Returns the id of the column at the specified index.
4853 * @param {Number} index The column index
4854 * @return {String} the id
4856 getColumnId : function(index){
4857 return this.config[index].id;
4861 * Returns the column for a specified id.
4862 * @param {String} id The column id
4863 * @return {Object} the column
4865 getColumnById : function(id){
4866 return this.lookup[id];
4871 * Returns the column for a specified dataIndex.
4872 * @param {String} dataIndex The column dataIndex
4873 * @return {Object|Boolean} the column or false if not found
4875 getColumnByDataIndex: function(dataIndex){
4876 var index = this.findColumnIndex(dataIndex);
4877 return index > -1 ? this.config[index] : false;
4881 * Returns the index for a specified column id.
4882 * @param {String} id The column id
4883 * @return {Number} the index, or -1 if not found
4885 getIndexById : function(id){
4886 for(var i = 0, len = this.config.length; i < len; i++){
4887 if(this.config[i].id == id){
4895 * Returns the index for a specified column dataIndex.
4896 * @param {String} dataIndex The column dataIndex
4897 * @return {Number} the index, or -1 if not found
4900 findColumnIndex : function(dataIndex){
4901 for(var i = 0, len = this.config.length; i < len; i++){
4902 if(this.config[i].dataIndex == dataIndex){
4910 moveColumn : function(oldIndex, newIndex){
4911 var c = this.config[oldIndex];
4912 this.config.splice(oldIndex, 1);
4913 this.config.splice(newIndex, 0, c);
4914 this.dataMap = null;
4915 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4918 isLocked : function(colIndex){
4919 return this.config[colIndex].locked === true;
4922 setLocked : function(colIndex, value, suppressEvent){
4923 if(this.isLocked(colIndex) == value){
4926 this.config[colIndex].locked = value;
4928 this.fireEvent("columnlockchange", this, colIndex, value);
4932 getTotalLockedWidth : function(){
4934 for(var i = 0; i < this.config.length; i++){
4935 if(this.isLocked(i) && !this.isHidden(i)){
4936 this.totalWidth += this.getColumnWidth(i);
4942 getLockedCount : function(){
4943 for(var i = 0, len = this.config.length; i < len; i++){
4944 if(!this.isLocked(i)){
4951 * Returns the number of columns.
4954 getColumnCount : function(visibleOnly){
4955 if(visibleOnly === true){
4957 for(var i = 0, len = this.config.length; i < len; i++){
4958 if(!this.isHidden(i)){
4964 return this.config.length;
4968 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4969 * @param {Function} fn
4970 * @param {Object} scope (optional)
4971 * @return {Array} result
4973 getColumnsBy : function(fn, scope){
4975 for(var i = 0, len = this.config.length; i < len; i++){
4976 var c = this.config[i];
4977 if(fn.call(scope||this, c, i) === true){
4985 * Returns true if the specified column is sortable.
4986 * @param {Number} col The column index
4989 isSortable : function(col){
4990 if(typeof this.config[col].sortable == "undefined"){
4991 return this.defaultSortable;
4993 return this.config[col].sortable;
4997 * Returns the rendering (formatting) function defined for the column.
4998 * @param {Number} col The column index.
4999 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5001 getRenderer : function(col){
5002 if(!this.config[col].renderer){
5003 return Roo.grid.ColumnModel.defaultRenderer;
5005 return this.config[col].renderer;
5009 * Sets the rendering (formatting) function for a column.
5010 * @param {Number} col The column index
5011 * @param {Function} fn The function to use to process the cell's raw data
5012 * to return HTML markup for the grid view. The render function is called with
5013 * the following parameters:<ul>
5014 * <li>Data value.</li>
5015 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5016 * <li>css A CSS style string to apply to the table cell.</li>
5017 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5018 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5019 * <li>Row index</li>
5020 * <li>Column index</li>
5021 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5023 setRenderer : function(col, fn){
5024 this.config[col].renderer = fn;
5028 * Returns the width for the specified column.
5029 * @param {Number} col The column index
5032 getColumnWidth : function(col){
5033 return this.config[col].width * 1 || this.defaultWidth;
5037 * Sets the width for a column.
5038 * @param {Number} col The column index
5039 * @param {Number} width The new width
5041 setColumnWidth : function(col, width, suppressEvent){
5042 this.config[col].width = width;
5043 this.totalWidth = null;
5045 this.fireEvent("widthchange", this, col, width);
5050 * Returns the total width of all columns.
5051 * @param {Boolean} includeHidden True to include hidden column widths
5054 getTotalWidth : function(includeHidden){
5055 if(!this.totalWidth){
5056 this.totalWidth = 0;
5057 for(var i = 0, len = this.config.length; i < len; i++){
5058 if(includeHidden || !this.isHidden(i)){
5059 this.totalWidth += this.getColumnWidth(i);
5063 return this.totalWidth;
5067 * Returns the header for the specified column.
5068 * @param {Number} col The column index
5071 getColumnHeader : function(col){
5072 return this.config[col].header;
5076 * Sets the header for a column.
5077 * @param {Number} col The column index
5078 * @param {String} header The new header
5080 setColumnHeader : function(col, header){
5081 this.config[col].header = header;
5082 this.fireEvent("headerchange", this, col, header);
5086 * Returns the tooltip for the specified column.
5087 * @param {Number} col The column index
5090 getColumnTooltip : function(col){
5091 return this.config[col].tooltip;
5094 * Sets the tooltip for a column.
5095 * @param {Number} col The column index
5096 * @param {String} tooltip The new tooltip
5098 setColumnTooltip : function(col, tooltip){
5099 this.config[col].tooltip = tooltip;
5103 * Returns the dataIndex for the specified column.
5104 * @param {Number} col The column index
5107 getDataIndex : function(col){
5108 return this.config[col].dataIndex;
5112 * Sets the dataIndex for a column.
5113 * @param {Number} col The column index
5114 * @param {Number} dataIndex The new dataIndex
5116 setDataIndex : function(col, dataIndex){
5117 this.config[col].dataIndex = dataIndex;
5123 * Returns true if the cell is editable.
5124 * @param {Number} colIndex The column index
5125 * @param {Number} rowIndex The row index
5128 isCellEditable : function(colIndex, rowIndex){
5129 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5133 * Returns the editor defined for the cell/column.
5134 * return false or null to disable editing.
5135 * @param {Number} colIndex The column index
5136 * @param {Number} rowIndex The row index
5139 getCellEditor : function(colIndex, rowIndex){
5140 return this.config[colIndex].editor;
5144 * Sets if a column is editable.
5145 * @param {Number} col The column index
5146 * @param {Boolean} editable True if the column is editable
5148 setEditable : function(col, editable){
5149 this.config[col].editable = editable;
5154 * Returns true if the column is hidden.
5155 * @param {Number} colIndex The column index
5158 isHidden : function(colIndex){
5159 return this.config[colIndex].hidden;
5164 * Returns true if the column width cannot be changed
5166 isFixed : function(colIndex){
5167 return this.config[colIndex].fixed;
5171 * Returns true if the column can be resized
5174 isResizable : function(colIndex){
5175 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5178 * Sets if a column is hidden.
5179 * @param {Number} colIndex The column index
5180 * @param {Boolean} hidden True if the column is hidden
5182 setHidden : function(colIndex, hidden){
5183 this.config[colIndex].hidden = hidden;
5184 this.totalWidth = null;
5185 this.fireEvent("hiddenchange", this, colIndex, hidden);
5189 * Sets the editor for a column.
5190 * @param {Number} col The column index
5191 * @param {Object} editor The editor object
5193 setEditor : function(col, editor){
5194 this.config[col].editor = editor;
5198 Roo.grid.ColumnModel.defaultRenderer = function(value){
5199 if(typeof value == "string" && value.length < 1){
5205 // Alias for backwards compatibility
5206 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5209 * Ext JS Library 1.1.1
5210 * Copyright(c) 2006-2007, Ext JS, LLC.
5212 * Originally Released Under LGPL - original licence link has changed is not relivant.
5215 * <script type="text/javascript">
5219 * @class Roo.LoadMask
5220 * A simple utility class for generically masking elements while loading data. If the element being masked has
5221 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5222 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5223 * element's UpdateManager load indicator and will be destroyed after the initial load.
5225 * Create a new LoadMask
5226 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5227 * @param {Object} config The config object
5229 Roo.LoadMask = function(el, config){
5230 this.el = Roo.get(el);
5231 Roo.apply(this, config);
5233 this.store.on('beforeload', this.onBeforeLoad, this);
5234 this.store.on('load', this.onLoad, this);
5235 this.store.on('loadexception', this.onLoadException, this);
5236 this.removeMask = false;
5238 var um = this.el.getUpdateManager();
5239 um.showLoadIndicator = false; // disable the default indicator
5240 um.on('beforeupdate', this.onBeforeLoad, this);
5241 um.on('update', this.onLoad, this);
5242 um.on('failure', this.onLoad, this);
5243 this.removeMask = true;
5247 Roo.LoadMask.prototype = {
5249 * @cfg {Boolean} removeMask
5250 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5251 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5255 * The text to display in a centered loading message box (defaults to 'Loading...')
5259 * @cfg {String} msgCls
5260 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5262 msgCls : 'x-mask-loading',
5265 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5271 * Disables the mask to prevent it from being displayed
5273 disable : function(){
5274 this.disabled = true;
5278 * Enables the mask so that it can be displayed
5280 enable : function(){
5281 this.disabled = false;
5284 onLoadException : function()
5288 if (typeof(arguments[3]) != 'undefined') {
5289 Roo.MessageBox.alert("Error loading",arguments[3]);
5293 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5294 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5303 this.el.unmask(this.removeMask);
5308 this.el.unmask(this.removeMask);
5312 onBeforeLoad : function(){
5314 this.el.mask(this.msg, this.msgCls);
5319 destroy : function(){
5321 this.store.un('beforeload', this.onBeforeLoad, this);
5322 this.store.un('load', this.onLoad, this);
5323 this.store.un('loadexception', this.onLoadException, this);
5325 var um = this.el.getUpdateManager();
5326 um.un('beforeupdate', this.onBeforeLoad, this);
5327 um.un('update', this.onLoad, this);
5328 um.un('failure', this.onLoad, this);
5339 * @class Roo.bootstrap.Table
5340 * @extends Roo.bootstrap.Component
5341 * Bootstrap Table class
5342 * @cfg {String} cls table class
5343 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5344 * @cfg {String} bgcolor Specifies the background color for a table
5345 * @cfg {Number} border Specifies whether the table cells should have borders or not
5346 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5347 * @cfg {Number} cellspacing Specifies the space between cells
5348 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5349 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5350 * @cfg {String} sortable Specifies that the table should be sortable
5351 * @cfg {String} summary Specifies a summary of the content of a table
5352 * @cfg {Number} width Specifies the width of a table
5353 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5355 * @cfg {boolean} striped Should the rows be alternative striped
5356 * @cfg {boolean} bordered Add borders to the table
5357 * @cfg {boolean} hover Add hover highlighting
5358 * @cfg {boolean} condensed Format condensed
5359 * @cfg {boolean} responsive Format condensed
5360 * @cfg {Boolean} loadMask (true|false) default false
5361 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5362 * @cfg {Boolean} thead (true|false) generate thead, default true
5363 * @cfg {Boolean} RowSelection (true|false) default false
5364 * @cfg {Boolean} CellSelection (true|false) default false
5365 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5369 * Create a new Table
5370 * @param {Object} config The config object
5373 Roo.bootstrap.Table = function(config){
5374 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5377 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5378 this.sm = this.selModel;
5379 this.sm.xmodule = this.xmodule || false;
5381 if (this.cm && typeof(this.cm.config) == 'undefined') {
5382 this.colModel = new Roo.grid.ColumnModel(this.cm);
5383 this.cm = this.colModel;
5384 this.cm.xmodule = this.xmodule || false;
5387 this.store= Roo.factory(this.store, Roo.data);
5388 this.ds = this.store;
5389 this.ds.xmodule = this.xmodule || false;
5392 if (this.footer && this.store) {
5393 this.footer.dataSource = this.ds;
5394 this.footer = Roo.factory(this.footer);
5401 * Fires when a cell is clicked
5402 * @param {Roo.bootstrap.Table} this
5403 * @param {Roo.Element} el
5404 * @param {Number} rowIndex
5405 * @param {Number} columnIndex
5406 * @param {Roo.EventObject} e
5410 * @event celldblclick
5411 * Fires when a cell is double clicked
5412 * @param {Roo.bootstrap.Table} this
5413 * @param {Roo.Element} el
5414 * @param {Number} rowIndex
5415 * @param {Number} columnIndex
5416 * @param {Roo.EventObject} e
5418 "celldblclick" : true,
5421 * Fires when a row is clicked
5422 * @param {Roo.bootstrap.Table} this
5423 * @param {Roo.Element} el
5424 * @param {Number} rowIndex
5425 * @param {Roo.EventObject} e
5429 * @event rowdblclick
5430 * Fires when a row is double clicked
5431 * @param {Roo.bootstrap.Table} this
5432 * @param {Roo.Element} el
5433 * @param {Number} rowIndex
5434 * @param {Roo.EventObject} e
5436 "rowdblclick" : true,
5439 * Fires when a mouseover occur
5440 * @param {Roo.bootstrap.Table} this
5441 * @param {Roo.Element} el
5442 * @param {Number} rowIndex
5443 * @param {Number} columnIndex
5444 * @param {Roo.EventObject} e
5449 * Fires when a mouseout occur
5450 * @param {Roo.bootstrap.Table} this
5451 * @param {Roo.Element} el
5452 * @param {Number} rowIndex
5453 * @param {Number} columnIndex
5454 * @param {Roo.EventObject} e
5459 * Fires when a row is rendered, so you can change add a style to it.
5460 * @param {Roo.bootstrap.Table} this
5461 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5465 * @event rowsrendered
5466 * Fires when all the rows have been rendered
5467 * @param {Roo.bootstrap.Table} this
5469 'rowsrendered' : true
5474 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5498 RowSelection : false,
5499 CellSelection : false,
5502 // Roo.Element - the tbody
5505 getAutoCreate : function(){
5506 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5515 cfg.cls += ' table-striped';
5519 cfg.cls += ' table-hover';
5521 if (this.bordered) {
5522 cfg.cls += ' table-bordered';
5524 if (this.condensed) {
5525 cfg.cls += ' table-condensed';
5527 if (this.responsive) {
5528 cfg.cls += ' table-responsive';
5532 cfg.cls+= ' ' +this.cls;
5535 // this lot should be simplifed...
5538 cfg.align=this.align;
5541 cfg.bgcolor=this.bgcolor;
5544 cfg.border=this.border;
5546 if (this.cellpadding) {
5547 cfg.cellpadding=this.cellpadding;
5549 if (this.cellspacing) {
5550 cfg.cellspacing=this.cellspacing;
5553 cfg.frame=this.frame;
5556 cfg.rules=this.rules;
5558 if (this.sortable) {
5559 cfg.sortable=this.sortable;
5562 cfg.summary=this.summary;
5565 cfg.width=this.width;
5568 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5571 if(this.store || this.cm){
5573 cfg.cn.push(this.renderHeader());
5576 cfg.cn.push(this.renderBody());
5579 cfg.cn.push(this.renderFooter());
5582 cfg.cls+= ' TableGrid';
5585 return { cn : [ cfg ] };
5588 initEvents : function()
5590 if(!this.store || !this.cm){
5594 //Roo.log('initEvents with ds!!!!');
5596 this.mainBody = this.el.select('tbody', true).first();
5601 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5602 e.on('click', _this.sort, _this);
5605 this.el.on("click", this.onClick, this);
5606 this.el.on("dblclick", this.onDblClick, this);
5608 // why is this done????? = it breaks dialogs??
5609 //this.parent().el.setStyle('position', 'relative');
5613 this.footer.parentId = this.id;
5614 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5617 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5619 this.store.on('load', this.onLoad, this);
5620 this.store.on('beforeload', this.onBeforeLoad, this);
5621 this.store.on('update', this.onUpdate, this);
5622 this.store.on('add', this.onAdd, this);
5626 onMouseover : function(e, el)
5628 var cell = Roo.get(el);
5634 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5635 cell = cell.findParent('td', false, true);
5638 var row = cell.findParent('tr', false, true);
5639 var cellIndex = cell.dom.cellIndex;
5640 var rowIndex = row.dom.rowIndex - 1; // start from 0
5642 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5646 onMouseout : function(e, el)
5648 var cell = Roo.get(el);
5654 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5655 cell = cell.findParent('td', false, true);
5658 var row = cell.findParent('tr', false, true);
5659 var cellIndex = cell.dom.cellIndex;
5660 var rowIndex = row.dom.rowIndex - 1; // start from 0
5662 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5666 onClick : function(e, el)
5668 var cell = Roo.get(el);
5670 if(!cell || (!this.CellSelection && !this.RowSelection)){
5674 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5675 cell = cell.findParent('td', false, true);
5678 if(!cell || typeof(cell) == 'undefined'){
5682 var row = cell.findParent('tr', false, true);
5684 if(!row || typeof(row) == 'undefined'){
5688 var cellIndex = cell.dom.cellIndex;
5689 var rowIndex = this.getRowIndex(row);
5691 if(this.CellSelection){
5692 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5695 if(this.RowSelection){
5696 this.fireEvent('rowclick', this, row, rowIndex, e);
5702 onDblClick : function(e,el)
5704 var cell = Roo.get(el);
5706 if(!cell || (!this.CellSelection && !this.RowSelection)){
5710 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5711 cell = cell.findParent('td', false, true);
5714 if(!cell || typeof(cell) == 'undefined'){
5718 var row = cell.findParent('tr', false, true);
5720 if(!row || typeof(row) == 'undefined'){
5724 var cellIndex = cell.dom.cellIndex;
5725 var rowIndex = this.getRowIndex(row);
5727 if(this.CellSelection){
5728 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5731 if(this.RowSelection){
5732 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5736 sort : function(e,el)
5738 var col = Roo.get(el);
5740 if(!col.hasClass('sortable')){
5744 var sort = col.attr('sort');
5747 if(col.hasClass('glyphicon-arrow-up')){
5751 this.store.sortInfo = {field : sort, direction : dir};
5754 Roo.log("calling footer first");
5755 this.footer.onClick('first');
5758 this.store.load({ params : { start : 0 } });
5762 renderHeader : function()
5771 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5773 var config = cm.config[i];
5778 html: cm.getColumnHeader(i)
5781 if(typeof(config.tooltip) != 'undefined'){
5782 c.tooltip = config.tooltip;
5785 if(typeof(config.colspan) != 'undefined'){
5786 c.colspan = config.colspan;
5789 if(typeof(config.hidden) != 'undefined' && config.hidden){
5790 c.style += ' display:none;';
5793 if(typeof(config.dataIndex) != 'undefined'){
5794 c.sort = config.dataIndex;
5797 if(typeof(config.sortable) != 'undefined' && config.sortable){
5801 if(typeof(config.align) != 'undefined' && config.align.length){
5802 c.style += ' text-align:' + config.align + ';';
5805 if(typeof(config.width) != 'undefined'){
5806 c.style += ' width:' + config.width + 'px;';
5809 if(typeof(config.cls) != 'undefined'){
5810 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5819 renderBody : function()
5829 colspan : this.cm.getColumnCount()
5839 renderFooter : function()
5849 colspan : this.cm.getColumnCount()
5863 Roo.log('ds onload');
5868 var ds = this.store;
5870 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5871 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5873 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5874 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5877 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5878 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5882 var tbody = this.mainBody;
5884 if(ds.getCount() > 0){
5885 ds.data.each(function(d,rowIndex){
5886 var row = this.renderRow(cm, ds, rowIndex);
5888 tbody.createChild(row);
5892 if(row.cellObjects.length){
5893 Roo.each(row.cellObjects, function(r){
5894 _this.renderCellObject(r);
5901 Roo.each(this.el.select('tbody td', true).elements, function(e){
5902 e.on('mouseover', _this.onMouseover, _this);
5905 Roo.each(this.el.select('tbody td', true).elements, function(e){
5906 e.on('mouseout', _this.onMouseout, _this);
5908 this.fireEvent('rowsrendered', this);
5909 //if(this.loadMask){
5910 // this.maskEl.hide();
5915 onUpdate : function(ds,record)
5917 this.refreshRow(record);
5920 onRemove : function(ds, record, index, isUpdate){
5921 if(isUpdate !== true){
5922 this.fireEvent("beforerowremoved", this, index, record);
5924 var bt = this.mainBody.dom;
5926 var rows = this.el.select('tbody > tr', true).elements;
5928 if(typeof(rows[index]) != 'undefined'){
5929 bt.removeChild(rows[index].dom);
5932 // if(bt.rows[index]){
5933 // bt.removeChild(bt.rows[index]);
5936 if(isUpdate !== true){
5937 //this.stripeRows(index);
5938 //this.syncRowHeights(index, index);
5940 this.fireEvent("rowremoved", this, index, record);
5944 onAdd : function(ds, records, rowIndex)
5946 //Roo.log('on Add called');
5947 // - note this does not handle multiple adding very well..
5948 var bt = this.mainBody.dom;
5949 for (var i =0 ; i < records.length;i++) {
5950 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5951 //Roo.log(records[i]);
5952 //Roo.log(this.store.getAt(rowIndex+i));
5953 this.insertRow(this.store, rowIndex + i, false);
5960 refreshRow : function(record){
5961 var ds = this.store, index;
5962 if(typeof record == 'number'){
5964 record = ds.getAt(index);
5966 index = ds.indexOf(record);
5968 this.insertRow(ds, index, true);
5969 this.onRemove(ds, record, index+1, true);
5970 //this.syncRowHeights(index, index);
5972 this.fireEvent("rowupdated", this, index, record);
5975 insertRow : function(dm, rowIndex, isUpdate){
5978 this.fireEvent("beforerowsinserted", this, rowIndex);
5980 //var s = this.getScrollState();
5981 var row = this.renderRow(this.cm, this.store, rowIndex);
5982 // insert before rowIndex..
5983 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5987 if(row.cellObjects.length){
5988 Roo.each(row.cellObjects, function(r){
5989 _this.renderCellObject(r);
5994 this.fireEvent("rowsinserted", this, rowIndex);
5995 //this.syncRowHeights(firstRow, lastRow);
5996 //this.stripeRows(firstRow);
6003 getRowDom : function(rowIndex)
6005 var rows = this.el.select('tbody > tr', true).elements;
6007 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6010 // returns the object tree for a tr..
6013 renderRow : function(cm, ds, rowIndex)
6016 var d = ds.getAt(rowIndex);
6023 var cellObjects = [];
6025 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6026 var config = cm.config[i];
6028 var renderer = cm.getRenderer(i);
6032 if(typeof(renderer) !== 'undefined'){
6033 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6035 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6036 // and are rendered into the cells after the row is rendered - using the id for the element.
6038 if(typeof(value) === 'object'){
6048 rowIndex : rowIndex,
6053 this.fireEvent('rowclass', this, rowcfg);
6057 cls : rowcfg.rowClass,
6059 html: (typeof(value) === 'object') ? '' : value
6066 if(typeof(config.colspan) != 'undefined'){
6067 td.colspan = config.colspan;
6070 if(typeof(config.hidden) != 'undefined' && config.hidden){
6071 td.style += ' display:none;';
6074 if(typeof(config.align) != 'undefined' && config.align.length){
6075 td.style += ' text-align:' + config.align + ';';
6078 if(typeof(config.width) != 'undefined'){
6079 td.style += ' width:' + config.width + 'px;';
6082 if(typeof(config.cursor) != 'undefined'){
6083 td.style += ' cursor:' + config.cursor + ';';
6086 if(typeof(config.cls) != 'undefined'){
6087 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6094 row.cellObjects = cellObjects;
6102 onBeforeLoad : function()
6104 //Roo.log('ds onBeforeLoad');
6108 //if(this.loadMask){
6109 // this.maskEl.show();
6117 this.el.select('tbody', true).first().dom.innerHTML = '';
6120 * Show or hide a row.
6121 * @param {Number} rowIndex to show or hide
6122 * @param {Boolean} state hide
6124 setRowVisibility : function(rowIndex, state)
6126 var bt = this.mainBody.dom;
6128 var rows = this.el.select('tbody > tr', true).elements;
6130 if(typeof(rows[rowIndex]) == 'undefined'){
6133 rows[rowIndex].dom.style.display = state ? '' : 'none';
6137 getSelectionModel : function(){
6139 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6141 return this.selModel;
6144 * Render the Roo.bootstrap object from renderder
6146 renderCellObject : function(r)
6150 var t = r.cfg.render(r.container);
6153 Roo.each(r.cfg.cn, function(c){
6155 container: t.getChildContainer(),
6158 _this.renderCellObject(child);
6163 getRowIndex : function(row)
6167 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6190 * @class Roo.bootstrap.TableCell
6191 * @extends Roo.bootstrap.Component
6192 * Bootstrap TableCell class
6193 * @cfg {String} html cell contain text
6194 * @cfg {String} cls cell class
6195 * @cfg {String} tag cell tag (td|th) default td
6196 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6197 * @cfg {String} align Aligns the content in a cell
6198 * @cfg {String} axis Categorizes cells
6199 * @cfg {String} bgcolor Specifies the background color of a cell
6200 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6201 * @cfg {Number} colspan Specifies the number of columns a cell should span
6202 * @cfg {String} headers Specifies one or more header cells a cell is related to
6203 * @cfg {Number} height Sets the height of a cell
6204 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6205 * @cfg {Number} rowspan Sets the number of rows a cell should span
6206 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6207 * @cfg {String} valign Vertical aligns the content in a cell
6208 * @cfg {Number} width Specifies the width of a cell
6211 * Create a new TableCell
6212 * @param {Object} config The config object
6215 Roo.bootstrap.TableCell = function(config){
6216 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6219 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6239 getAutoCreate : function(){
6240 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6260 cfg.align=this.align
6266 cfg.bgcolor=this.bgcolor
6269 cfg.charoff=this.charoff
6272 cfg.colspan=this.colspan
6275 cfg.headers=this.headers
6278 cfg.height=this.height
6281 cfg.nowrap=this.nowrap
6284 cfg.rowspan=this.rowspan
6287 cfg.scope=this.scope
6290 cfg.valign=this.valign
6293 cfg.width=this.width
6312 * @class Roo.bootstrap.TableRow
6313 * @extends Roo.bootstrap.Component
6314 * Bootstrap TableRow class
6315 * @cfg {String} cls row class
6316 * @cfg {String} align Aligns the content in a table row
6317 * @cfg {String} bgcolor Specifies a background color for a table row
6318 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6319 * @cfg {String} valign Vertical aligns the content in a table row
6322 * Create a new TableRow
6323 * @param {Object} config The config object
6326 Roo.bootstrap.TableRow = function(config){
6327 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6330 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6338 getAutoCreate : function(){
6339 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6349 cfg.align = this.align;
6352 cfg.bgcolor = this.bgcolor;
6355 cfg.charoff = this.charoff;
6358 cfg.valign = this.valign;
6376 * @class Roo.bootstrap.TableBody
6377 * @extends Roo.bootstrap.Component
6378 * Bootstrap TableBody class
6379 * @cfg {String} cls element class
6380 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6381 * @cfg {String} align Aligns the content inside the element
6382 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6383 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6386 * Create a new TableBody
6387 * @param {Object} config The config object
6390 Roo.bootstrap.TableBody = function(config){
6391 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6394 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6402 getAutoCreate : function(){
6403 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6417 cfg.align = this.align;
6420 cfg.charoff = this.charoff;
6423 cfg.valign = this.valign;
6430 // initEvents : function()
6437 // this.store = Roo.factory(this.store, Roo.data);
6438 // this.store.on('load', this.onLoad, this);
6440 // this.store.load();
6444 // onLoad: function ()
6446 // this.fireEvent('load', this);
6456 * Ext JS Library 1.1.1
6457 * Copyright(c) 2006-2007, Ext JS, LLC.
6459 * Originally Released Under LGPL - original licence link has changed is not relivant.
6462 * <script type="text/javascript">
6465 // as we use this in bootstrap.
6466 Roo.namespace('Roo.form');
6468 * @class Roo.form.Action
6469 * Internal Class used to handle form actions
6471 * @param {Roo.form.BasicForm} el The form element or its id
6472 * @param {Object} config Configuration options
6477 // define the action interface
6478 Roo.form.Action = function(form, options){
6480 this.options = options || {};
6483 * Client Validation Failed
6486 Roo.form.Action.CLIENT_INVALID = 'client';
6488 * Server Validation Failed
6491 Roo.form.Action.SERVER_INVALID = 'server';
6493 * Connect to Server Failed
6496 Roo.form.Action.CONNECT_FAILURE = 'connect';
6498 * Reading Data from Server Failed
6501 Roo.form.Action.LOAD_FAILURE = 'load';
6503 Roo.form.Action.prototype = {
6505 failureType : undefined,
6506 response : undefined,
6510 run : function(options){
6515 success : function(response){
6520 handleResponse : function(response){
6524 // default connection failure
6525 failure : function(response){
6527 this.response = response;
6528 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6529 this.form.afterAction(this, false);
6532 processResponse : function(response){
6533 this.response = response;
6534 if(!response.responseText){
6537 this.result = this.handleResponse(response);
6541 // utility functions used internally
6542 getUrl : function(appendParams){
6543 var url = this.options.url || this.form.url || this.form.el.dom.action;
6545 var p = this.getParams();
6547 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6553 getMethod : function(){
6554 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6557 getParams : function(){
6558 var bp = this.form.baseParams;
6559 var p = this.options.params;
6561 if(typeof p == "object"){
6562 p = Roo.urlEncode(Roo.applyIf(p, bp));
6563 }else if(typeof p == 'string' && bp){
6564 p += '&' + Roo.urlEncode(bp);
6567 p = Roo.urlEncode(bp);
6572 createCallback : function(){
6574 success: this.success,
6575 failure: this.failure,
6577 timeout: (this.form.timeout*1000),
6578 upload: this.form.fileUpload ? this.success : undefined
6583 Roo.form.Action.Submit = function(form, options){
6584 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6587 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6590 haveProgress : false,
6591 uploadComplete : false,
6593 // uploadProgress indicator.
6594 uploadProgress : function()
6596 if (!this.form.progressUrl) {
6600 if (!this.haveProgress) {
6601 Roo.MessageBox.progress("Uploading", "Uploading");
6603 if (this.uploadComplete) {
6604 Roo.MessageBox.hide();
6608 this.haveProgress = true;
6610 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6612 var c = new Roo.data.Connection();
6614 url : this.form.progressUrl,
6619 success : function(req){
6620 //console.log(data);
6624 rdata = Roo.decode(req.responseText)
6626 Roo.log("Invalid data from server..");
6630 if (!rdata || !rdata.success) {
6632 Roo.MessageBox.alert(Roo.encode(rdata));
6635 var data = rdata.data;
6637 if (this.uploadComplete) {
6638 Roo.MessageBox.hide();
6643 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6644 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6647 this.uploadProgress.defer(2000,this);
6650 failure: function(data) {
6651 Roo.log('progress url failed ');
6662 // run get Values on the form, so it syncs any secondary forms.
6663 this.form.getValues();
6665 var o = this.options;
6666 var method = this.getMethod();
6667 var isPost = method == 'POST';
6668 if(o.clientValidation === false || this.form.isValid()){
6670 if (this.form.progressUrl) {
6671 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6672 (new Date() * 1) + '' + Math.random());
6677 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6678 form:this.form.el.dom,
6679 url:this.getUrl(!isPost),
6681 params:isPost ? this.getParams() : null,
6682 isUpload: this.form.fileUpload
6685 this.uploadProgress();
6687 }else if (o.clientValidation !== false){ // client validation failed
6688 this.failureType = Roo.form.Action.CLIENT_INVALID;
6689 this.form.afterAction(this, false);
6693 success : function(response)
6695 this.uploadComplete= true;
6696 if (this.haveProgress) {
6697 Roo.MessageBox.hide();
6701 var result = this.processResponse(response);
6702 if(result === true || result.success){
6703 this.form.afterAction(this, true);
6707 this.form.markInvalid(result.errors);
6708 this.failureType = Roo.form.Action.SERVER_INVALID;
6710 this.form.afterAction(this, false);
6712 failure : function(response)
6714 this.uploadComplete= true;
6715 if (this.haveProgress) {
6716 Roo.MessageBox.hide();
6719 this.response = response;
6720 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6721 this.form.afterAction(this, false);
6724 handleResponse : function(response){
6725 if(this.form.errorReader){
6726 var rs = this.form.errorReader.read(response);
6729 for(var i = 0, len = rs.records.length; i < len; i++) {
6730 var r = rs.records[i];
6734 if(errors.length < 1){
6738 success : rs.success,
6744 ret = Roo.decode(response.responseText);
6748 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6758 Roo.form.Action.Load = function(form, options){
6759 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6760 this.reader = this.form.reader;
6763 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6768 Roo.Ajax.request(Roo.apply(
6769 this.createCallback(), {
6770 method:this.getMethod(),
6771 url:this.getUrl(false),
6772 params:this.getParams()
6776 success : function(response){
6778 var result = this.processResponse(response);
6779 if(result === true || !result.success || !result.data){
6780 this.failureType = Roo.form.Action.LOAD_FAILURE;
6781 this.form.afterAction(this, false);
6784 this.form.clearInvalid();
6785 this.form.setValues(result.data);
6786 this.form.afterAction(this, true);
6789 handleResponse : function(response){
6790 if(this.form.reader){
6791 var rs = this.form.reader.read(response);
6792 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6794 success : rs.success,
6798 return Roo.decode(response.responseText);
6802 Roo.form.Action.ACTION_TYPES = {
6803 'load' : Roo.form.Action.Load,
6804 'submit' : Roo.form.Action.Submit
6813 * @class Roo.bootstrap.Form
6814 * @extends Roo.bootstrap.Component
6815 * Bootstrap Form class
6816 * @cfg {String} method GET | POST (default POST)
6817 * @cfg {String} labelAlign top | left (default top)
6818 * @cfg {String} align left | right - for navbars
6819 * @cfg {Boolean} loadMask load mask when submit (default true)
6824 * @param {Object} config The config object
6828 Roo.bootstrap.Form = function(config){
6829 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6832 * @event clientvalidation
6833 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6834 * @param {Form} this
6835 * @param {Boolean} valid true if the form has passed client-side validation
6837 clientvalidation: true,
6839 * @event beforeaction
6840 * Fires before any action is performed. Return false to cancel the action.
6841 * @param {Form} this
6842 * @param {Action} action The action to be performed
6846 * @event actionfailed
6847 * Fires when an action fails.
6848 * @param {Form} this
6849 * @param {Action} action The action that failed
6851 actionfailed : true,
6853 * @event actioncomplete
6854 * Fires when an action is completed.
6855 * @param {Form} this
6856 * @param {Action} action The action that completed
6858 actioncomplete : true
6863 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6866 * @cfg {String} method
6867 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6872 * The URL to use for form actions if one isn't supplied in the action options.
6875 * @cfg {Boolean} fileUpload
6876 * Set to true if this form is a file upload.
6880 * @cfg {Object} baseParams
6881 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6885 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6889 * @cfg {Sting} align (left|right) for navbar forms
6894 activeAction : null,
6897 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6898 * element by passing it or its id or mask the form itself by passing in true.
6901 waitMsgTarget : false,
6905 getAutoCreate : function(){
6909 method : this.method || 'POST',
6910 id : this.id || Roo.id(),
6913 if (this.parent().xtype.match(/^Nav/)) {
6914 cfg.cls = 'navbar-form navbar-' + this.align;
6918 if (this.labelAlign == 'left' ) {
6919 cfg.cls += ' form-horizontal';
6925 initEvents : function()
6927 this.el.on('submit', this.onSubmit, this);
6928 // this was added as random key presses on the form where triggering form submit.
6929 this.el.on('keypress', function(e) {
6930 if (e.getCharCode() != 13) {
6933 // we might need to allow it for textareas.. and some other items.
6934 // check e.getTarget().
6936 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6940 Roo.log("keypress blocked");
6948 onSubmit : function(e){
6953 * Returns true if client-side validation on the form is successful.
6956 isValid : function(){
6957 var items = this.getItems();
6959 items.each(function(f){
6968 * Returns true if any fields in this form have changed since their original load.
6971 isDirty : function(){
6973 var items = this.getItems();
6974 items.each(function(f){
6984 * Performs a predefined action (submit or load) or custom actions you define on this form.
6985 * @param {String} actionName The name of the action type
6986 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6987 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6988 * accept other config options):
6990 Property Type Description
6991 ---------------- --------------- ----------------------------------------------------------------------------------
6992 url String The url for the action (defaults to the form's url)
6993 method String The form method to use (defaults to the form's method, or POST if not defined)
6994 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6995 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6996 validate the form on the client (defaults to false)
6998 * @return {BasicForm} this
7000 doAction : function(action, options){
7001 if(typeof action == 'string'){
7002 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7004 if(this.fireEvent('beforeaction', this, action) !== false){
7005 this.beforeAction(action);
7006 action.run.defer(100, action);
7012 beforeAction : function(action){
7013 var o = action.options;
7016 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7018 // not really supported yet.. ??
7020 //if(this.waitMsgTarget === true){
7021 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7022 //}else if(this.waitMsgTarget){
7023 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7024 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7026 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7032 afterAction : function(action, success){
7033 this.activeAction = null;
7034 var o = action.options;
7036 //if(this.waitMsgTarget === true){
7038 //}else if(this.waitMsgTarget){
7039 // this.waitMsgTarget.unmask();
7041 // Roo.MessageBox.updateProgress(1);
7042 // Roo.MessageBox.hide();
7049 Roo.callback(o.success, o.scope, [this, action]);
7050 this.fireEvent('actioncomplete', this, action);
7054 // failure condition..
7055 // we have a scenario where updates need confirming.
7056 // eg. if a locking scenario exists..
7057 // we look for { errors : { needs_confirm : true }} in the response.
7059 (typeof(action.result) != 'undefined') &&
7060 (typeof(action.result.errors) != 'undefined') &&
7061 (typeof(action.result.errors.needs_confirm) != 'undefined')
7064 Roo.log("not supported yet");
7067 Roo.MessageBox.confirm(
7068 "Change requires confirmation",
7069 action.result.errorMsg,
7074 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7084 Roo.callback(o.failure, o.scope, [this, action]);
7085 // show an error message if no failed handler is set..
7086 if (!this.hasListener('actionfailed')) {
7087 Roo.log("need to add dialog support");
7089 Roo.MessageBox.alert("Error",
7090 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7091 action.result.errorMsg :
7092 "Saving Failed, please check your entries or try again"
7097 this.fireEvent('actionfailed', this, action);
7102 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7103 * @param {String} id The value to search for
7106 findField : function(id){
7107 var items = this.getItems();
7108 var field = items.get(id);
7110 items.each(function(f){
7111 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7118 return field || null;
7121 * Mark fields in this form invalid in bulk.
7122 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7123 * @return {BasicForm} this
7125 markInvalid : function(errors){
7126 if(errors instanceof Array){
7127 for(var i = 0, len = errors.length; i < len; i++){
7128 var fieldError = errors[i];
7129 var f = this.findField(fieldError.id);
7131 f.markInvalid(fieldError.msg);
7137 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7138 field.markInvalid(errors[id]);
7142 //Roo.each(this.childForms || [], function (f) {
7143 // f.markInvalid(errors);
7150 * Set values for fields in this form in bulk.
7151 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7152 * @return {BasicForm} this
7154 setValues : function(values){
7155 if(values instanceof Array){ // array of objects
7156 for(var i = 0, len = values.length; i < len; i++){
7158 var f = this.findField(v.id);
7160 f.setValue(v.value);
7161 if(this.trackResetOnLoad){
7162 f.originalValue = f.getValue();
7166 }else{ // object hash
7169 if(typeof values[id] != 'function' && (field = this.findField(id))){
7171 if (field.setFromData &&
7173 field.displayField &&
7174 // combos' with local stores can
7175 // be queried via setValue()
7176 // to set their value..
7177 (field.store && !field.store.isLocal)
7181 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7182 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7183 field.setFromData(sd);
7186 field.setValue(values[id]);
7190 if(this.trackResetOnLoad){
7191 field.originalValue = field.getValue();
7197 //Roo.each(this.childForms || [], function (f) {
7198 // f.setValues(values);
7205 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7206 * they are returned as an array.
7207 * @param {Boolean} asString
7210 getValues : function(asString){
7211 //if (this.childForms) {
7212 // copy values from the child forms
7213 // Roo.each(this.childForms, function (f) {
7214 // this.setValues(f.getValues());
7220 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7221 if(asString === true){
7224 return Roo.urlDecode(fs);
7228 * Returns the fields in this form as an object with key/value pairs.
7229 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7232 getFieldValues : function(with_hidden)
7234 var items = this.getItems();
7236 items.each(function(f){
7240 var v = f.getValue();
7241 if (f.inputType =='radio') {
7242 if (typeof(ret[f.getName()]) == 'undefined') {
7243 ret[f.getName()] = ''; // empty..
7246 if (!f.el.dom.checked) {
7254 // not sure if this supported any more..
7255 if ((typeof(v) == 'object') && f.getRawValue) {
7256 v = f.getRawValue() ; // dates..
7258 // combo boxes where name != hiddenName...
7259 if (f.name != f.getName()) {
7260 ret[f.name] = f.getRawValue();
7262 ret[f.getName()] = v;
7269 * Clears all invalid messages in this form.
7270 * @return {BasicForm} this
7272 clearInvalid : function(){
7273 var items = this.getItems();
7275 items.each(function(f){
7286 * @return {BasicForm} this
7289 var items = this.getItems();
7290 items.each(function(f){
7294 Roo.each(this.childForms || [], function (f) {
7301 getItems : function()
7303 var r=new Roo.util.MixedCollection(false, function(o){
7304 return o.id || (o.id = Roo.id());
7306 var iter = function(el) {
7313 Roo.each(el.items,function(e) {
7333 * Ext JS Library 1.1.1
7334 * Copyright(c) 2006-2007, Ext JS, LLC.
7336 * Originally Released Under LGPL - original licence link has changed is not relivant.
7339 * <script type="text/javascript">
7342 * @class Roo.form.VTypes
7343 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7346 Roo.form.VTypes = function(){
7347 // closure these in so they are only created once.
7348 var alpha = /^[a-zA-Z_]+$/;
7349 var alphanum = /^[a-zA-Z0-9_]+$/;
7350 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7351 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7353 // All these messages and functions are configurable
7356 * The function used to validate email addresses
7357 * @param {String} value The email address
7359 'email' : function(v){
7360 return email.test(v);
7363 * The error text to display when the email validation function returns false
7366 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7368 * The keystroke filter mask to be applied on email input
7371 'emailMask' : /[a-z0-9_\.\-@]/i,
7374 * The function used to validate URLs
7375 * @param {String} value The URL
7377 'url' : function(v){
7381 * The error text to display when the url validation function returns false
7384 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7387 * The function used to validate alpha values
7388 * @param {String} value The value
7390 'alpha' : function(v){
7391 return alpha.test(v);
7394 * The error text to display when the alpha validation function returns false
7397 'alphaText' : 'This field should only contain letters and _',
7399 * The keystroke filter mask to be applied on alpha input
7402 'alphaMask' : /[a-z_]/i,
7405 * The function used to validate alphanumeric values
7406 * @param {String} value The value
7408 'alphanum' : function(v){
7409 return alphanum.test(v);
7412 * The error text to display when the alphanumeric validation function returns false
7415 'alphanumText' : 'This field should only contain letters, numbers and _',
7417 * The keystroke filter mask to be applied on alphanumeric input
7420 'alphanumMask' : /[a-z0-9_]/i
7430 * @class Roo.bootstrap.Input
7431 * @extends Roo.bootstrap.Component
7432 * Bootstrap Input class
7433 * @cfg {Boolean} disabled is it disabled
7434 * @cfg {String} fieldLabel - the label associated
7435 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7436 * @cfg {String} name name of the input
7437 * @cfg {string} fieldLabel - the label associated
7438 * @cfg {string} inputType - input / file submit ...
7439 * @cfg {string} placeholder - placeholder to put in text.
7440 * @cfg {string} before - input group add on before
7441 * @cfg {string} after - input group add on after
7442 * @cfg {string} size - (lg|sm) or leave empty..
7443 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7444 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7445 * @cfg {Number} md colspan out of 12 for computer-sized screens
7446 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7447 * @cfg {string} value default value of the input
7448 * @cfg {Number} labelWidth set the width of label (0-12)
7449 * @cfg {String} labelAlign (top|left)
7450 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7451 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7453 * @cfg {String} align (left|center|right) Default left
7458 * Create a new Input
7459 * @param {Object} config The config object
7462 Roo.bootstrap.Input = function(config){
7463 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7468 * Fires when this field receives input focus.
7469 * @param {Roo.form.Field} this
7474 * Fires when this field loses input focus.
7475 * @param {Roo.form.Field} this
7480 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7481 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7482 * @param {Roo.form.Field} this
7483 * @param {Roo.EventObject} e The event object
7488 * Fires just before the field blurs if the field value has changed.
7489 * @param {Roo.form.Field} this
7490 * @param {Mixed} newValue The new value
7491 * @param {Mixed} oldValue The original value
7496 * Fires after the field has been marked as invalid.
7497 * @param {Roo.form.Field} this
7498 * @param {String} msg The validation message
7503 * Fires after the field has been validated with no errors.
7504 * @param {Roo.form.Field} this
7509 * Fires after the key up
7510 * @param {Roo.form.Field} this
7511 * @param {Roo.EventObject} e The event Object
7517 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7519 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7520 automatic validation (defaults to "keyup").
7522 validationEvent : "keyup",
7524 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7526 validateOnBlur : true,
7528 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7530 validationDelay : 250,
7532 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7534 focusClass : "x-form-focus", // not needed???
7538 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7540 invalidClass : "has-warning",
7543 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7545 validClass : "has-success",
7548 * @cfg {Boolean} hasFeedback (true|false) default true
7553 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7555 invalidFeedbackClass : "glyphicon-warning-sign",
7558 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7560 validFeedbackClass : "glyphicon-ok",
7563 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7565 selectOnFocus : false,
7568 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7572 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7577 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7579 disableKeyFilter : false,
7582 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7586 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7590 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7592 blankText : "This field is required",
7595 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7599 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7601 maxLength : Number.MAX_VALUE,
7603 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7605 minLengthText : "The minimum length for this field is {0}",
7607 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7609 maxLengthText : "The maximum length for this field is {0}",
7613 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7614 * If available, this function will be called only after the basic validators all return true, and will be passed the
7615 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7619 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7620 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7621 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7625 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7629 autocomplete: false,
7648 formatedValue : false,
7650 parentLabelAlign : function()
7653 while (parent.parent()) {
7654 parent = parent.parent();
7655 if (typeof(parent.labelAlign) !='undefined') {
7656 return parent.labelAlign;
7663 getAutoCreate : function(){
7665 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7671 if(this.inputType != 'hidden'){
7672 cfg.cls = 'form-group' //input-group
7678 type : this.inputType,
7680 cls : 'form-control',
7681 placeholder : this.placeholder || '',
7682 autocomplete : this.autocomplete || 'new-password'
7687 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7690 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7691 input.maxLength = this.maxLength;
7694 if (this.disabled) {
7695 input.disabled=true;
7698 if (this.readOnly) {
7699 input.readonly=true;
7703 input.name = this.name;
7706 input.cls += ' input-' + this.size;
7709 ['xs','sm','md','lg'].map(function(size){
7710 if (settings[size]) {
7711 cfg.cls += ' col-' + size + '-' + settings[size];
7715 var inputblock = input;
7719 cls: 'glyphicon form-control-feedback'
7722 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7725 cls : 'has-feedback',
7733 if (this.before || this.after) {
7736 cls : 'input-group',
7740 if (this.before && typeof(this.before) == 'string') {
7742 inputblock.cn.push({
7744 cls : 'roo-input-before input-group-addon',
7748 if (this.before && typeof(this.before) == 'object') {
7749 this.before = Roo.factory(this.before);
7750 Roo.log(this.before);
7751 inputblock.cn.push({
7753 cls : 'roo-input-before input-group-' +
7754 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7758 inputblock.cn.push(input);
7760 if (this.after && typeof(this.after) == 'string') {
7761 inputblock.cn.push({
7763 cls : 'roo-input-after input-group-addon',
7767 if (this.after && typeof(this.after) == 'object') {
7768 this.after = Roo.factory(this.after);
7769 Roo.log(this.after);
7770 inputblock.cn.push({
7772 cls : 'roo-input-after input-group-' +
7773 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7777 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7778 inputblock.cls += ' has-feedback';
7779 inputblock.cn.push(feedback);
7783 if (align ==='left' && this.fieldLabel.length) {
7784 Roo.log("left and has label");
7790 cls : 'control-label col-sm-' + this.labelWidth,
7791 html : this.fieldLabel
7795 cls : "col-sm-" + (12 - this.labelWidth),
7802 } else if ( this.fieldLabel.length) {
7808 //cls : 'input-group-addon',
7809 html : this.fieldLabel
7819 Roo.log(" no label && no align");
7828 Roo.log('input-parentType: ' + this.parentType);
7830 if (this.parentType === 'Navbar' && this.parent().bar) {
7831 cfg.cls += ' navbar-form';
7839 * return the real input element.
7841 inputEl: function ()
7843 return this.el.select('input.form-control',true).first();
7846 tooltipEl : function()
7848 return this.inputEl();
7851 setDisabled : function(v)
7853 var i = this.inputEl().dom;
7855 i.removeAttribute('disabled');
7859 i.setAttribute('disabled','true');
7861 initEvents : function()
7864 this.inputEl().on("keydown" , this.fireKey, this);
7865 this.inputEl().on("focus", this.onFocus, this);
7866 this.inputEl().on("blur", this.onBlur, this);
7868 this.inputEl().relayEvent('keyup', this);
7870 // reference to original value for reset
7871 this.originalValue = this.getValue();
7872 //Roo.form.TextField.superclass.initEvents.call(this);
7873 if(this.validationEvent == 'keyup'){
7874 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7875 this.inputEl().on('keyup', this.filterValidation, this);
7877 else if(this.validationEvent !== false){
7878 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7881 if(this.selectOnFocus){
7882 this.on("focus", this.preFocus, this);
7885 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7886 this.inputEl().on("keypress", this.filterKeys, this);
7889 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7890 this.el.on("click", this.autoSize, this);
7893 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7894 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7897 if (typeof(this.before) == 'object') {
7898 this.before.render(this.el.select('.roo-input-before',true).first());
7900 if (typeof(this.after) == 'object') {
7901 this.after.render(this.el.select('.roo-input-after',true).first());
7906 filterValidation : function(e){
7907 if(!e.isNavKeyPress()){
7908 this.validationTask.delay(this.validationDelay);
7912 * Validates the field value
7913 * @return {Boolean} True if the value is valid, else false
7915 validate : function(){
7916 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7917 if(this.disabled || this.validateValue(this.getRawValue())){
7928 * Validates a value according to the field's validation rules and marks the field as invalid
7929 * if the validation fails
7930 * @param {Mixed} value The value to validate
7931 * @return {Boolean} True if the value is valid, else false
7933 validateValue : function(value){
7934 if(value.length < 1) { // if it's blank
7935 if(this.allowBlank){
7941 if(value.length < this.minLength){
7944 if(value.length > this.maxLength){
7948 var vt = Roo.form.VTypes;
7949 if(!vt[this.vtype](value, this)){
7953 if(typeof this.validator == "function"){
7954 var msg = this.validator(value);
7960 if(this.regex && !this.regex.test(value)){
7970 fireKey : function(e){
7971 //Roo.log('field ' + e.getKey());
7972 if(e.isNavKeyPress()){
7973 this.fireEvent("specialkey", this, e);
7976 focus : function (selectText){
7978 this.inputEl().focus();
7979 if(selectText === true){
7980 this.inputEl().dom.select();
7986 onFocus : function(){
7987 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7988 // this.el.addClass(this.focusClass);
7991 this.hasFocus = true;
7992 this.startValue = this.getValue();
7993 this.fireEvent("focus", this);
7997 beforeBlur : Roo.emptyFn,
8001 onBlur : function(){
8003 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8004 //this.el.removeClass(this.focusClass);
8006 this.hasFocus = false;
8007 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8010 var v = this.getValue();
8011 if(String(v) !== String(this.startValue)){
8012 this.fireEvent('change', this, v, this.startValue);
8014 this.fireEvent("blur", this);
8018 * Resets the current field value to the originally loaded value and clears any validation messages
8021 this.setValue(this.originalValue);
8025 * Returns the name of the field
8026 * @return {Mixed} name The name field
8028 getName: function(){
8032 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8033 * @return {Mixed} value The field value
8035 getValue : function(){
8037 var v = this.inputEl().getValue();
8042 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8043 * @return {Mixed} value The field value
8045 getRawValue : function(){
8046 var v = this.inputEl().getValue();
8052 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8053 * @param {Mixed} value The value to set
8055 setRawValue : function(v){
8056 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8059 selectText : function(start, end){
8060 var v = this.getRawValue();
8062 start = start === undefined ? 0 : start;
8063 end = end === undefined ? v.length : end;
8064 var d = this.inputEl().dom;
8065 if(d.setSelectionRange){
8066 d.setSelectionRange(start, end);
8067 }else if(d.createTextRange){
8068 var range = d.createTextRange();
8069 range.moveStart("character", start);
8070 range.moveEnd("character", v.length-end);
8077 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8078 * @param {Mixed} value The value to set
8080 setValue : function(v){
8083 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8089 processValue : function(value){
8090 if(this.stripCharsRe){
8091 var newValue = value.replace(this.stripCharsRe, '');
8092 if(newValue !== value){
8093 this.setRawValue(newValue);
8100 preFocus : function(){
8102 if(this.selectOnFocus){
8103 this.inputEl().dom.select();
8106 filterKeys : function(e){
8108 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8111 var c = e.getCharCode(), cc = String.fromCharCode(c);
8112 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8115 if(!this.maskRe.test(cc)){
8120 * Clear any invalid styles/messages for this field
8122 clearInvalid : function(){
8124 if(!this.el || this.preventMark){ // not rendered
8127 this.el.removeClass(this.invalidClass);
8129 this.fireEvent('valid', this);
8133 * Mark this field as valid
8135 markValid : function(){
8136 if(!this.el || this.preventMark){ // not rendered
8140 this.el.removeClass([this.invalidClass, this.validClass]);
8142 if(this.disabled || this.allowBlank){
8146 this.el.addClass(this.validClass);
8148 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8150 var feedback = this.el.select('.form-control-feedback', true).first();
8153 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8154 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8159 this.fireEvent('valid', this);
8163 * Mark this field as invalid
8164 * @param {String} msg The validation message
8166 markInvalid : function(msg){
8167 if(!this.el || this.preventMark){ // not rendered
8171 this.el.removeClass([this.invalidClass, this.validClass]);
8173 if(this.disabled || this.allowBlank){
8177 this.el.addClass(this.invalidClass);
8179 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8181 var feedback = this.el.select('.form-control-feedback', true).first();
8184 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8186 if(this.getValue().length){
8187 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8194 this.fireEvent('invalid', this, msg);
8197 SafariOnKeyDown : function(event)
8199 // this is a workaround for a password hang bug on chrome/ webkit.
8201 var isSelectAll = false;
8203 if(this.inputEl().dom.selectionEnd > 0){
8204 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8206 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8207 event.preventDefault();
8212 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8214 event.preventDefault();
8215 // this is very hacky as keydown always get's upper case.
8217 var cc = String.fromCharCode(event.getCharCode());
8218 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8222 adjustWidth : function(tag, w){
8223 tag = tag.toLowerCase();
8224 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8225 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8229 if(tag == 'textarea'){
8232 }else if(Roo.isOpera){
8236 if(tag == 'textarea'){
8255 * @class Roo.bootstrap.TextArea
8256 * @extends Roo.bootstrap.Input
8257 * Bootstrap TextArea class
8258 * @cfg {Number} cols Specifies the visible width of a text area
8259 * @cfg {Number} rows Specifies the visible number of lines in a text area
8260 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8261 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8262 * @cfg {string} html text
8265 * Create a new TextArea
8266 * @param {Object} config The config object
8269 Roo.bootstrap.TextArea = function(config){
8270 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8274 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8284 getAutoCreate : function(){
8286 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8297 value : this.value || '',
8298 html: this.html || '',
8299 cls : 'form-control',
8300 placeholder : this.placeholder || ''
8304 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8305 input.maxLength = this.maxLength;
8309 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8313 input.cols = this.cols;
8316 if (this.readOnly) {
8317 input.readonly = true;
8321 input.name = this.name;
8325 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8329 ['xs','sm','md','lg'].map(function(size){
8330 if (settings[size]) {
8331 cfg.cls += ' col-' + size + '-' + settings[size];
8335 var inputblock = input;
8337 if(this.hasFeedback && !this.allowBlank){
8341 cls: 'glyphicon form-control-feedback'
8345 cls : 'has-feedback',
8354 if (this.before || this.after) {
8357 cls : 'input-group',
8361 inputblock.cn.push({
8363 cls : 'input-group-addon',
8368 inputblock.cn.push(input);
8370 if(this.hasFeedback && !this.allowBlank){
8371 inputblock.cls += ' has-feedback';
8372 inputblock.cn.push(feedback);
8376 inputblock.cn.push({
8378 cls : 'input-group-addon',
8385 if (align ==='left' && this.fieldLabel.length) {
8386 Roo.log("left and has label");
8392 cls : 'control-label col-sm-' + this.labelWidth,
8393 html : this.fieldLabel
8397 cls : "col-sm-" + (12 - this.labelWidth),
8404 } else if ( this.fieldLabel.length) {
8410 //cls : 'input-group-addon',
8411 html : this.fieldLabel
8421 Roo.log(" no label && no align");
8431 if (this.disabled) {
8432 input.disabled=true;
8439 * return the real textarea element.
8441 inputEl: function ()
8443 return this.el.select('textarea.form-control',true).first();
8451 * trigger field - base class for combo..
8456 * @class Roo.bootstrap.TriggerField
8457 * @extends Roo.bootstrap.Input
8458 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8459 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8460 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8461 * for which you can provide a custom implementation. For example:
8463 var trigger = new Roo.bootstrap.TriggerField();
8464 trigger.onTriggerClick = myTriggerFn;
8465 trigger.applyTo('my-field');
8468 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8469 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8470 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8471 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8472 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8475 * Create a new TriggerField.
8476 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8477 * to the base TextField)
8479 Roo.bootstrap.TriggerField = function(config){
8480 this.mimicing = false;
8481 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8484 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8486 * @cfg {String} triggerClass A CSS class to apply to the trigger
8489 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8494 * @cfg {Boolean} removable (true|false) special filter default false
8498 /** @cfg {Boolean} grow @hide */
8499 /** @cfg {Number} growMin @hide */
8500 /** @cfg {Number} growMax @hide */
8506 autoSize: Roo.emptyFn,
8513 actionMode : 'wrap',
8518 getAutoCreate : function(){
8520 var align = this.labelAlign || this.parentLabelAlign();
8525 cls: 'form-group' //input-group
8532 type : this.inputType,
8533 cls : 'form-control',
8534 autocomplete: 'new-password',
8535 placeholder : this.placeholder || ''
8539 input.name = this.name;
8542 input.cls += ' input-' + this.size;
8545 if (this.disabled) {
8546 input.disabled=true;
8549 var inputblock = input;
8551 if(this.hasFeedback && !this.allowBlank){
8555 cls: 'glyphicon form-control-feedback'
8558 if(this.removable && !this.editable && !this.tickable){
8560 cls : 'has-feedback',
8566 cls : 'roo-combo-removable-btn close'
8573 cls : 'has-feedback',
8582 if(this.removable && !this.editable && !this.tickable){
8584 cls : 'roo-removable',
8590 cls : 'roo-combo-removable-btn close'
8597 if (this.before || this.after) {
8600 cls : 'input-group',
8604 inputblock.cn.push({
8606 cls : 'input-group-addon',
8611 inputblock.cn.push(input);
8613 if(this.hasFeedback && !this.allowBlank){
8614 inputblock.cls += ' has-feedback';
8615 inputblock.cn.push(feedback);
8619 inputblock.cn.push({
8621 cls : 'input-group-addon',
8634 cls: 'form-hidden-field'
8642 Roo.log('multiple');
8650 cls: 'form-hidden-field'
8654 cls: 'select2-choices',
8658 cls: 'select2-search-field',
8671 cls: 'select2-container input-group',
8676 // cls: 'typeahead typeahead-long dropdown-menu',
8677 // style: 'display:none'
8682 if(!this.multiple && this.showToggleBtn){
8688 if (this.caret != false) {
8691 cls: 'fa fa-' + this.caret
8698 cls : 'input-group-addon btn dropdown-toggle',
8703 cls: 'combobox-clear',
8717 combobox.cls += ' select2-container-multi';
8720 if (align ==='left' && this.fieldLabel.length) {
8722 Roo.log("left and has label");
8728 cls : 'control-label col-sm-' + this.labelWidth,
8729 html : this.fieldLabel
8733 cls : "col-sm-" + (12 - this.labelWidth),
8740 } else if ( this.fieldLabel.length) {
8746 //cls : 'input-group-addon',
8747 html : this.fieldLabel
8757 Roo.log(" no label && no align");
8764 ['xs','sm','md','lg'].map(function(size){
8765 if (settings[size]) {
8766 cfg.cls += ' col-' + size + '-' + settings[size];
8777 onResize : function(w, h){
8778 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8779 // if(typeof w == 'number'){
8780 // var x = w - this.trigger.getWidth();
8781 // this.inputEl().setWidth(this.adjustWidth('input', x));
8782 // this.trigger.setStyle('left', x+'px');
8787 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8790 getResizeEl : function(){
8791 return this.inputEl();
8795 getPositionEl : function(){
8796 return this.inputEl();
8800 alignErrorIcon : function(){
8801 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8805 initEvents : function(){
8809 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8810 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8811 if(!this.multiple && this.showToggleBtn){
8812 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8813 if(this.hideTrigger){
8814 this.trigger.setDisplayed(false);
8816 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8820 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8823 if(this.removable && !this.editable && !this.tickable){
8824 var close = this.closeTriggerEl();
8827 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8828 close.on('click', this.removeBtnClick, this, close);
8832 //this.trigger.addClassOnOver('x-form-trigger-over');
8833 //this.trigger.addClassOnClick('x-form-trigger-click');
8836 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8840 closeTriggerEl : function()
8842 var close = this.el.select('.roo-combo-removable-btn', true).first();
8843 return close ? close : false;
8846 removeBtnClick : function(e, h, el)
8850 this.fireEvent("remove", this);
8853 createList : function()
8855 this.list = Roo.get(document.body).createChild({
8857 cls: 'typeahead typeahead-long dropdown-menu',
8858 style: 'display:none'
8861 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8866 initTrigger : function(){
8871 onDestroy : function(){
8873 this.trigger.removeAllListeners();
8874 // this.trigger.remove();
8877 // this.wrap.remove();
8879 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8883 onFocus : function(){
8884 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8887 this.wrap.addClass('x-trigger-wrap-focus');
8888 this.mimicing = true;
8889 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8890 if(this.monitorTab){
8891 this.el.on("keydown", this.checkTab, this);
8898 checkTab : function(e){
8899 if(e.getKey() == e.TAB){
8905 onBlur : function(){
8910 mimicBlur : function(e, t){
8912 if(!this.wrap.contains(t) && this.validateBlur()){
8919 triggerBlur : function(){
8920 this.mimicing = false;
8921 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8922 if(this.monitorTab){
8923 this.el.un("keydown", this.checkTab, this);
8925 //this.wrap.removeClass('x-trigger-wrap-focus');
8926 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8930 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8931 validateBlur : function(e, t){
8936 onDisable : function(){
8937 this.inputEl().dom.disabled = true;
8938 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8940 // this.wrap.addClass('x-item-disabled');
8945 onEnable : function(){
8946 this.inputEl().dom.disabled = false;
8947 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8949 // this.el.removeClass('x-item-disabled');
8954 onShow : function(){
8955 var ae = this.getActionEl();
8958 ae.dom.style.display = '';
8959 ae.dom.style.visibility = 'visible';
8965 onHide : function(){
8966 var ae = this.getActionEl();
8967 ae.dom.style.display = 'none';
8971 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8972 * by an implementing function.
8974 * @param {EventObject} e
8976 onTriggerClick : Roo.emptyFn
8980 * Ext JS Library 1.1.1
8981 * Copyright(c) 2006-2007, Ext JS, LLC.
8983 * Originally Released Under LGPL - original licence link has changed is not relivant.
8986 * <script type="text/javascript">
8991 * @class Roo.data.SortTypes
8993 * Defines the default sorting (casting?) comparison functions used when sorting data.
8995 Roo.data.SortTypes = {
8997 * Default sort that does nothing
8998 * @param {Mixed} s The value being converted
8999 * @return {Mixed} The comparison value
9006 * The regular expression used to strip tags
9010 stripTagsRE : /<\/?[^>]+>/gi,
9013 * Strips all HTML tags to sort on text only
9014 * @param {Mixed} s The value being converted
9015 * @return {String} The comparison value
9017 asText : function(s){
9018 return String(s).replace(this.stripTagsRE, "");
9022 * Strips all HTML tags to sort on text only - Case insensitive
9023 * @param {Mixed} s The value being converted
9024 * @return {String} The comparison value
9026 asUCText : function(s){
9027 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9031 * Case insensitive string
9032 * @param {Mixed} s The value being converted
9033 * @return {String} The comparison value
9035 asUCString : function(s) {
9036 return String(s).toUpperCase();
9041 * @param {Mixed} s The value being converted
9042 * @return {Number} The comparison value
9044 asDate : function(s) {
9048 if(s instanceof Date){
9051 return Date.parse(String(s));
9056 * @param {Mixed} s The value being converted
9057 * @return {Float} The comparison value
9059 asFloat : function(s) {
9060 var val = parseFloat(String(s).replace(/,/g, ""));
9061 if(isNaN(val)) val = 0;
9067 * @param {Mixed} s The value being converted
9068 * @return {Number} The comparison value
9070 asInt : function(s) {
9071 var val = parseInt(String(s).replace(/,/g, ""));
9072 if(isNaN(val)) val = 0;
9077 * Ext JS Library 1.1.1
9078 * Copyright(c) 2006-2007, Ext JS, LLC.
9080 * Originally Released Under LGPL - original licence link has changed is not relivant.
9083 * <script type="text/javascript">
9087 * @class Roo.data.Record
9088 * Instances of this class encapsulate both record <em>definition</em> information, and record
9089 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9090 * to access Records cached in an {@link Roo.data.Store} object.<br>
9092 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9093 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9096 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9098 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9099 * {@link #create}. The parameters are the same.
9100 * @param {Array} data An associative Array of data values keyed by the field name.
9101 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9102 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9103 * not specified an integer id is generated.
9105 Roo.data.Record = function(data, id){
9106 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9111 * Generate a constructor for a specific record layout.
9112 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9113 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9114 * Each field definition object may contain the following properties: <ul>
9115 * <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,
9116 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9117 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9118 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9119 * is being used, then this is a string containing the javascript expression to reference the data relative to
9120 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9121 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9122 * this may be omitted.</p></li>
9123 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9124 * <ul><li>auto (Default, implies no conversion)</li>
9129 * <li>date</li></ul></p></li>
9130 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9131 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9132 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9133 * by the Reader into an object that will be stored in the Record. It is passed the
9134 * following parameters:<ul>
9135 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9137 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9139 * <br>usage:<br><pre><code>
9140 var TopicRecord = Roo.data.Record.create(
9141 {name: 'title', mapping: 'topic_title'},
9142 {name: 'author', mapping: 'username'},
9143 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9144 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9145 {name: 'lastPoster', mapping: 'user2'},
9146 {name: 'excerpt', mapping: 'post_text'}
9149 var myNewRecord = new TopicRecord({
9150 title: 'Do my job please',
9153 lastPost: new Date(),
9154 lastPoster: 'Animal',
9155 excerpt: 'No way dude!'
9157 myStore.add(myNewRecord);
9162 Roo.data.Record.create = function(o){
9164 f.superclass.constructor.apply(this, arguments);
9166 Roo.extend(f, Roo.data.Record);
9167 var p = f.prototype;
9168 p.fields = new Roo.util.MixedCollection(false, function(field){
9171 for(var i = 0, len = o.length; i < len; i++){
9172 p.fields.add(new Roo.data.Field(o[i]));
9174 f.getField = function(name){
9175 return p.fields.get(name);
9180 Roo.data.Record.AUTO_ID = 1000;
9181 Roo.data.Record.EDIT = 'edit';
9182 Roo.data.Record.REJECT = 'reject';
9183 Roo.data.Record.COMMIT = 'commit';
9185 Roo.data.Record.prototype = {
9187 * Readonly flag - true if this record has been modified.
9196 join : function(store){
9201 * Set the named field to the specified value.
9202 * @param {String} name The name of the field to set.
9203 * @param {Object} value The value to set the field to.
9205 set : function(name, value){
9206 if(this.data[name] == value){
9213 if(typeof this.modified[name] == 'undefined'){
9214 this.modified[name] = this.data[name];
9216 this.data[name] = value;
9217 if(!this.editing && this.store){
9218 this.store.afterEdit(this);
9223 * Get the value of the named field.
9224 * @param {String} name The name of the field to get the value of.
9225 * @return {Object} The value of the field.
9227 get : function(name){
9228 return this.data[name];
9232 beginEdit : function(){
9233 this.editing = true;
9238 cancelEdit : function(){
9239 this.editing = false;
9240 delete this.modified;
9244 endEdit : function(){
9245 this.editing = false;
9246 if(this.dirty && this.store){
9247 this.store.afterEdit(this);
9252 * Usually called by the {@link Roo.data.Store} which owns the Record.
9253 * Rejects all changes made to the Record since either creation, or the last commit operation.
9254 * Modified fields are reverted to their original values.
9256 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9257 * of reject operations.
9259 reject : function(){
9260 var m = this.modified;
9262 if(typeof m[n] != "function"){
9263 this.data[n] = m[n];
9267 delete this.modified;
9268 this.editing = false;
9270 this.store.afterReject(this);
9275 * Usually called by the {@link Roo.data.Store} which owns the Record.
9276 * Commits all changes made to the Record since either creation, or the last commit operation.
9278 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9279 * of commit operations.
9281 commit : function(){
9283 delete this.modified;
9284 this.editing = false;
9286 this.store.afterCommit(this);
9291 hasError : function(){
9292 return this.error != null;
9296 clearError : function(){
9301 * Creates a copy of this record.
9302 * @param {String} id (optional) A new record id if you don't want to use this record's id
9305 copy : function(newId) {
9306 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9310 * Ext JS Library 1.1.1
9311 * Copyright(c) 2006-2007, Ext JS, LLC.
9313 * Originally Released Under LGPL - original licence link has changed is not relivant.
9316 * <script type="text/javascript">
9322 * @class Roo.data.Store
9323 * @extends Roo.util.Observable
9324 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9325 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9327 * 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
9328 * has no knowledge of the format of the data returned by the Proxy.<br>
9330 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9331 * instances from the data object. These records are cached and made available through accessor functions.
9333 * Creates a new Store.
9334 * @param {Object} config A config object containing the objects needed for the Store to access data,
9335 * and read the data into Records.
9337 Roo.data.Store = function(config){
9338 this.data = new Roo.util.MixedCollection(false);
9339 this.data.getKey = function(o){
9342 this.baseParams = {};
9349 "multisort" : "_multisort"
9352 if(config && config.data){
9353 this.inlineData = config.data;
9357 Roo.apply(this, config);
9359 if(this.reader){ // reader passed
9360 this.reader = Roo.factory(this.reader, Roo.data);
9361 this.reader.xmodule = this.xmodule || false;
9362 if(!this.recordType){
9363 this.recordType = this.reader.recordType;
9365 if(this.reader.onMetaChange){
9366 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9370 if(this.recordType){
9371 this.fields = this.recordType.prototype.fields;
9377 * @event datachanged
9378 * Fires when the data cache has changed, and a widget which is using this Store
9379 * as a Record cache should refresh its view.
9380 * @param {Store} this
9385 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9386 * @param {Store} this
9387 * @param {Object} meta The JSON metadata
9392 * Fires when Records have been added to the Store
9393 * @param {Store} this
9394 * @param {Roo.data.Record[]} records The array of Records added
9395 * @param {Number} index The index at which the record(s) were added
9400 * Fires when a Record has been removed from the Store
9401 * @param {Store} this
9402 * @param {Roo.data.Record} record The Record that was removed
9403 * @param {Number} index The index at which the record was removed
9408 * Fires when a Record has been updated
9409 * @param {Store} this
9410 * @param {Roo.data.Record} record The Record that was updated
9411 * @param {String} operation The update operation being performed. Value may be one of:
9413 Roo.data.Record.EDIT
9414 Roo.data.Record.REJECT
9415 Roo.data.Record.COMMIT
9421 * Fires when the data cache has been cleared.
9422 * @param {Store} this
9427 * Fires before a request is made for a new data object. If the beforeload handler returns false
9428 * the load action will be canceled.
9429 * @param {Store} this
9430 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9434 * @event beforeloadadd
9435 * Fires after a new set of Records has been loaded.
9436 * @param {Store} this
9437 * @param {Roo.data.Record[]} records The Records that were loaded
9438 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9440 beforeloadadd : true,
9443 * Fires after a new set of Records has been loaded, before they are added to the store.
9444 * @param {Store} this
9445 * @param {Roo.data.Record[]} records The Records that were loaded
9446 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9447 * @params {Object} return from reader
9451 * @event loadexception
9452 * Fires if an exception occurs in the Proxy during loading.
9453 * Called with the signature of the Proxy's "loadexception" event.
9454 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9457 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9458 * @param {Object} load options
9459 * @param {Object} jsonData from your request (normally this contains the Exception)
9461 loadexception : true
9465 this.proxy = Roo.factory(this.proxy, Roo.data);
9466 this.proxy.xmodule = this.xmodule || false;
9467 this.relayEvents(this.proxy, ["loadexception"]);
9469 this.sortToggle = {};
9470 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9472 Roo.data.Store.superclass.constructor.call(this);
9474 if(this.inlineData){
9475 this.loadData(this.inlineData);
9476 delete this.inlineData;
9480 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9482 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9483 * without a remote query - used by combo/forms at present.
9487 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9490 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9493 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9494 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9497 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9498 * on any HTTP request
9501 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9504 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9508 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9509 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9514 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9515 * loaded or when a record is removed. (defaults to false).
9517 pruneModifiedRecords : false,
9523 * Add Records to the Store and fires the add event.
9524 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9526 add : function(records){
9527 records = [].concat(records);
9528 for(var i = 0, len = records.length; i < len; i++){
9529 records[i].join(this);
9531 var index = this.data.length;
9532 this.data.addAll(records);
9533 this.fireEvent("add", this, records, index);
9537 * Remove a Record from the Store and fires the remove event.
9538 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9540 remove : function(record){
9541 var index = this.data.indexOf(record);
9542 this.data.removeAt(index);
9543 if(this.pruneModifiedRecords){
9544 this.modified.remove(record);
9546 this.fireEvent("remove", this, record, index);
9550 * Remove all Records from the Store and fires the clear event.
9552 removeAll : function(){
9554 if(this.pruneModifiedRecords){
9557 this.fireEvent("clear", this);
9561 * Inserts Records to the Store at the given index and fires the add event.
9562 * @param {Number} index The start index at which to insert the passed Records.
9563 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9565 insert : function(index, records){
9566 records = [].concat(records);
9567 for(var i = 0, len = records.length; i < len; i++){
9568 this.data.insert(index, records[i]);
9569 records[i].join(this);
9571 this.fireEvent("add", this, records, index);
9575 * Get the index within the cache of the passed Record.
9576 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9577 * @return {Number} The index of the passed Record. Returns -1 if not found.
9579 indexOf : function(record){
9580 return this.data.indexOf(record);
9584 * Get the index within the cache of the Record with the passed id.
9585 * @param {String} id The id of the Record to find.
9586 * @return {Number} The index of the Record. Returns -1 if not found.
9588 indexOfId : function(id){
9589 return this.data.indexOfKey(id);
9593 * Get the Record with the specified id.
9594 * @param {String} id The id of the Record to find.
9595 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9597 getById : function(id){
9598 return this.data.key(id);
9602 * Get the Record at the specified index.
9603 * @param {Number} index The index of the Record to find.
9604 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9606 getAt : function(index){
9607 return this.data.itemAt(index);
9611 * Returns a range of Records between specified indices.
9612 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9613 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9614 * @return {Roo.data.Record[]} An array of Records
9616 getRange : function(start, end){
9617 return this.data.getRange(start, end);
9621 storeOptions : function(o){
9622 o = Roo.apply({}, o);
9625 this.lastOptions = o;
9629 * Loads the Record cache from the configured Proxy using the configured Reader.
9631 * If using remote paging, then the first load call must specify the <em>start</em>
9632 * and <em>limit</em> properties in the options.params property to establish the initial
9633 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9635 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9636 * and this call will return before the new data has been loaded. Perform any post-processing
9637 * in a callback function, or in a "load" event handler.</strong>
9639 * @param {Object} options An object containing properties which control loading options:<ul>
9640 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9641 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9642 * passed the following arguments:<ul>
9643 * <li>r : Roo.data.Record[]</li>
9644 * <li>options: Options object from the load call</li>
9645 * <li>success: Boolean success indicator</li></ul></li>
9646 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9647 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9650 load : function(options){
9651 options = options || {};
9652 if(this.fireEvent("beforeload", this, options) !== false){
9653 this.storeOptions(options);
9654 var p = Roo.apply(options.params || {}, this.baseParams);
9655 // if meta was not loaded from remote source.. try requesting it.
9656 if (!this.reader.metaFromRemote) {
9659 if(this.sortInfo && this.remoteSort){
9660 var pn = this.paramNames;
9661 p[pn["sort"]] = this.sortInfo.field;
9662 p[pn["dir"]] = this.sortInfo.direction;
9664 if (this.multiSort) {
9665 var pn = this.paramNames;
9666 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9669 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9674 * Reloads the Record cache from the configured Proxy using the configured Reader and
9675 * the options from the last load operation performed.
9676 * @param {Object} options (optional) An object containing properties which may override the options
9677 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9678 * the most recently used options are reused).
9680 reload : function(options){
9681 this.load(Roo.applyIf(options||{}, this.lastOptions));
9685 // Called as a callback by the Reader during a load operation.
9686 loadRecords : function(o, options, success){
9687 if(!o || success === false){
9688 if(success !== false){
9689 this.fireEvent("load", this, [], options, o);
9691 if(options.callback){
9692 options.callback.call(options.scope || this, [], options, false);
9696 // if data returned failure - throw an exception.
9697 if (o.success === false) {
9698 // show a message if no listener is registered.
9699 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9700 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9702 // loadmask wil be hooked into this..
9703 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9706 var r = o.records, t = o.totalRecords || r.length;
9708 this.fireEvent("beforeloadadd", this, r, options, o);
9710 if(!options || options.add !== true){
9711 if(this.pruneModifiedRecords){
9714 for(var i = 0, len = r.length; i < len; i++){
9718 this.data = this.snapshot;
9719 delete this.snapshot;
9722 this.data.addAll(r);
9723 this.totalLength = t;
9725 this.fireEvent("datachanged", this);
9727 this.totalLength = Math.max(t, this.data.length+r.length);
9730 this.fireEvent("load", this, r, options, o);
9731 if(options.callback){
9732 options.callback.call(options.scope || this, r, options, true);
9738 * Loads data from a passed data block. A Reader which understands the format of the data
9739 * must have been configured in the constructor.
9740 * @param {Object} data The data block from which to read the Records. The format of the data expected
9741 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9742 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9744 loadData : function(o, append){
9745 var r = this.reader.readRecords(o);
9746 this.loadRecords(r, {add: append}, true);
9750 * Gets the number of cached records.
9752 * <em>If using paging, this may not be the total size of the dataset. If the data object
9753 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9754 * the data set size</em>
9756 getCount : function(){
9757 return this.data.length || 0;
9761 * Gets the total number of records in the dataset as returned by the server.
9763 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9764 * the dataset size</em>
9766 getTotalCount : function(){
9767 return this.totalLength || 0;
9771 * Returns the sort state of the Store as an object with two properties:
9773 field {String} The name of the field by which the Records are sorted
9774 direction {String} The sort order, "ASC" or "DESC"
9777 getSortState : function(){
9778 return this.sortInfo;
9782 applySort : function(){
9783 if(this.sortInfo && !this.remoteSort){
9784 var s = this.sortInfo, f = s.field;
9785 var st = this.fields.get(f).sortType;
9786 var fn = function(r1, r2){
9787 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9788 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9790 this.data.sort(s.direction, fn);
9791 if(this.snapshot && this.snapshot != this.data){
9792 this.snapshot.sort(s.direction, fn);
9798 * Sets the default sort column and order to be used by the next load operation.
9799 * @param {String} fieldName The name of the field to sort by.
9800 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9802 setDefaultSort : function(field, dir){
9803 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9808 * If remote sorting is used, the sort is performed on the server, and the cache is
9809 * reloaded. If local sorting is used, the cache is sorted internally.
9810 * @param {String} fieldName The name of the field to sort by.
9811 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9813 sort : function(fieldName, dir){
9814 var f = this.fields.get(fieldName);
9816 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9818 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9819 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9824 this.sortToggle[f.name] = dir;
9825 this.sortInfo = {field: f.name, direction: dir};
9826 if(!this.remoteSort){
9828 this.fireEvent("datachanged", this);
9830 this.load(this.lastOptions);
9835 * Calls the specified function for each of the Records in the cache.
9836 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9837 * Returning <em>false</em> aborts and exits the iteration.
9838 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9840 each : function(fn, scope){
9841 this.data.each(fn, scope);
9845 * Gets all records modified since the last commit. Modified records are persisted across load operations
9846 * (e.g., during paging).
9847 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9849 getModifiedRecords : function(){
9850 return this.modified;
9854 createFilterFn : function(property, value, anyMatch){
9855 if(!value.exec){ // not a regex
9856 value = String(value);
9857 if(value.length == 0){
9860 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9863 return value.test(r.data[property]);
9868 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9869 * @param {String} property A field on your records
9870 * @param {Number} start The record index to start at (defaults to 0)
9871 * @param {Number} end The last record index to include (defaults to length - 1)
9872 * @return {Number} The sum
9874 sum : function(property, start, end){
9875 var rs = this.data.items, v = 0;
9877 end = (end || end === 0) ? end : rs.length-1;
9879 for(var i = start; i <= end; i++){
9880 v += (rs[i].data[property] || 0);
9886 * Filter the records by a specified property.
9887 * @param {String} field A field on your records
9888 * @param {String/RegExp} value Either a string that the field
9889 * should start with or a RegExp to test against the field
9890 * @param {Boolean} anyMatch True to match any part not just the beginning
9892 filter : function(property, value, anyMatch){
9893 var fn = this.createFilterFn(property, value, anyMatch);
9894 return fn ? this.filterBy(fn) : this.clearFilter();
9898 * Filter by a function. The specified function will be called with each
9899 * record in this data source. If the function returns true the record is included,
9900 * otherwise it is filtered.
9901 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9902 * @param {Object} scope (optional) The scope of the function (defaults to this)
9904 filterBy : function(fn, scope){
9905 this.snapshot = this.snapshot || this.data;
9906 this.data = this.queryBy(fn, scope||this);
9907 this.fireEvent("datachanged", this);
9911 * Query the records by a specified property.
9912 * @param {String} field A field on your records
9913 * @param {String/RegExp} value Either a string that the field
9914 * should start with or a RegExp to test against the field
9915 * @param {Boolean} anyMatch True to match any part not just the beginning
9916 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9918 query : function(property, value, anyMatch){
9919 var fn = this.createFilterFn(property, value, anyMatch);
9920 return fn ? this.queryBy(fn) : this.data.clone();
9924 * Query by a function. The specified function will be called with each
9925 * record in this data source. If the function returns true the record is included
9927 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9928 * @param {Object} scope (optional) The scope of the function (defaults to this)
9929 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9931 queryBy : function(fn, scope){
9932 var data = this.snapshot || this.data;
9933 return data.filterBy(fn, scope||this);
9937 * Collects unique values for a particular dataIndex from this store.
9938 * @param {String} dataIndex The property to collect
9939 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9940 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9941 * @return {Array} An array of the unique values
9943 collect : function(dataIndex, allowNull, bypassFilter){
9944 var d = (bypassFilter === true && this.snapshot) ?
9945 this.snapshot.items : this.data.items;
9946 var v, sv, r = [], l = {};
9947 for(var i = 0, len = d.length; i < len; i++){
9948 v = d[i].data[dataIndex];
9950 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9959 * Revert to a view of the Record cache with no filtering applied.
9960 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9962 clearFilter : function(suppressEvent){
9963 if(this.snapshot && this.snapshot != this.data){
9964 this.data = this.snapshot;
9965 delete this.snapshot;
9966 if(suppressEvent !== true){
9967 this.fireEvent("datachanged", this);
9973 afterEdit : function(record){
9974 if(this.modified.indexOf(record) == -1){
9975 this.modified.push(record);
9977 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9981 afterReject : function(record){
9982 this.modified.remove(record);
9983 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9987 afterCommit : function(record){
9988 this.modified.remove(record);
9989 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9993 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9994 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9996 commitChanges : function(){
9997 var m = this.modified.slice(0);
9999 for(var i = 0, len = m.length; i < len; i++){
10005 * Cancel outstanding changes on all changed records.
10007 rejectChanges : function(){
10008 var m = this.modified.slice(0);
10009 this.modified = [];
10010 for(var i = 0, len = m.length; i < len; i++){
10015 onMetaChange : function(meta, rtype, o){
10016 this.recordType = rtype;
10017 this.fields = rtype.prototype.fields;
10018 delete this.snapshot;
10019 this.sortInfo = meta.sortInfo || this.sortInfo;
10020 this.modified = [];
10021 this.fireEvent('metachange', this, this.reader.meta);
10024 moveIndex : function(data, type)
10026 var index = this.indexOf(data);
10028 var newIndex = index + type;
10032 this.insert(newIndex, data);
10037 * Ext JS Library 1.1.1
10038 * Copyright(c) 2006-2007, Ext JS, LLC.
10040 * Originally Released Under LGPL - original licence link has changed is not relivant.
10043 * <script type="text/javascript">
10047 * @class Roo.data.SimpleStore
10048 * @extends Roo.data.Store
10049 * Small helper class to make creating Stores from Array data easier.
10050 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10051 * @cfg {Array} fields An array of field definition objects, or field name strings.
10052 * @cfg {Array} data The multi-dimensional array of data
10054 * @param {Object} config
10056 Roo.data.SimpleStore = function(config){
10057 Roo.data.SimpleStore.superclass.constructor.call(this, {
10059 reader: new Roo.data.ArrayReader({
10062 Roo.data.Record.create(config.fields)
10064 proxy : new Roo.data.MemoryProxy(config.data)
10068 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10070 * Ext JS Library 1.1.1
10071 * Copyright(c) 2006-2007, Ext JS, LLC.
10073 * Originally Released Under LGPL - original licence link has changed is not relivant.
10076 * <script type="text/javascript">
10081 * @extends Roo.data.Store
10082 * @class Roo.data.JsonStore
10083 * Small helper class to make creating Stores for JSON data easier. <br/>
10085 var store = new Roo.data.JsonStore({
10086 url: 'get-images.php',
10088 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10091 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10092 * JsonReader and HttpProxy (unless inline data is provided).</b>
10093 * @cfg {Array} fields An array of field definition objects, or field name strings.
10095 * @param {Object} config
10097 Roo.data.JsonStore = function(c){
10098 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10099 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10100 reader: new Roo.data.JsonReader(c, c.fields)
10103 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10105 * Ext JS Library 1.1.1
10106 * Copyright(c) 2006-2007, Ext JS, LLC.
10108 * Originally Released Under LGPL - original licence link has changed is not relivant.
10111 * <script type="text/javascript">
10115 Roo.data.Field = function(config){
10116 if(typeof config == "string"){
10117 config = {name: config};
10119 Roo.apply(this, config);
10122 this.type = "auto";
10125 var st = Roo.data.SortTypes;
10126 // named sortTypes are supported, here we look them up
10127 if(typeof this.sortType == "string"){
10128 this.sortType = st[this.sortType];
10131 // set default sortType for strings and dates
10132 if(!this.sortType){
10135 this.sortType = st.asUCString;
10138 this.sortType = st.asDate;
10141 this.sortType = st.none;
10146 var stripRe = /[\$,%]/g;
10148 // prebuilt conversion function for this field, instead of
10149 // switching every time we're reading a value
10151 var cv, dateFormat = this.dateFormat;
10156 cv = function(v){ return v; };
10159 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10163 return v !== undefined && v !== null && v !== '' ?
10164 parseInt(String(v).replace(stripRe, ""), 10) : '';
10169 return v !== undefined && v !== null && v !== '' ?
10170 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10175 cv = function(v){ return v === true || v === "true" || v == 1; };
10182 if(v instanceof Date){
10186 if(dateFormat == "timestamp"){
10187 return new Date(v*1000);
10189 return Date.parseDate(v, dateFormat);
10191 var parsed = Date.parse(v);
10192 return parsed ? new Date(parsed) : null;
10201 Roo.data.Field.prototype = {
10209 * Ext JS Library 1.1.1
10210 * Copyright(c) 2006-2007, Ext JS, LLC.
10212 * Originally Released Under LGPL - original licence link has changed is not relivant.
10215 * <script type="text/javascript">
10218 // Base class for reading structured data from a data source. This class is intended to be
10219 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10222 * @class Roo.data.DataReader
10223 * Base class for reading structured data from a data source. This class is intended to be
10224 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10227 Roo.data.DataReader = function(meta, recordType){
10231 this.recordType = recordType instanceof Array ?
10232 Roo.data.Record.create(recordType) : recordType;
10235 Roo.data.DataReader.prototype = {
10237 * Create an empty record
10238 * @param {Object} data (optional) - overlay some values
10239 * @return {Roo.data.Record} record created.
10241 newRow : function(d) {
10243 this.recordType.prototype.fields.each(function(c) {
10245 case 'int' : da[c.name] = 0; break;
10246 case 'date' : da[c.name] = new Date(); break;
10247 case 'float' : da[c.name] = 0.0; break;
10248 case 'boolean' : da[c.name] = false; break;
10249 default : da[c.name] = ""; break;
10253 return new this.recordType(Roo.apply(da, d));
10258 * Ext JS Library 1.1.1
10259 * Copyright(c) 2006-2007, Ext JS, LLC.
10261 * Originally Released Under LGPL - original licence link has changed is not relivant.
10264 * <script type="text/javascript">
10268 * @class Roo.data.DataProxy
10269 * @extends Roo.data.Observable
10270 * This class is an abstract base class for implementations which provide retrieval of
10271 * unformatted data objects.<br>
10273 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10274 * (of the appropriate type which knows how to parse the data object) to provide a block of
10275 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10277 * Custom implementations must implement the load method as described in
10278 * {@link Roo.data.HttpProxy#load}.
10280 Roo.data.DataProxy = function(){
10283 * @event beforeload
10284 * Fires before a network request is made to retrieve a data object.
10285 * @param {Object} This DataProxy object.
10286 * @param {Object} params The params parameter to the load function.
10291 * Fires before the load method's callback is called.
10292 * @param {Object} This DataProxy object.
10293 * @param {Object} o The data object.
10294 * @param {Object} arg The callback argument object passed to the load function.
10298 * @event loadexception
10299 * Fires if an Exception occurs during data retrieval.
10300 * @param {Object} This DataProxy object.
10301 * @param {Object} o The data object.
10302 * @param {Object} arg The callback argument object passed to the load function.
10303 * @param {Object} e The Exception.
10305 loadexception : true
10307 Roo.data.DataProxy.superclass.constructor.call(this);
10310 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10313 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10317 * Ext JS Library 1.1.1
10318 * Copyright(c) 2006-2007, Ext JS, LLC.
10320 * Originally Released Under LGPL - original licence link has changed is not relivant.
10323 * <script type="text/javascript">
10326 * @class Roo.data.MemoryProxy
10327 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10328 * to the Reader when its load method is called.
10330 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10332 Roo.data.MemoryProxy = function(data){
10336 Roo.data.MemoryProxy.superclass.constructor.call(this);
10340 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10342 * Load data from the requested source (in this case an in-memory
10343 * data object passed to the constructor), read the data object into
10344 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10345 * process that block using the passed callback.
10346 * @param {Object} params This parameter is not used by the MemoryProxy class.
10347 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10348 * object into a block of Roo.data.Records.
10349 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10350 * The function must be passed <ul>
10351 * <li>The Record block object</li>
10352 * <li>The "arg" argument from the load function</li>
10353 * <li>A boolean success indicator</li>
10355 * @param {Object} scope The scope in which to call the callback
10356 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10358 load : function(params, reader, callback, scope, arg){
10359 params = params || {};
10362 result = reader.readRecords(this.data);
10364 this.fireEvent("loadexception", this, arg, null, e);
10365 callback.call(scope, null, arg, false);
10368 callback.call(scope, result, arg, true);
10372 update : function(params, records){
10377 * Ext JS Library 1.1.1
10378 * Copyright(c) 2006-2007, Ext JS, LLC.
10380 * Originally Released Under LGPL - original licence link has changed is not relivant.
10383 * <script type="text/javascript">
10386 * @class Roo.data.HttpProxy
10387 * @extends Roo.data.DataProxy
10388 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10389 * configured to reference a certain URL.<br><br>
10391 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10392 * from which the running page was served.<br><br>
10394 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10396 * Be aware that to enable the browser to parse an XML document, the server must set
10397 * the Content-Type header in the HTTP response to "text/xml".
10399 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10400 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10401 * will be used to make the request.
10403 Roo.data.HttpProxy = function(conn){
10404 Roo.data.HttpProxy.superclass.constructor.call(this);
10405 // is conn a conn config or a real conn?
10407 this.useAjax = !conn || !conn.events;
10411 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10412 // thse are take from connection...
10415 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10418 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10419 * extra parameters to each request made by this object. (defaults to undefined)
10422 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10423 * to each request made by this object. (defaults to undefined)
10426 * @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)
10429 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10432 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10438 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10442 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10443 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10444 * a finer-grained basis than the DataProxy events.
10446 getConnection : function(){
10447 return this.useAjax ? Roo.Ajax : this.conn;
10451 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10452 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10453 * process that block using the passed callback.
10454 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10455 * for the request to the remote server.
10456 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10457 * object into a block of Roo.data.Records.
10458 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10459 * The function must be passed <ul>
10460 * <li>The Record block object</li>
10461 * <li>The "arg" argument from the load function</li>
10462 * <li>A boolean success indicator</li>
10464 * @param {Object} scope The scope in which to call the callback
10465 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10467 load : function(params, reader, callback, scope, arg){
10468 if(this.fireEvent("beforeload", this, params) !== false){
10470 params : params || {},
10472 callback : callback,
10477 callback : this.loadResponse,
10481 Roo.applyIf(o, this.conn);
10482 if(this.activeRequest){
10483 Roo.Ajax.abort(this.activeRequest);
10485 this.activeRequest = Roo.Ajax.request(o);
10487 this.conn.request(o);
10490 callback.call(scope||this, null, arg, false);
10495 loadResponse : function(o, success, response){
10496 delete this.activeRequest;
10498 this.fireEvent("loadexception", this, o, response);
10499 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10504 result = o.reader.read(response);
10506 this.fireEvent("loadexception", this, o, response, e);
10507 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10511 this.fireEvent("load", this, o, o.request.arg);
10512 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10516 update : function(dataSet){
10521 updateResponse : function(dataSet){
10526 * Ext JS Library 1.1.1
10527 * Copyright(c) 2006-2007, Ext JS, LLC.
10529 * Originally Released Under LGPL - original licence link has changed is not relivant.
10532 * <script type="text/javascript">
10536 * @class Roo.data.ScriptTagProxy
10537 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10538 * other than the originating domain of the running page.<br><br>
10540 * <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
10541 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10543 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10544 * source code that is used as the source inside a <script> tag.<br><br>
10546 * In order for the browser to process the returned data, the server must wrap the data object
10547 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10548 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10549 * depending on whether the callback name was passed:
10552 boolean scriptTag = false;
10553 String cb = request.getParameter("callback");
10556 response.setContentType("text/javascript");
10558 response.setContentType("application/x-json");
10560 Writer out = response.getWriter();
10562 out.write(cb + "(");
10564 out.print(dataBlock.toJsonString());
10571 * @param {Object} config A configuration object.
10573 Roo.data.ScriptTagProxy = function(config){
10574 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10575 Roo.apply(this, config);
10576 this.head = document.getElementsByTagName("head")[0];
10579 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10581 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10583 * @cfg {String} url The URL from which to request the data object.
10586 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10590 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10591 * the server the name of the callback function set up by the load call to process the returned data object.
10592 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10593 * javascript output which calls this named function passing the data object as its only parameter.
10595 callbackParam : "callback",
10597 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10598 * name to the request.
10603 * Load data from the configured URL, read the data object into
10604 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10605 * process that block using the passed callback.
10606 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10607 * for the request to the remote server.
10608 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10609 * object into a block of Roo.data.Records.
10610 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10611 * The function must be passed <ul>
10612 * <li>The Record block object</li>
10613 * <li>The "arg" argument from the load function</li>
10614 * <li>A boolean success indicator</li>
10616 * @param {Object} scope The scope in which to call the callback
10617 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10619 load : function(params, reader, callback, scope, arg){
10620 if(this.fireEvent("beforeload", this, params) !== false){
10622 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10624 var url = this.url;
10625 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10627 url += "&_dc=" + (new Date().getTime());
10629 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10632 cb : "stcCallback"+transId,
10633 scriptId : "stcScript"+transId,
10637 callback : callback,
10643 window[trans.cb] = function(o){
10644 conn.handleResponse(o, trans);
10647 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10649 if(this.autoAbort !== false){
10653 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10655 var script = document.createElement("script");
10656 script.setAttribute("src", url);
10657 script.setAttribute("type", "text/javascript");
10658 script.setAttribute("id", trans.scriptId);
10659 this.head.appendChild(script);
10661 this.trans = trans;
10663 callback.call(scope||this, null, arg, false);
10668 isLoading : function(){
10669 return this.trans ? true : false;
10673 * Abort the current server request.
10675 abort : function(){
10676 if(this.isLoading()){
10677 this.destroyTrans(this.trans);
10682 destroyTrans : function(trans, isLoaded){
10683 this.head.removeChild(document.getElementById(trans.scriptId));
10684 clearTimeout(trans.timeoutId);
10686 window[trans.cb] = undefined;
10688 delete window[trans.cb];
10691 // if hasn't been loaded, wait for load to remove it to prevent script error
10692 window[trans.cb] = function(){
10693 window[trans.cb] = undefined;
10695 delete window[trans.cb];
10702 handleResponse : function(o, trans){
10703 this.trans = false;
10704 this.destroyTrans(trans, true);
10707 result = trans.reader.readRecords(o);
10709 this.fireEvent("loadexception", this, o, trans.arg, e);
10710 trans.callback.call(trans.scope||window, null, trans.arg, false);
10713 this.fireEvent("load", this, o, trans.arg);
10714 trans.callback.call(trans.scope||window, result, trans.arg, true);
10718 handleFailure : function(trans){
10719 this.trans = false;
10720 this.destroyTrans(trans, false);
10721 this.fireEvent("loadexception", this, null, trans.arg);
10722 trans.callback.call(trans.scope||window, null, trans.arg, false);
10726 * Ext JS Library 1.1.1
10727 * Copyright(c) 2006-2007, Ext JS, LLC.
10729 * Originally Released Under LGPL - original licence link has changed is not relivant.
10732 * <script type="text/javascript">
10736 * @class Roo.data.JsonReader
10737 * @extends Roo.data.DataReader
10738 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10739 * based on mappings in a provided Roo.data.Record constructor.
10741 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10742 * in the reply previously.
10747 var RecordDef = Roo.data.Record.create([
10748 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10749 {name: 'occupation'} // This field will use "occupation" as the mapping.
10751 var myReader = new Roo.data.JsonReader({
10752 totalProperty: "results", // The property which contains the total dataset size (optional)
10753 root: "rows", // The property which contains an Array of row objects
10754 id: "id" // The property within each row object that provides an ID for the record (optional)
10758 * This would consume a JSON file like this:
10760 { 'results': 2, 'rows': [
10761 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10762 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10765 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10766 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10767 * paged from the remote server.
10768 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10769 * @cfg {String} root name of the property which contains the Array of row objects.
10770 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10771 * @cfg {Array} fields Array of field definition objects
10773 * Create a new JsonReader
10774 * @param {Object} meta Metadata configuration options
10775 * @param {Object} recordType Either an Array of field definition objects,
10776 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10778 Roo.data.JsonReader = function(meta, recordType){
10781 // set some defaults:
10782 Roo.applyIf(meta, {
10783 totalProperty: 'total',
10784 successProperty : 'success',
10789 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10791 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10794 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10795 * Used by Store query builder to append _requestMeta to params.
10798 metaFromRemote : false,
10800 * This method is only used by a DataProxy which has retrieved data from a remote server.
10801 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10802 * @return {Object} data A data block which is used by an Roo.data.Store object as
10803 * a cache of Roo.data.Records.
10805 read : function(response){
10806 var json = response.responseText;
10808 var o = /* eval:var:o */ eval("("+json+")");
10810 throw {message: "JsonReader.read: Json object not found"};
10816 this.metaFromRemote = true;
10817 this.meta = o.metaData;
10818 this.recordType = Roo.data.Record.create(o.metaData.fields);
10819 this.onMetaChange(this.meta, this.recordType, o);
10821 return this.readRecords(o);
10824 // private function a store will implement
10825 onMetaChange : function(meta, recordType, o){
10832 simpleAccess: function(obj, subsc) {
10839 getJsonAccessor: function(){
10841 return function(expr) {
10843 return(re.test(expr))
10844 ? new Function("obj", "return obj." + expr)
10849 return Roo.emptyFn;
10854 * Create a data block containing Roo.data.Records from an XML document.
10855 * @param {Object} o An object which contains an Array of row objects in the property specified
10856 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10857 * which contains the total size of the dataset.
10858 * @return {Object} data A data block which is used by an Roo.data.Store object as
10859 * a cache of Roo.data.Records.
10861 readRecords : function(o){
10863 * After any data loads, the raw JSON data is available for further custom processing.
10867 var s = this.meta, Record = this.recordType,
10868 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10870 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10872 if(s.totalProperty) {
10873 this.getTotal = this.getJsonAccessor(s.totalProperty);
10875 if(s.successProperty) {
10876 this.getSuccess = this.getJsonAccessor(s.successProperty);
10878 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10880 var g = this.getJsonAccessor(s.id);
10881 this.getId = function(rec) {
10883 return (r === undefined || r === "") ? null : r;
10886 this.getId = function(){return null;};
10889 for(var jj = 0; jj < fl; jj++){
10891 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10892 this.ef[jj] = this.getJsonAccessor(map);
10896 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10897 if(s.totalProperty){
10898 var vt = parseInt(this.getTotal(o), 10);
10903 if(s.successProperty){
10904 var vs = this.getSuccess(o);
10905 if(vs === false || vs === 'false'){
10910 for(var i = 0; i < c; i++){
10913 var id = this.getId(n);
10914 for(var j = 0; j < fl; j++){
10916 var v = this.ef[j](n);
10918 Roo.log('missing convert for ' + f.name);
10922 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10924 var record = new Record(values, id);
10926 records[i] = record;
10932 totalRecords : totalRecords
10937 * Ext JS Library 1.1.1
10938 * Copyright(c) 2006-2007, Ext JS, LLC.
10940 * Originally Released Under LGPL - original licence link has changed is not relivant.
10943 * <script type="text/javascript">
10947 * @class Roo.data.ArrayReader
10948 * @extends Roo.data.DataReader
10949 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10950 * Each element of that Array represents a row of data fields. The
10951 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10952 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10956 var RecordDef = Roo.data.Record.create([
10957 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10958 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10960 var myReader = new Roo.data.ArrayReader({
10961 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10965 * This would consume an Array like this:
10967 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10969 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10971 * Create a new JsonReader
10972 * @param {Object} meta Metadata configuration options.
10973 * @param {Object} recordType Either an Array of field definition objects
10974 * as specified to {@link Roo.data.Record#create},
10975 * or an {@link Roo.data.Record} object
10976 * created using {@link Roo.data.Record#create}.
10978 Roo.data.ArrayReader = function(meta, recordType){
10979 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10982 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10984 * Create a data block containing Roo.data.Records from an XML document.
10985 * @param {Object} o An Array of row objects which represents the dataset.
10986 * @return {Object} data A data block which is used by an Roo.data.Store object as
10987 * a cache of Roo.data.Records.
10989 readRecords : function(o){
10990 var sid = this.meta ? this.meta.id : null;
10991 var recordType = this.recordType, fields = recordType.prototype.fields;
10994 for(var i = 0; i < root.length; i++){
10997 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10998 for(var j = 0, jlen = fields.length; j < jlen; j++){
10999 var f = fields.items[j];
11000 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11001 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11003 values[f.name] = v;
11005 var record = new recordType(values, id);
11007 records[records.length] = record;
11011 totalRecords : records.length
11020 * @class Roo.bootstrap.ComboBox
11021 * @extends Roo.bootstrap.TriggerField
11022 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11023 * @cfg {Boolean} append (true|false) default false
11024 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11025 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11026 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11027 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11028 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11030 * Create a new ComboBox.
11031 * @param {Object} config Configuration options
11033 Roo.bootstrap.ComboBox = function(config){
11034 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11038 * Fires when the dropdown list is expanded
11039 * @param {Roo.bootstrap.ComboBox} combo This combo box
11044 * Fires when the dropdown list is collapsed
11045 * @param {Roo.bootstrap.ComboBox} combo This combo box
11049 * @event beforeselect
11050 * Fires before a list item is selected. Return false to cancel the selection.
11051 * @param {Roo.bootstrap.ComboBox} combo This combo box
11052 * @param {Roo.data.Record} record The data record returned from the underlying store
11053 * @param {Number} index The index of the selected item in the dropdown list
11055 'beforeselect' : true,
11058 * Fires when a list item is selected
11059 * @param {Roo.bootstrap.ComboBox} combo This combo box
11060 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11061 * @param {Number} index The index of the selected item in the dropdown list
11065 * @event beforequery
11066 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11067 * The event object passed has these properties:
11068 * @param {Roo.bootstrap.ComboBox} combo This combo box
11069 * @param {String} query The query
11070 * @param {Boolean} forceAll true to force "all" query
11071 * @param {Boolean} cancel true to cancel the query
11072 * @param {Object} e The query event object
11074 'beforequery': true,
11077 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11078 * @param {Roo.bootstrap.ComboBox} combo This combo box
11083 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11084 * @param {Roo.bootstrap.ComboBox} combo This combo box
11085 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11090 * Fires when the remove value from the combobox array
11091 * @param {Roo.bootstrap.ComboBox} combo This combo box
11095 * @event specialfilter
11096 * Fires when specialfilter
11097 * @param {Roo.bootstrap.ComboBox} combo This combo box
11099 'specialfilter' : true
11104 this.tickItems = [];
11106 this.selectedIndex = -1;
11107 if(this.mode == 'local'){
11108 if(config.queryDelay === undefined){
11109 this.queryDelay = 10;
11111 if(config.minChars === undefined){
11117 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11120 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11121 * rendering into an Roo.Editor, defaults to false)
11124 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11125 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11128 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11131 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11132 * the dropdown list (defaults to undefined, with no header element)
11136 * @cfg {String/Roo.Template} tpl The template to use to render the output
11140 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11142 listWidth: undefined,
11144 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11145 * mode = 'remote' or 'text' if mode = 'local')
11147 displayField: undefined,
11150 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11151 * mode = 'remote' or 'value' if mode = 'local').
11152 * Note: use of a valueField requires the user make a selection
11153 * in order for a value to be mapped.
11155 valueField: undefined,
11159 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11160 * field's data value (defaults to the underlying DOM element's name)
11162 hiddenName: undefined,
11164 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11168 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11170 selectedClass: 'active',
11173 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11177 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11178 * anchor positions (defaults to 'tl-bl')
11180 listAlign: 'tl-bl?',
11182 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11186 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11187 * query specified by the allQuery config option (defaults to 'query')
11189 triggerAction: 'query',
11191 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11192 * (defaults to 4, does not apply if editable = false)
11196 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11197 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11201 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11202 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11206 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11207 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11211 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11212 * when editable = true (defaults to false)
11214 selectOnFocus:false,
11216 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11218 queryParam: 'query',
11220 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11221 * when mode = 'remote' (defaults to 'Loading...')
11223 loadingText: 'Loading...',
11225 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11229 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11233 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11234 * traditional select (defaults to true)
11238 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11242 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11246 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11247 * listWidth has a higher value)
11251 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11252 * allow the user to set arbitrary text into the field (defaults to false)
11254 forceSelection:false,
11256 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11257 * if typeAhead = true (defaults to 250)
11259 typeAheadDelay : 250,
11261 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11262 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11264 valueNotFoundText : undefined,
11266 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11268 blockFocus : false,
11271 * @cfg {Boolean} disableClear Disable showing of clear button.
11273 disableClear : false,
11275 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11277 alwaysQuery : false,
11280 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11285 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11287 invalidClass : "has-warning",
11290 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11292 validClass : "has-success",
11295 * @cfg {Boolean} specialFilter (true|false) special filter default false
11297 specialFilter : false,
11309 btnPosition : 'right',
11310 triggerList : true,
11311 showToggleBtn : true,
11312 // element that contains real text value.. (when hidden is used..)
11314 getAutoCreate : function()
11321 if(!this.tickable){
11322 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11327 * ComboBox with tickable selections
11330 var align = this.labelAlign || this.parentLabelAlign();
11333 cls : 'form-group roo-combobox-tickable' //input-group
11338 cls : 'tickable-buttons',
11343 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11350 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11357 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11364 buttons.cn.unshift({
11366 cls: 'select2-search-field-input'
11372 Roo.each(buttons.cn, function(c){
11374 c.cls += ' btn-' + _this.size;
11377 if (_this.disabled) {
11388 cls: 'form-hidden-field'
11392 cls: 'select2-choices',
11396 cls: 'select2-search-field',
11408 cls: 'select2-container input-group select2-container-multi',
11413 // cls: 'typeahead typeahead-long dropdown-menu',
11414 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11419 if(this.hasFeedback && !this.allowBlank){
11423 cls: 'glyphicon form-control-feedback'
11426 combobox.cn.push(feedback);
11429 if (align ==='left' && this.fieldLabel.length) {
11431 Roo.log("left and has label");
11437 cls : 'control-label col-sm-' + this.labelWidth,
11438 html : this.fieldLabel
11442 cls : "col-sm-" + (12 - this.labelWidth),
11449 } else if ( this.fieldLabel.length) {
11455 //cls : 'input-group-addon',
11456 html : this.fieldLabel
11466 Roo.log(" no label && no align");
11473 ['xs','sm','md','lg'].map(function(size){
11474 if (settings[size]) {
11475 cfg.cls += ' col-' + size + '-' + settings[size];
11484 initEvents: function()
11488 throw "can not find store for combo";
11490 this.store = Roo.factory(this.store, Roo.data);
11493 this.initTickableEvents();
11497 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11499 if(this.hiddenName){
11501 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11503 this.hiddenField.dom.value =
11504 this.hiddenValue !== undefined ? this.hiddenValue :
11505 this.value !== undefined ? this.value : '';
11507 // prevent input submission
11508 this.el.dom.removeAttribute('name');
11509 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11514 // this.el.dom.setAttribute('autocomplete', 'off');
11517 var cls = 'x-combo-list';
11519 //this.list = new Roo.Layer({
11520 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11526 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11527 _this.list.setWidth(lw);
11530 this.list.on('mouseover', this.onViewOver, this);
11531 this.list.on('mousemove', this.onViewMove, this);
11533 this.list.on('scroll', this.onViewScroll, this);
11536 this.list.swallowEvent('mousewheel');
11537 this.assetHeight = 0;
11540 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11541 this.assetHeight += this.header.getHeight();
11544 this.innerList = this.list.createChild({cls:cls+'-inner'});
11545 this.innerList.on('mouseover', this.onViewOver, this);
11546 this.innerList.on('mousemove', this.onViewMove, this);
11547 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11549 if(this.allowBlank && !this.pageSize && !this.disableClear){
11550 this.footer = this.list.createChild({cls:cls+'-ft'});
11551 this.pageTb = new Roo.Toolbar(this.footer);
11555 this.footer = this.list.createChild({cls:cls+'-ft'});
11556 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11557 {pageSize: this.pageSize});
11561 if (this.pageTb && this.allowBlank && !this.disableClear) {
11563 this.pageTb.add(new Roo.Toolbar.Fill(), {
11564 cls: 'x-btn-icon x-btn-clear',
11566 handler: function()
11569 _this.clearValue();
11570 _this.onSelect(false, -1);
11575 this.assetHeight += this.footer.getHeight();
11580 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11583 this.view = new Roo.View(this.list, this.tpl, {
11584 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11586 //this.view.wrapEl.setDisplayed(false);
11587 this.view.on('click', this.onViewClick, this);
11591 this.store.on('beforeload', this.onBeforeLoad, this);
11592 this.store.on('load', this.onLoad, this);
11593 this.store.on('loadexception', this.onLoadException, this);
11595 if(this.resizable){
11596 this.resizer = new Roo.Resizable(this.list, {
11597 pinned:true, handles:'se'
11599 this.resizer.on('resize', function(r, w, h){
11600 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11601 this.listWidth = w;
11602 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11603 this.restrictHeight();
11605 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11608 if(!this.editable){
11609 this.editable = true;
11610 this.setEditable(false);
11615 if (typeof(this.events.add.listeners) != 'undefined') {
11617 this.addicon = this.wrap.createChild(
11618 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11620 this.addicon.on('click', function(e) {
11621 this.fireEvent('add', this);
11624 if (typeof(this.events.edit.listeners) != 'undefined') {
11626 this.editicon = this.wrap.createChild(
11627 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11628 if (this.addicon) {
11629 this.editicon.setStyle('margin-left', '40px');
11631 this.editicon.on('click', function(e) {
11633 // we fire even if inothing is selected..
11634 this.fireEvent('edit', this, this.lastData );
11640 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11641 "up" : function(e){
11642 this.inKeyMode = true;
11646 "down" : function(e){
11647 if(!this.isExpanded()){
11648 this.onTriggerClick();
11650 this.inKeyMode = true;
11655 "enter" : function(e){
11656 // this.onViewClick();
11660 if(this.fireEvent("specialkey", this, e)){
11661 this.onViewClick(false);
11667 "esc" : function(e){
11671 "tab" : function(e){
11674 if(this.fireEvent("specialkey", this, e)){
11675 this.onViewClick(false);
11683 doRelay : function(foo, bar, hname){
11684 if(hname == 'down' || this.scope.isExpanded()){
11685 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11694 this.queryDelay = Math.max(this.queryDelay || 10,
11695 this.mode == 'local' ? 10 : 250);
11698 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11700 if(this.typeAhead){
11701 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11703 if(this.editable !== false){
11704 this.inputEl().on("keyup", this.onKeyUp, this);
11706 if(this.forceSelection){
11707 this.inputEl().on('blur', this.doForce, this);
11711 this.choices = this.el.select('ul.select2-choices', true).first();
11712 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11716 initTickableEvents: function()
11720 if(this.hiddenName){
11722 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11724 this.hiddenField.dom.value =
11725 this.hiddenValue !== undefined ? this.hiddenValue :
11726 this.value !== undefined ? this.value : '';
11728 // prevent input submission
11729 this.el.dom.removeAttribute('name');
11730 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11735 // this.list = this.el.select('ul.dropdown-menu',true).first();
11737 this.choices = this.el.select('ul.select2-choices', true).first();
11738 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11739 if(this.triggerList){
11740 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11743 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11744 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11746 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11747 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11749 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11750 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11752 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11753 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11754 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11757 this.cancelBtn.hide();
11762 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11763 _this.list.setWidth(lw);
11766 this.list.on('mouseover', this.onViewOver, this);
11767 this.list.on('mousemove', this.onViewMove, this);
11769 this.list.on('scroll', this.onViewScroll, this);
11772 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>';
11775 this.view = new Roo.View(this.list, this.tpl, {
11776 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11779 //this.view.wrapEl.setDisplayed(false);
11780 this.view.on('click', this.onViewClick, this);
11784 this.store.on('beforeload', this.onBeforeLoad, this);
11785 this.store.on('load', this.onLoad, this);
11786 this.store.on('loadexception', this.onLoadException, this);
11789 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11790 "up" : function(e){
11791 this.inKeyMode = true;
11795 "down" : function(e){
11796 this.inKeyMode = true;
11800 "enter" : function(e){
11801 if(this.fireEvent("specialkey", this, e)){
11802 this.onViewClick(false);
11808 "esc" : function(e){
11809 this.onTickableFooterButtonClick(e, false, false);
11812 "tab" : function(e){
11813 this.fireEvent("specialkey", this, e);
11815 this.onTickableFooterButtonClick(e, false, false);
11822 doRelay : function(e, fn, key){
11823 if(this.scope.isExpanded()){
11824 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11833 this.queryDelay = Math.max(this.queryDelay || 10,
11834 this.mode == 'local' ? 10 : 250);
11837 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11839 if(this.typeAhead){
11840 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11843 if(this.editable !== false){
11844 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11849 onDestroy : function(){
11851 this.view.setStore(null);
11852 this.view.el.removeAllListeners();
11853 this.view.el.remove();
11854 this.view.purgeListeners();
11857 this.list.dom.innerHTML = '';
11861 this.store.un('beforeload', this.onBeforeLoad, this);
11862 this.store.un('load', this.onLoad, this);
11863 this.store.un('loadexception', this.onLoadException, this);
11865 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11869 fireKey : function(e){
11870 if(e.isNavKeyPress() && !this.list.isVisible()){
11871 this.fireEvent("specialkey", this, e);
11876 onResize: function(w, h){
11877 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11879 // if(typeof w != 'number'){
11880 // // we do not handle it!?!?
11883 // var tw = this.trigger.getWidth();
11884 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11885 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11887 // this.inputEl().setWidth( this.adjustWidth('input', x));
11889 // //this.trigger.setStyle('left', x+'px');
11891 // if(this.list && this.listWidth === undefined){
11892 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11893 // this.list.setWidth(lw);
11894 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11902 * Allow or prevent the user from directly editing the field text. If false is passed,
11903 * the user will only be able to select from the items defined in the dropdown list. This method
11904 * is the runtime equivalent of setting the 'editable' config option at config time.
11905 * @param {Boolean} value True to allow the user to directly edit the field text
11907 setEditable : function(value){
11908 if(value == this.editable){
11911 this.editable = value;
11913 this.inputEl().dom.setAttribute('readOnly', true);
11914 this.inputEl().on('mousedown', this.onTriggerClick, this);
11915 this.inputEl().addClass('x-combo-noedit');
11917 this.inputEl().dom.setAttribute('readOnly', false);
11918 this.inputEl().un('mousedown', this.onTriggerClick, this);
11919 this.inputEl().removeClass('x-combo-noedit');
11925 onBeforeLoad : function(combo,opts){
11926 if(!this.hasFocus){
11930 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11932 this.restrictHeight();
11933 this.selectedIndex = -1;
11937 onLoad : function(){
11939 this.hasQuery = false;
11941 if(!this.hasFocus){
11945 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11946 this.loading.hide();
11949 if(this.store.getCount() > 0){
11951 this.restrictHeight();
11952 if(this.lastQuery == this.allQuery){
11953 if(this.editable && !this.tickable){
11954 this.inputEl().dom.select();
11958 !this.selectByValue(this.value, true) &&
11961 !this.store.lastOptions ||
11962 typeof(this.store.lastOptions.add) == 'undefined' ||
11963 this.store.lastOptions.add != true
11966 this.select(0, true);
11969 if(this.autoFocus){
11972 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11973 this.taTask.delay(this.typeAheadDelay);
11977 this.onEmptyResults();
11983 onLoadException : function()
11985 this.hasQuery = false;
11987 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11988 this.loading.hide();
11991 if(this.tickable && this.editable){
11997 Roo.log(this.store.reader.jsonData);
11998 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12000 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12006 onTypeAhead : function(){
12007 if(this.store.getCount() > 0){
12008 var r = this.store.getAt(0);
12009 var newValue = r.data[this.displayField];
12010 var len = newValue.length;
12011 var selStart = this.getRawValue().length;
12013 if(selStart != len){
12014 this.setRawValue(newValue);
12015 this.selectText(selStart, newValue.length);
12021 onSelect : function(record, index){
12023 if(this.fireEvent('beforeselect', this, record, index) !== false){
12025 this.setFromData(index > -1 ? record.data : false);
12028 this.fireEvent('select', this, record, index);
12033 * Returns the currently selected field value or empty string if no value is set.
12034 * @return {String} value The selected value
12036 getValue : function(){
12039 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12042 if(this.valueField){
12043 return typeof this.value != 'undefined' ? this.value : '';
12045 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12050 * Clears any text/value currently set in the field
12052 clearValue : function(){
12053 if(this.hiddenField){
12054 this.hiddenField.dom.value = '';
12057 this.setRawValue('');
12058 this.lastSelectionText = '';
12059 this.lastData = false;
12061 var close = this.closeTriggerEl();
12070 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12071 * will be displayed in the field. If the value does not match the data value of an existing item,
12072 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12073 * Otherwise the field will be blank (although the value will still be set).
12074 * @param {String} value The value to match
12076 setValue : function(v){
12083 if(this.valueField){
12084 var r = this.findRecord(this.valueField, v);
12086 text = r.data[this.displayField];
12087 }else if(this.valueNotFoundText !== undefined){
12088 text = this.valueNotFoundText;
12091 this.lastSelectionText = text;
12092 if(this.hiddenField){
12093 this.hiddenField.dom.value = v;
12095 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12098 var close = this.closeTriggerEl();
12101 (v.length || v * 1 > 0) ? close.show() : close.hide();
12105 * @property {Object} the last set data for the element
12110 * Sets the value of the field based on a object which is related to the record format for the store.
12111 * @param {Object} value the value to set as. or false on reset?
12113 setFromData : function(o){
12120 var dv = ''; // display value
12121 var vv = ''; // value value..
12123 if (this.displayField) {
12124 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12126 // this is an error condition!!!
12127 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12130 if(this.valueField){
12131 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12134 var close = this.closeTriggerEl();
12137 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12140 if(this.hiddenField){
12141 this.hiddenField.dom.value = vv;
12143 this.lastSelectionText = dv;
12144 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12148 // no hidden field.. - we store the value in 'value', but still display
12149 // display field!!!!
12150 this.lastSelectionText = dv;
12151 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12158 reset : function(){
12159 // overridden so that last data is reset..
12166 this.setValue(this.originalValue);
12167 this.clearInvalid();
12168 this.lastData = false;
12170 this.view.clearSelections();
12174 findRecord : function(prop, value){
12176 if(this.store.getCount() > 0){
12177 this.store.each(function(r){
12178 if(r.data[prop] == value){
12188 getName: function()
12190 // returns hidden if it's set..
12191 if (!this.rendered) {return ''};
12192 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12196 onViewMove : function(e, t){
12197 this.inKeyMode = false;
12201 onViewOver : function(e, t){
12202 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12205 var item = this.view.findItemFromChild(t);
12208 var index = this.view.indexOf(item);
12209 this.select(index, false);
12214 onViewClick : function(view, doFocus, el, e)
12216 var index = this.view.getSelectedIndexes()[0];
12218 var r = this.store.getAt(index);
12222 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12229 Roo.each(this.tickItems, function(v,k){
12231 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12232 _this.tickItems.splice(k, 1);
12234 if(typeof(e) == 'undefined' && view == false){
12235 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12247 this.tickItems.push(r.data);
12249 if(typeof(e) == 'undefined' && view == false){
12250 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12257 this.onSelect(r, index);
12259 if(doFocus !== false && !this.blockFocus){
12260 this.inputEl().focus();
12265 restrictHeight : function(){
12266 //this.innerList.dom.style.height = '';
12267 //var inner = this.innerList.dom;
12268 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12269 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12270 //this.list.beginUpdate();
12271 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12272 this.list.alignTo(this.inputEl(), this.listAlign);
12273 this.list.alignTo(this.inputEl(), this.listAlign);
12274 //this.list.endUpdate();
12278 onEmptyResults : function(){
12280 if(this.tickable && this.editable){
12281 this.restrictHeight();
12289 * Returns true if the dropdown list is expanded, else false.
12291 isExpanded : function(){
12292 return this.list.isVisible();
12296 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12297 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12298 * @param {String} value The data value of the item to select
12299 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12300 * selected item if it is not currently in view (defaults to true)
12301 * @return {Boolean} True if the value matched an item in the list, else false
12303 selectByValue : function(v, scrollIntoView){
12304 if(v !== undefined && v !== null){
12305 var r = this.findRecord(this.valueField || this.displayField, v);
12307 this.select(this.store.indexOf(r), scrollIntoView);
12315 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12316 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12317 * @param {Number} index The zero-based index of the list item to select
12318 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12319 * selected item if it is not currently in view (defaults to true)
12321 select : function(index, scrollIntoView){
12322 this.selectedIndex = index;
12323 this.view.select(index);
12324 if(scrollIntoView !== false){
12325 var el = this.view.getNode(index);
12327 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12330 this.list.scrollChildIntoView(el, false);
12336 selectNext : function(){
12337 var ct = this.store.getCount();
12339 if(this.selectedIndex == -1){
12341 }else if(this.selectedIndex < ct-1){
12342 this.select(this.selectedIndex+1);
12348 selectPrev : function(){
12349 var ct = this.store.getCount();
12351 if(this.selectedIndex == -1){
12353 }else if(this.selectedIndex != 0){
12354 this.select(this.selectedIndex-1);
12360 onKeyUp : function(e){
12361 if(this.editable !== false && !e.isSpecialKey()){
12362 this.lastKey = e.getKey();
12363 this.dqTask.delay(this.queryDelay);
12368 validateBlur : function(){
12369 return !this.list || !this.list.isVisible();
12373 initQuery : function(){
12375 var v = this.getRawValue();
12377 if(this.tickable && this.editable){
12378 v = this.tickableInputEl().getValue();
12385 doForce : function(){
12386 if(this.inputEl().dom.value.length > 0){
12387 this.inputEl().dom.value =
12388 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12394 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12395 * query allowing the query action to be canceled if needed.
12396 * @param {String} query The SQL query to execute
12397 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12398 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12399 * saved in the current store (defaults to false)
12401 doQuery : function(q, forceAll){
12403 if(q === undefined || q === null){
12408 forceAll: forceAll,
12412 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12417 forceAll = qe.forceAll;
12418 if(forceAll === true || (q.length >= this.minChars)){
12420 this.hasQuery = true;
12422 if(this.lastQuery != q || this.alwaysQuery){
12423 this.lastQuery = q;
12424 if(this.mode == 'local'){
12425 this.selectedIndex = -1;
12427 this.store.clearFilter();
12430 if(this.specialFilter){
12431 this.fireEvent('specialfilter', this);
12436 this.store.filter(this.displayField, q);
12439 this.store.fireEvent("datachanged", this.store);
12446 this.store.baseParams[this.queryParam] = q;
12448 var options = {params : this.getParams(q)};
12451 options.add = true;
12452 options.params.start = this.page * this.pageSize;
12455 this.store.load(options);
12458 * this code will make the page width larger, at the beginning, the list not align correctly,
12459 * we should expand the list on onLoad
12460 * so command out it
12465 this.selectedIndex = -1;
12470 this.loadNext = false;
12474 getParams : function(q){
12476 //p[this.queryParam] = q;
12480 p.limit = this.pageSize;
12486 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12488 collapse : function(){
12489 if(!this.isExpanded()){
12496 this.hasFocus = false;
12498 this.cancelBtn.hide();
12499 this.trigger.show();
12502 this.tickableInputEl().dom.value = '';
12503 this.tickableInputEl().blur();
12508 Roo.get(document).un('mousedown', this.collapseIf, this);
12509 Roo.get(document).un('mousewheel', this.collapseIf, this);
12510 if (!this.editable) {
12511 Roo.get(document).un('keydown', this.listKeyPress, this);
12513 this.fireEvent('collapse', this);
12517 collapseIf : function(e){
12518 var in_combo = e.within(this.el);
12519 var in_list = e.within(this.list);
12520 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12522 if (in_combo || in_list || is_list) {
12523 //e.stopPropagation();
12528 this.onTickableFooterButtonClick(e, false, false);
12536 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12538 expand : function(){
12540 if(this.isExpanded() || !this.hasFocus){
12544 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12545 this.list.setWidth(lw);
12552 this.restrictHeight();
12556 this.tickItems = Roo.apply([], this.item);
12559 this.cancelBtn.show();
12560 this.trigger.hide();
12563 this.tickableInputEl().focus();
12568 Roo.get(document).on('mousedown', this.collapseIf, this);
12569 Roo.get(document).on('mousewheel', this.collapseIf, this);
12570 if (!this.editable) {
12571 Roo.get(document).on('keydown', this.listKeyPress, this);
12574 this.fireEvent('expand', this);
12578 // Implements the default empty TriggerField.onTriggerClick function
12579 onTriggerClick : function(e)
12581 Roo.log('trigger click');
12583 if(this.disabled || !this.triggerList){
12588 this.loadNext = false;
12590 if(this.isExpanded()){
12592 if (!this.blockFocus) {
12593 this.inputEl().focus();
12597 this.hasFocus = true;
12598 if(this.triggerAction == 'all') {
12599 this.doQuery(this.allQuery, true);
12601 this.doQuery(this.getRawValue());
12603 if (!this.blockFocus) {
12604 this.inputEl().focus();
12609 onTickableTriggerClick : function(e)
12616 this.loadNext = false;
12617 this.hasFocus = true;
12619 if(this.triggerAction == 'all') {
12620 this.doQuery(this.allQuery, true);
12622 this.doQuery(this.getRawValue());
12626 onSearchFieldClick : function(e)
12628 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12629 this.onTickableFooterButtonClick(e, false, false);
12633 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12638 this.loadNext = false;
12639 this.hasFocus = true;
12641 if(this.triggerAction == 'all') {
12642 this.doQuery(this.allQuery, true);
12644 this.doQuery(this.getRawValue());
12648 listKeyPress : function(e)
12650 //Roo.log('listkeypress');
12651 // scroll to first matching element based on key pres..
12652 if (e.isSpecialKey()) {
12655 var k = String.fromCharCode(e.getKey()).toUpperCase();
12658 var csel = this.view.getSelectedNodes();
12659 var cselitem = false;
12661 var ix = this.view.indexOf(csel[0]);
12662 cselitem = this.store.getAt(ix);
12663 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12669 this.store.each(function(v) {
12671 // start at existing selection.
12672 if (cselitem.id == v.id) {
12678 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12679 match = this.store.indexOf(v);
12685 if (match === false) {
12686 return true; // no more action?
12689 this.view.select(match);
12690 var sn = Roo.get(this.view.getSelectedNodes()[0])
12691 sn.scrollIntoView(sn.dom.parentNode, false);
12694 onViewScroll : function(e, t){
12696 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){
12700 this.hasQuery = true;
12702 this.loading = this.list.select('.loading', true).first();
12704 if(this.loading === null){
12705 this.list.createChild({
12707 cls: 'loading select2-more-results select2-active',
12708 html: 'Loading more results...'
12711 this.loading = this.list.select('.loading', true).first();
12713 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12715 this.loading.hide();
12718 this.loading.show();
12723 this.loadNext = true;
12725 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12730 addItem : function(o)
12732 var dv = ''; // display value
12734 if (this.displayField) {
12735 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12737 // this is an error condition!!!
12738 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12745 var choice = this.choices.createChild({
12747 cls: 'select2-search-choice',
12756 cls: 'select2-search-choice-close',
12761 }, this.searchField);
12763 var close = choice.select('a.select2-search-choice-close', true).first()
12765 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12773 this.inputEl().dom.value = '';
12778 onRemoveItem : function(e, _self, o)
12780 e.preventDefault();
12782 this.lastItem = Roo.apply([], this.item);
12784 var index = this.item.indexOf(o.data) * 1;
12787 Roo.log('not this item?!');
12791 this.item.splice(index, 1);
12796 this.fireEvent('remove', this, e);
12802 syncValue : function()
12804 if(!this.item.length){
12811 Roo.each(this.item, function(i){
12812 if(_this.valueField){
12813 value.push(i[_this.valueField]);
12820 this.value = value.join(',');
12822 if(this.hiddenField){
12823 this.hiddenField.dom.value = this.value;
12826 this.store.fireEvent("datachanged", this.store);
12829 clearItem : function()
12831 if(!this.multiple){
12837 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12846 inputEl: function ()
12849 return this.searchField;
12851 return this.el.select('input.form-control',true).first();
12855 onTickableFooterButtonClick : function(e, btn, el)
12857 e.preventDefault();
12859 this.lastItem = Roo.apply([], this.item);
12861 if(btn && btn.name == 'cancel'){
12862 this.tickItems = Roo.apply([], this.item);
12871 Roo.each(this.tickItems, function(o){
12879 validate : function()
12881 var v = this.getRawValue();
12884 v = this.getValue();
12887 if(this.disabled || this.allowBlank || v.length){
12892 this.markInvalid();
12896 tickableInputEl : function()
12898 if(!this.tickable || !this.editable){
12899 return this.inputEl();
12902 return this.inputEl().select('.select2-search-field-input', true).first();
12908 * @cfg {Boolean} grow
12912 * @cfg {Number} growMin
12916 * @cfg {Number} growMax
12926 * Ext JS Library 1.1.1
12927 * Copyright(c) 2006-2007, Ext JS, LLC.
12929 * Originally Released Under LGPL - original licence link has changed is not relivant.
12932 * <script type="text/javascript">
12937 * @extends Roo.util.Observable
12938 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12939 * This class also supports single and multi selection modes. <br>
12940 * Create a data model bound view:
12942 var store = new Roo.data.Store(...);
12944 var view = new Roo.View({
12946 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12948 singleSelect: true,
12949 selectedClass: "ydataview-selected",
12953 // listen for node click?
12954 view.on("click", function(vw, index, node, e){
12955 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12959 dataModel.load("foobar.xml");
12961 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12963 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12964 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12966 * Note: old style constructor is still suported (container, template, config)
12969 * Create a new View
12970 * @param {Object} config The config object
12973 Roo.View = function(config, depreciated_tpl, depreciated_config){
12975 this.parent = false;
12977 if (typeof(depreciated_tpl) == 'undefined') {
12978 // new way.. - universal constructor.
12979 Roo.apply(this, config);
12980 this.el = Roo.get(this.el);
12983 this.el = Roo.get(config);
12984 this.tpl = depreciated_tpl;
12985 Roo.apply(this, depreciated_config);
12987 this.wrapEl = this.el.wrap().wrap();
12988 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12991 if(typeof(this.tpl) == "string"){
12992 this.tpl = new Roo.Template(this.tpl);
12994 // support xtype ctors..
12995 this.tpl = new Roo.factory(this.tpl, Roo);
12999 this.tpl.compile();
13004 * @event beforeclick
13005 * Fires before a click is processed. Returns false to cancel the default action.
13006 * @param {Roo.View} this
13007 * @param {Number} index The index of the target node
13008 * @param {HTMLElement} node The target node
13009 * @param {Roo.EventObject} e The raw event object
13011 "beforeclick" : true,
13014 * Fires when a template node is clicked.
13015 * @param {Roo.View} this
13016 * @param {Number} index The index of the target node
13017 * @param {HTMLElement} node The target node
13018 * @param {Roo.EventObject} e The raw event object
13023 * Fires when a template node is double clicked.
13024 * @param {Roo.View} this
13025 * @param {Number} index The index of the target node
13026 * @param {HTMLElement} node The target node
13027 * @param {Roo.EventObject} e The raw event object
13031 * @event contextmenu
13032 * Fires when a template node is right clicked.
13033 * @param {Roo.View} this
13034 * @param {Number} index The index of the target node
13035 * @param {HTMLElement} node The target node
13036 * @param {Roo.EventObject} e The raw event object
13038 "contextmenu" : true,
13040 * @event selectionchange
13041 * Fires when the selected nodes change.
13042 * @param {Roo.View} this
13043 * @param {Array} selections Array of the selected nodes
13045 "selectionchange" : true,
13048 * @event beforeselect
13049 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13050 * @param {Roo.View} this
13051 * @param {HTMLElement} node The node to be selected
13052 * @param {Array} selections Array of currently selected nodes
13054 "beforeselect" : true,
13056 * @event preparedata
13057 * Fires on every row to render, to allow you to change the data.
13058 * @param {Roo.View} this
13059 * @param {Object} data to be rendered (change this)
13061 "preparedata" : true
13069 "click": this.onClick,
13070 "dblclick": this.onDblClick,
13071 "contextmenu": this.onContextMenu,
13075 this.selections = [];
13077 this.cmp = new Roo.CompositeElementLite([]);
13079 this.store = Roo.factory(this.store, Roo.data);
13080 this.setStore(this.store, true);
13083 if ( this.footer && this.footer.xtype) {
13085 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13087 this.footer.dataSource = this.store
13088 this.footer.container = fctr;
13089 this.footer = Roo.factory(this.footer, Roo);
13090 fctr.insertFirst(this.el);
13092 // this is a bit insane - as the paging toolbar seems to detach the el..
13093 // dom.parentNode.parentNode.parentNode
13094 // they get detached?
13098 Roo.View.superclass.constructor.call(this);
13103 Roo.extend(Roo.View, Roo.util.Observable, {
13106 * @cfg {Roo.data.Store} store Data store to load data from.
13111 * @cfg {String|Roo.Element} el The container element.
13116 * @cfg {String|Roo.Template} tpl The template used by this View
13120 * @cfg {String} dataName the named area of the template to use as the data area
13121 * Works with domtemplates roo-name="name"
13125 * @cfg {String} selectedClass The css class to add to selected nodes
13127 selectedClass : "x-view-selected",
13129 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13134 * @cfg {String} text to display on mask (default Loading)
13138 * @cfg {Boolean} multiSelect Allow multiple selection
13140 multiSelect : false,
13142 * @cfg {Boolean} singleSelect Allow single selection
13144 singleSelect: false,
13147 * @cfg {Boolean} toggleSelect - selecting
13149 toggleSelect : false,
13152 * @cfg {Boolean} tickable - selecting
13157 * Returns the element this view is bound to.
13158 * @return {Roo.Element}
13160 getEl : function(){
13161 return this.wrapEl;
13167 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13169 refresh : function(){
13170 //Roo.log('refresh');
13173 // if we are using something like 'domtemplate', then
13174 // the what gets used is:
13175 // t.applySubtemplate(NAME, data, wrapping data..)
13176 // the outer template then get' applied with
13177 // the store 'extra data'
13178 // and the body get's added to the
13179 // roo-name="data" node?
13180 // <span class='roo-tpl-{name}'></span> ?????
13184 this.clearSelections();
13185 this.el.update("");
13187 var records = this.store.getRange();
13188 if(records.length < 1) {
13190 // is this valid?? = should it render a template??
13192 this.el.update(this.emptyText);
13196 if (this.dataName) {
13197 this.el.update(t.apply(this.store.meta)); //????
13198 el = this.el.child('.roo-tpl-' + this.dataName);
13201 for(var i = 0, len = records.length; i < len; i++){
13202 var data = this.prepareData(records[i].data, i, records[i]);
13203 this.fireEvent("preparedata", this, data, i, records[i]);
13205 var d = Roo.apply({}, data);
13208 Roo.apply(d, {'roo-id' : Roo.id()});
13212 Roo.each(this.parent.item, function(item){
13213 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13216 Roo.apply(d, {'roo-data-checked' : 'checked'});
13220 html[html.length] = Roo.util.Format.trim(
13222 t.applySubtemplate(this.dataName, d, this.store.meta) :
13229 el.update(html.join(""));
13230 this.nodes = el.dom.childNodes;
13231 this.updateIndexes(0);
13236 * Function to override to reformat the data that is sent to
13237 * the template for each node.
13238 * DEPRICATED - use the preparedata event handler.
13239 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13240 * a JSON object for an UpdateManager bound view).
13242 prepareData : function(data, index, record)
13244 this.fireEvent("preparedata", this, data, index, record);
13248 onUpdate : function(ds, record){
13249 // Roo.log('on update');
13250 this.clearSelections();
13251 var index = this.store.indexOf(record);
13252 var n = this.nodes[index];
13253 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13254 n.parentNode.removeChild(n);
13255 this.updateIndexes(index, index);
13261 onAdd : function(ds, records, index)
13263 //Roo.log(['on Add', ds, records, index] );
13264 this.clearSelections();
13265 if(this.nodes.length == 0){
13269 var n = this.nodes[index];
13270 for(var i = 0, len = records.length; i < len; i++){
13271 var d = this.prepareData(records[i].data, i, records[i]);
13273 this.tpl.insertBefore(n, d);
13276 this.tpl.append(this.el, d);
13279 this.updateIndexes(index);
13282 onRemove : function(ds, record, index){
13283 // Roo.log('onRemove');
13284 this.clearSelections();
13285 var el = this.dataName ?
13286 this.el.child('.roo-tpl-' + this.dataName) :
13289 el.dom.removeChild(this.nodes[index]);
13290 this.updateIndexes(index);
13294 * Refresh an individual node.
13295 * @param {Number} index
13297 refreshNode : function(index){
13298 this.onUpdate(this.store, this.store.getAt(index));
13301 updateIndexes : function(startIndex, endIndex){
13302 var ns = this.nodes;
13303 startIndex = startIndex || 0;
13304 endIndex = endIndex || ns.length - 1;
13305 for(var i = startIndex; i <= endIndex; i++){
13306 ns[i].nodeIndex = i;
13311 * Changes the data store this view uses and refresh the view.
13312 * @param {Store} store
13314 setStore : function(store, initial){
13315 if(!initial && this.store){
13316 this.store.un("datachanged", this.refresh);
13317 this.store.un("add", this.onAdd);
13318 this.store.un("remove", this.onRemove);
13319 this.store.un("update", this.onUpdate);
13320 this.store.un("clear", this.refresh);
13321 this.store.un("beforeload", this.onBeforeLoad);
13322 this.store.un("load", this.onLoad);
13323 this.store.un("loadexception", this.onLoad);
13327 store.on("datachanged", this.refresh, this);
13328 store.on("add", this.onAdd, this);
13329 store.on("remove", this.onRemove, this);
13330 store.on("update", this.onUpdate, this);
13331 store.on("clear", this.refresh, this);
13332 store.on("beforeload", this.onBeforeLoad, this);
13333 store.on("load", this.onLoad, this);
13334 store.on("loadexception", this.onLoad, this);
13342 * onbeforeLoad - masks the loading area.
13345 onBeforeLoad : function(store,opts)
13347 //Roo.log('onBeforeLoad');
13349 this.el.update("");
13351 this.el.mask(this.mask ? this.mask : "Loading" );
13353 onLoad : function ()
13360 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13361 * @param {HTMLElement} node
13362 * @return {HTMLElement} The template node
13364 findItemFromChild : function(node){
13365 var el = this.dataName ?
13366 this.el.child('.roo-tpl-' + this.dataName,true) :
13369 if(!node || node.parentNode == el){
13372 var p = node.parentNode;
13373 while(p && p != el){
13374 if(p.parentNode == el){
13383 onClick : function(e){
13384 var item = this.findItemFromChild(e.getTarget());
13386 var index = this.indexOf(item);
13387 if(this.onItemClick(item, index, e) !== false){
13388 this.fireEvent("click", this, index, item, e);
13391 this.clearSelections();
13396 onContextMenu : function(e){
13397 var item = this.findItemFromChild(e.getTarget());
13399 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13404 onDblClick : function(e){
13405 var item = this.findItemFromChild(e.getTarget());
13407 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13411 onItemClick : function(item, index, e)
13413 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13416 if (this.toggleSelect) {
13417 var m = this.isSelected(item) ? 'unselect' : 'select';
13420 _t[m](item, true, false);
13423 if(this.multiSelect || this.singleSelect){
13424 if(this.multiSelect && e.shiftKey && this.lastSelection){
13425 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13427 this.select(item, this.multiSelect && e.ctrlKey);
13428 this.lastSelection = item;
13431 if(!this.tickable){
13432 e.preventDefault();
13440 * Get the number of selected nodes.
13443 getSelectionCount : function(){
13444 return this.selections.length;
13448 * Get the currently selected nodes.
13449 * @return {Array} An array of HTMLElements
13451 getSelectedNodes : function(){
13452 return this.selections;
13456 * Get the indexes of the selected nodes.
13459 getSelectedIndexes : function(){
13460 var indexes = [], s = this.selections;
13461 for(var i = 0, len = s.length; i < len; i++){
13462 indexes.push(s[i].nodeIndex);
13468 * Clear all selections
13469 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13471 clearSelections : function(suppressEvent){
13472 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13473 this.cmp.elements = this.selections;
13474 this.cmp.removeClass(this.selectedClass);
13475 this.selections = [];
13476 if(!suppressEvent){
13477 this.fireEvent("selectionchange", this, this.selections);
13483 * Returns true if the passed node is selected
13484 * @param {HTMLElement/Number} node The node or node index
13485 * @return {Boolean}
13487 isSelected : function(node){
13488 var s = this.selections;
13492 node = this.getNode(node);
13493 return s.indexOf(node) !== -1;
13498 * @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
13499 * @param {Boolean} keepExisting (optional) true to keep existing selections
13500 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13502 select : function(nodeInfo, keepExisting, suppressEvent){
13503 if(nodeInfo instanceof Array){
13505 this.clearSelections(true);
13507 for(var i = 0, len = nodeInfo.length; i < len; i++){
13508 this.select(nodeInfo[i], true, true);
13512 var node = this.getNode(nodeInfo);
13513 if(!node || this.isSelected(node)){
13514 return; // already selected.
13517 this.clearSelections(true);
13520 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13521 Roo.fly(node).addClass(this.selectedClass);
13522 this.selections.push(node);
13523 if(!suppressEvent){
13524 this.fireEvent("selectionchange", this, this.selections);
13532 * @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
13533 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13534 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13536 unselect : function(nodeInfo, keepExisting, suppressEvent)
13538 if(nodeInfo instanceof Array){
13539 Roo.each(this.selections, function(s) {
13540 this.unselect(s, nodeInfo);
13544 var node = this.getNode(nodeInfo);
13545 if(!node || !this.isSelected(node)){
13546 //Roo.log("not selected");
13547 return; // not selected.
13551 Roo.each(this.selections, function(s) {
13553 Roo.fly(node).removeClass(this.selectedClass);
13560 this.selections= ns;
13561 this.fireEvent("selectionchange", this, this.selections);
13565 * Gets a template node.
13566 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13567 * @return {HTMLElement} The node or null if it wasn't found
13569 getNode : function(nodeInfo){
13570 if(typeof nodeInfo == "string"){
13571 return document.getElementById(nodeInfo);
13572 }else if(typeof nodeInfo == "number"){
13573 return this.nodes[nodeInfo];
13579 * Gets a range template nodes.
13580 * @param {Number} startIndex
13581 * @param {Number} endIndex
13582 * @return {Array} An array of nodes
13584 getNodes : function(start, end){
13585 var ns = this.nodes;
13586 start = start || 0;
13587 end = typeof end == "undefined" ? ns.length - 1 : end;
13590 for(var i = start; i <= end; i++){
13594 for(var i = start; i >= end; i--){
13602 * Finds the index of the passed node
13603 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13604 * @return {Number} The index of the node or -1
13606 indexOf : function(node){
13607 node = this.getNode(node);
13608 if(typeof node.nodeIndex == "number"){
13609 return node.nodeIndex;
13611 var ns = this.nodes;
13612 for(var i = 0, len = ns.length; i < len; i++){
13623 * based on jquery fullcalendar
13627 Roo.bootstrap = Roo.bootstrap || {};
13629 * @class Roo.bootstrap.Calendar
13630 * @extends Roo.bootstrap.Component
13631 * Bootstrap Calendar class
13632 * @cfg {Boolean} loadMask (true|false) default false
13633 * @cfg {Object} header generate the user specific header of the calendar, default false
13636 * Create a new Container
13637 * @param {Object} config The config object
13642 Roo.bootstrap.Calendar = function(config){
13643 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13647 * Fires when a date is selected
13648 * @param {DatePicker} this
13649 * @param {Date} date The selected date
13653 * @event monthchange
13654 * Fires when the displayed month changes
13655 * @param {DatePicker} this
13656 * @param {Date} date The selected month
13658 'monthchange': true,
13660 * @event evententer
13661 * Fires when mouse over an event
13662 * @param {Calendar} this
13663 * @param {event} Event
13665 'evententer': true,
13667 * @event eventleave
13668 * Fires when the mouse leaves an
13669 * @param {Calendar} this
13672 'eventleave': true,
13674 * @event eventclick
13675 * Fires when the mouse click an
13676 * @param {Calendar} this
13685 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13688 * @cfg {Number} startDay
13689 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13697 getAutoCreate : function(){
13700 var fc_button = function(name, corner, style, content ) {
13701 return Roo.apply({},{
13703 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13705 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13708 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13719 style : 'width:100%',
13726 cls : 'fc-header-left',
13728 fc_button('prev', 'left', 'arrow', '‹' ),
13729 fc_button('next', 'right', 'arrow', '›' ),
13730 { tag: 'span', cls: 'fc-header-space' },
13731 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13739 cls : 'fc-header-center',
13743 cls: 'fc-header-title',
13746 html : 'month / year'
13754 cls : 'fc-header-right',
13756 /* fc_button('month', 'left', '', 'month' ),
13757 fc_button('week', '', '', 'week' ),
13758 fc_button('day', 'right', '', 'day' )
13770 header = this.header;
13773 var cal_heads = function() {
13775 // fixme - handle this.
13777 for (var i =0; i < Date.dayNames.length; i++) {
13778 var d = Date.dayNames[i];
13781 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13782 html : d.substring(0,3)
13786 ret[0].cls += ' fc-first';
13787 ret[6].cls += ' fc-last';
13790 var cal_cell = function(n) {
13793 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13798 cls: 'fc-day-number',
13802 cls: 'fc-day-content',
13806 style: 'position: relative;' // height: 17px;
13818 var cal_rows = function() {
13821 for (var r = 0; r < 6; r++) {
13828 for (var i =0; i < Date.dayNames.length; i++) {
13829 var d = Date.dayNames[i];
13830 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13833 row.cn[0].cls+=' fc-first';
13834 row.cn[0].cn[0].style = 'min-height:90px';
13835 row.cn[6].cls+=' fc-last';
13839 ret[0].cls += ' fc-first';
13840 ret[4].cls += ' fc-prev-last';
13841 ret[5].cls += ' fc-last';
13848 cls: 'fc-border-separate',
13849 style : 'width:100%',
13857 cls : 'fc-first fc-last',
13875 cls : 'fc-content',
13876 style : "position: relative;",
13879 cls : 'fc-view fc-view-month fc-grid',
13880 style : 'position: relative',
13881 unselectable : 'on',
13884 cls : 'fc-event-container',
13885 style : 'position:absolute;z-index:8;top:0;left:0;'
13903 initEvents : function()
13906 throw "can not find store for calendar";
13912 style: "text-align:center",
13916 style: "background-color:white;width:50%;margin:250 auto",
13920 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13931 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13933 var size = this.el.select('.fc-content', true).first().getSize();
13934 this.maskEl.setSize(size.width, size.height);
13935 this.maskEl.enableDisplayMode("block");
13936 if(!this.loadMask){
13937 this.maskEl.hide();
13940 this.store = Roo.factory(this.store, Roo.data);
13941 this.store.on('load', this.onLoad, this);
13942 this.store.on('beforeload', this.onBeforeLoad, this);
13946 this.cells = this.el.select('.fc-day',true);
13947 //Roo.log(this.cells);
13948 this.textNodes = this.el.query('.fc-day-number');
13949 this.cells.addClassOnOver('fc-state-hover');
13951 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13952 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13953 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13954 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13956 this.on('monthchange', this.onMonthChange, this);
13958 this.update(new Date().clearTime());
13961 resize : function() {
13962 var sz = this.el.getSize();
13964 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13965 this.el.select('.fc-day-content div',true).setHeight(34);
13970 showPrevMonth : function(e){
13971 this.update(this.activeDate.add("mo", -1));
13973 showToday : function(e){
13974 this.update(new Date().clearTime());
13977 showNextMonth : function(e){
13978 this.update(this.activeDate.add("mo", 1));
13982 showPrevYear : function(){
13983 this.update(this.activeDate.add("y", -1));
13987 showNextYear : function(){
13988 this.update(this.activeDate.add("y", 1));
13993 update : function(date)
13995 var vd = this.activeDate;
13996 this.activeDate = date;
13997 // if(vd && this.el){
13998 // var t = date.getTime();
13999 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14000 // Roo.log('using add remove');
14002 // this.fireEvent('monthchange', this, date);
14004 // this.cells.removeClass("fc-state-highlight");
14005 // this.cells.each(function(c){
14006 // if(c.dateValue == t){
14007 // c.addClass("fc-state-highlight");
14008 // setTimeout(function(){
14009 // try{c.dom.firstChild.focus();}catch(e){}
14019 var days = date.getDaysInMonth();
14021 var firstOfMonth = date.getFirstDateOfMonth();
14022 var startingPos = firstOfMonth.getDay()-this.startDay;
14024 if(startingPos < this.startDay){
14028 var pm = date.add(Date.MONTH, -1);
14029 var prevStart = pm.getDaysInMonth()-startingPos;
14031 this.cells = this.el.select('.fc-day',true);
14032 this.textNodes = this.el.query('.fc-day-number');
14033 this.cells.addClassOnOver('fc-state-hover');
14035 var cells = this.cells.elements;
14036 var textEls = this.textNodes;
14038 Roo.each(cells, function(cell){
14039 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14042 days += startingPos;
14044 // convert everything to numbers so it's fast
14045 var day = 86400000;
14046 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14049 //Roo.log(prevStart);
14051 var today = new Date().clearTime().getTime();
14052 var sel = date.clearTime().getTime();
14053 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14054 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14055 var ddMatch = this.disabledDatesRE;
14056 var ddText = this.disabledDatesText;
14057 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14058 var ddaysText = this.disabledDaysText;
14059 var format = this.format;
14061 var setCellClass = function(cal, cell){
14065 //Roo.log('set Cell Class');
14067 var t = d.getTime();
14071 cell.dateValue = t;
14073 cell.className += " fc-today";
14074 cell.className += " fc-state-highlight";
14075 cell.title = cal.todayText;
14078 // disable highlight in other month..
14079 //cell.className += " fc-state-highlight";
14084 cell.className = " fc-state-disabled";
14085 cell.title = cal.minText;
14089 cell.className = " fc-state-disabled";
14090 cell.title = cal.maxText;
14094 if(ddays.indexOf(d.getDay()) != -1){
14095 cell.title = ddaysText;
14096 cell.className = " fc-state-disabled";
14099 if(ddMatch && format){
14100 var fvalue = d.dateFormat(format);
14101 if(ddMatch.test(fvalue)){
14102 cell.title = ddText.replace("%0", fvalue);
14103 cell.className = " fc-state-disabled";
14107 if (!cell.initialClassName) {
14108 cell.initialClassName = cell.dom.className;
14111 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14116 for(; i < startingPos; i++) {
14117 textEls[i].innerHTML = (++prevStart);
14118 d.setDate(d.getDate()+1);
14120 cells[i].className = "fc-past fc-other-month";
14121 setCellClass(this, cells[i]);
14126 for(; i < days; i++){
14127 intDay = i - startingPos + 1;
14128 textEls[i].innerHTML = (intDay);
14129 d.setDate(d.getDate()+1);
14131 cells[i].className = ''; // "x-date-active";
14132 setCellClass(this, cells[i]);
14136 for(; i < 42; i++) {
14137 textEls[i].innerHTML = (++extraDays);
14138 d.setDate(d.getDate()+1);
14140 cells[i].className = "fc-future fc-other-month";
14141 setCellClass(this, cells[i]);
14144 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14146 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14148 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14149 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14151 if(totalRows != 6){
14152 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14153 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14156 this.fireEvent('monthchange', this, date);
14160 if(!this.internalRender){
14161 var main = this.el.dom.firstChild;
14162 var w = main.offsetWidth;
14163 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14164 Roo.fly(main).setWidth(w);
14165 this.internalRender = true;
14166 // opera does not respect the auto grow header center column
14167 // then, after it gets a width opera refuses to recalculate
14168 // without a second pass
14169 if(Roo.isOpera && !this.secondPass){
14170 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14171 this.secondPass = true;
14172 this.update.defer(10, this, [date]);
14179 findCell : function(dt) {
14180 dt = dt.clearTime().getTime();
14182 this.cells.each(function(c){
14183 //Roo.log("check " +c.dateValue + '?=' + dt);
14184 if(c.dateValue == dt){
14194 findCells : function(ev) {
14195 var s = ev.start.clone().clearTime().getTime();
14197 var e= ev.end.clone().clearTime().getTime();
14200 this.cells.each(function(c){
14201 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14203 if(c.dateValue > e){
14206 if(c.dateValue < s){
14215 // findBestRow: function(cells)
14219 // for (var i =0 ; i < cells.length;i++) {
14220 // ret = Math.max(cells[i].rows || 0,ret);
14227 addItem : function(ev)
14229 // look for vertical location slot in
14230 var cells = this.findCells(ev);
14232 // ev.row = this.findBestRow(cells);
14234 // work out the location.
14238 for(var i =0; i < cells.length; i++) {
14240 cells[i].row = cells[0].row;
14243 cells[i].row = cells[i].row + 1;
14253 if (crow.start.getY() == cells[i].getY()) {
14255 crow.end = cells[i];
14272 cells[0].events.push(ev);
14274 this.calevents.push(ev);
14277 clearEvents: function() {
14279 if(!this.calevents){
14283 Roo.each(this.cells.elements, function(c){
14289 Roo.each(this.calevents, function(e) {
14290 Roo.each(e.els, function(el) {
14291 el.un('mouseenter' ,this.onEventEnter, this);
14292 el.un('mouseleave' ,this.onEventLeave, this);
14297 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14303 renderEvents: function()
14307 this.cells.each(function(c) {
14316 if(c.row != c.events.length){
14317 r = 4 - (4 - (c.row - c.events.length));
14320 c.events = ev.slice(0, r);
14321 c.more = ev.slice(r);
14323 if(c.more.length && c.more.length == 1){
14324 c.events.push(c.more.pop());
14327 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14331 this.cells.each(function(c) {
14333 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14336 for (var e = 0; e < c.events.length; e++){
14337 var ev = c.events[e];
14338 var rows = ev.rows;
14340 for(var i = 0; i < rows.length; i++) {
14342 // how many rows should it span..
14345 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14346 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14348 unselectable : "on",
14351 cls: 'fc-event-inner',
14355 // cls: 'fc-event-time',
14356 // html : cells.length > 1 ? '' : ev.time
14360 cls: 'fc-event-title',
14361 html : String.format('{0}', ev.title)
14368 cls: 'ui-resizable-handle ui-resizable-e',
14369 html : '  '
14376 cfg.cls += ' fc-event-start';
14378 if ((i+1) == rows.length) {
14379 cfg.cls += ' fc-event-end';
14382 var ctr = _this.el.select('.fc-event-container',true).first();
14383 var cg = ctr.createChild(cfg);
14385 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14386 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14388 var r = (c.more.length) ? 1 : 0;
14389 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14390 cg.setWidth(ebox.right - sbox.x -2);
14392 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14393 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14394 cg.on('click', _this.onEventClick, _this, ev);
14405 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14406 style : 'position: absolute',
14407 unselectable : "on",
14410 cls: 'fc-event-inner',
14414 cls: 'fc-event-title',
14422 cls: 'ui-resizable-handle ui-resizable-e',
14423 html : '  '
14429 var ctr = _this.el.select('.fc-event-container',true).first();
14430 var cg = ctr.createChild(cfg);
14432 var sbox = c.select('.fc-day-content',true).first().getBox();
14433 var ebox = c.select('.fc-day-content',true).first().getBox();
14435 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14436 cg.setWidth(ebox.right - sbox.x -2);
14438 cg.on('click', _this.onMoreEventClick, _this, c.more);
14448 onEventEnter: function (e, el,event,d) {
14449 this.fireEvent('evententer', this, el, event);
14452 onEventLeave: function (e, el,event,d) {
14453 this.fireEvent('eventleave', this, el, event);
14456 onEventClick: function (e, el,event,d) {
14457 this.fireEvent('eventclick', this, el, event);
14460 onMonthChange: function () {
14464 onMoreEventClick: function(e, el, more)
14468 this.calpopover.placement = 'right';
14469 this.calpopover.setTitle('More');
14471 this.calpopover.setContent('');
14473 var ctr = this.calpopover.el.select('.popover-content', true).first();
14475 Roo.each(more, function(m){
14477 cls : 'fc-event-hori fc-event-draggable',
14480 var cg = ctr.createChild(cfg);
14482 cg.on('click', _this.onEventClick, _this, m);
14485 this.calpopover.show(el);
14490 onLoad: function ()
14492 this.calevents = [];
14495 if(this.store.getCount() > 0){
14496 this.store.data.each(function(d){
14499 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14500 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14501 time : d.data.start_time,
14502 title : d.data.title,
14503 description : d.data.description,
14504 venue : d.data.venue
14509 this.renderEvents();
14511 if(this.calevents.length && this.loadMask){
14512 this.maskEl.hide();
14516 onBeforeLoad: function()
14518 this.clearEvents();
14520 this.maskEl.show();
14534 * @class Roo.bootstrap.Popover
14535 * @extends Roo.bootstrap.Component
14536 * Bootstrap Popover class
14537 * @cfg {String} html contents of the popover (or false to use children..)
14538 * @cfg {String} title of popover (or false to hide)
14539 * @cfg {String} placement how it is placed
14540 * @cfg {String} trigger click || hover (or false to trigger manually)
14541 * @cfg {String} over what (parent or false to trigger manually.)
14542 * @cfg {Number} delay - delay before showing
14545 * Create a new Popover
14546 * @param {Object} config The config object
14549 Roo.bootstrap.Popover = function(config){
14550 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14553 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14555 title: 'Fill in a title',
14558 placement : 'right',
14559 trigger : 'hover', // hover
14565 can_build_overlaid : false,
14567 getChildContainer : function()
14569 return this.el.select('.popover-content',true).first();
14572 getAutoCreate : function(){
14573 Roo.log('make popover?');
14575 cls : 'popover roo-dynamic',
14576 style: 'display:block',
14582 cls : 'popover-inner',
14586 cls: 'popover-title',
14590 cls : 'popover-content',
14601 setTitle: function(str)
14603 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14605 setContent: function(str)
14607 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14609 // as it get's added to the bottom of the page.
14610 onRender : function(ct, position)
14612 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14614 var cfg = Roo.apply({}, this.getAutoCreate());
14618 cfg.cls += ' ' + this.cls;
14621 cfg.style = this.style;
14623 Roo.log("adding to ")
14624 this.el = Roo.get(document.body).createChild(cfg, position);
14630 initEvents : function()
14632 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14633 this.el.enableDisplayMode('block');
14635 if (this.over === false) {
14638 if (this.triggers === false) {
14641 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14642 var triggers = this.trigger ? this.trigger.split(' ') : [];
14643 Roo.each(triggers, function(trigger) {
14645 if (trigger == 'click') {
14646 on_el.on('click', this.toggle, this);
14647 } else if (trigger != 'manual') {
14648 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14649 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14651 on_el.on(eventIn ,this.enter, this);
14652 on_el.on(eventOut, this.leave, this);
14663 toggle : function () {
14664 this.hoverState == 'in' ? this.leave() : this.enter();
14667 enter : function () {
14670 clearTimeout(this.timeout);
14672 this.hoverState = 'in';
14674 if (!this.delay || !this.delay.show) {
14679 this.timeout = setTimeout(function () {
14680 if (_t.hoverState == 'in') {
14683 }, this.delay.show)
14685 leave : function() {
14686 clearTimeout(this.timeout);
14688 this.hoverState = 'out';
14690 if (!this.delay || !this.delay.hide) {
14695 this.timeout = setTimeout(function () {
14696 if (_t.hoverState == 'out') {
14699 }, this.delay.hide)
14702 show : function (on_el)
14705 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14708 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14709 if (this.html !== false) {
14710 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14712 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14713 if (!this.title.length) {
14714 this.el.select('.popover-title',true).hide();
14717 var placement = typeof this.placement == 'function' ?
14718 this.placement.call(this, this.el, on_el) :
14721 var autoToken = /\s?auto?\s?/i;
14722 var autoPlace = autoToken.test(placement);
14724 placement = placement.replace(autoToken, '') || 'top';
14728 //this.el.setXY([0,0]);
14730 this.el.dom.style.display='block';
14731 this.el.addClass(placement);
14733 //this.el.appendTo(on_el);
14735 var p = this.getPosition();
14736 var box = this.el.getBox();
14741 var align = Roo.bootstrap.Popover.alignment[placement];
14742 this.el.alignTo(on_el, align[0],align[1]);
14743 //var arrow = this.el.select('.arrow',true).first();
14744 //arrow.set(align[2],
14746 this.el.addClass('in');
14747 this.hoverState = null;
14749 if (this.el.hasClass('fade')) {
14756 this.el.setXY([0,0]);
14757 this.el.removeClass('in');
14764 Roo.bootstrap.Popover.alignment = {
14765 'left' : ['r-l', [-10,0], 'right'],
14766 'right' : ['l-r', [10,0], 'left'],
14767 'bottom' : ['t-b', [0,10], 'top'],
14768 'top' : [ 'b-t', [0,-10], 'bottom']
14779 * @class Roo.bootstrap.Progress
14780 * @extends Roo.bootstrap.Component
14781 * Bootstrap Progress class
14782 * @cfg {Boolean} striped striped of the progress bar
14783 * @cfg {Boolean} active animated of the progress bar
14787 * Create a new Progress
14788 * @param {Object} config The config object
14791 Roo.bootstrap.Progress = function(config){
14792 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14795 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14800 getAutoCreate : function(){
14808 cfg.cls += ' progress-striped';
14812 cfg.cls += ' active';
14831 * @class Roo.bootstrap.ProgressBar
14832 * @extends Roo.bootstrap.Component
14833 * Bootstrap ProgressBar class
14834 * @cfg {Number} aria_valuenow aria-value now
14835 * @cfg {Number} aria_valuemin aria-value min
14836 * @cfg {Number} aria_valuemax aria-value max
14837 * @cfg {String} label label for the progress bar
14838 * @cfg {String} panel (success | info | warning | danger )
14839 * @cfg {String} role role of the progress bar
14840 * @cfg {String} sr_only text
14844 * Create a new ProgressBar
14845 * @param {Object} config The config object
14848 Roo.bootstrap.ProgressBar = function(config){
14849 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14852 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14856 aria_valuemax : 100,
14862 getAutoCreate : function()
14867 cls: 'progress-bar',
14868 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14880 cfg.role = this.role;
14883 if(this.aria_valuenow){
14884 cfg['aria-valuenow'] = this.aria_valuenow;
14887 if(this.aria_valuemin){
14888 cfg['aria-valuemin'] = this.aria_valuemin;
14891 if(this.aria_valuemax){
14892 cfg['aria-valuemax'] = this.aria_valuemax;
14895 if(this.label && !this.sr_only){
14896 cfg.html = this.label;
14900 cfg.cls += ' progress-bar-' + this.panel;
14906 update : function(aria_valuenow)
14908 this.aria_valuenow = aria_valuenow;
14910 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14925 * @class Roo.bootstrap.TabGroup
14926 * @extends Roo.bootstrap.Column
14927 * Bootstrap Column class
14928 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14929 * @cfg {Boolean} carousel true to make the group behave like a carousel
14930 * @cfg {Number} bullets show the panel pointer.. default 0
14931 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14932 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14933 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14936 * Create a new TabGroup
14937 * @param {Object} config The config object
14940 Roo.bootstrap.TabGroup = function(config){
14941 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14943 this.navId = Roo.id();
14946 Roo.bootstrap.TabGroup.register(this);
14950 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14953 transition : false,
14958 slideOnTouch : false,
14960 getAutoCreate : function()
14962 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14964 cfg.cls += ' tab-content';
14966 Roo.log('get auto create...............');
14968 if (this.carousel) {
14969 cfg.cls += ' carousel slide';
14972 cls : 'carousel-inner'
14975 if(this.bullets > 0 && !Roo.isTouch){
14978 cls : 'carousel-bullets',
14982 if(this.bullets_cls){
14983 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14986 for (var i = 0; i < this.bullets; i++){
14988 cls : 'bullet bullet-' + i
14996 cfg.cn[0].cn = bullets;
15003 initEvents: function()
15005 Roo.log('-------- init events on tab group ---------');
15007 if(this.bullets > 0 && !Roo.isTouch){
15013 if(Roo.isTouch && this.slideOnTouch){
15014 this.el.on("touchstart", this.onTouchStart, this);
15017 if(this.autoslide){
15020 this.slideFn = window.setInterval(function() {
15021 _this.showPanelNext();
15027 onTouchStart : function(e, el, o)
15029 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15033 this.showPanelNext();
15036 getChildContainer : function()
15038 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15042 * register a Navigation item
15043 * @param {Roo.bootstrap.NavItem} the navitem to add
15045 register : function(item)
15047 this.tabs.push( item);
15048 item.navId = this.navId; // not really needed..
15052 getActivePanel : function()
15055 Roo.each(this.tabs, function(t) {
15065 getPanelByName : function(n)
15068 Roo.each(this.tabs, function(t) {
15069 if (t.tabId == n) {
15077 indexOfPanel : function(p)
15080 Roo.each(this.tabs, function(t,i) {
15081 if (t.tabId == p.tabId) {
15090 * show a specific panel
15091 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15092 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15094 showPanel : function (pan)
15096 if(this.transition){
15097 Roo.log("waiting for the transitionend");
15101 if (typeof(pan) == 'number') {
15102 pan = this.tabs[pan];
15104 if (typeof(pan) == 'string') {
15105 pan = this.getPanelByName(pan);
15107 if (pan.tabId == this.getActivePanel().tabId) {
15110 var cur = this.getActivePanel();
15112 if (false === cur.fireEvent('beforedeactivate')) {
15116 if(this.bullets > 0 && !Roo.isTouch){
15117 this.setActiveBullet(this.indexOfPanel(pan));
15120 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15122 this.transition = true;
15123 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15124 var lr = dir == 'next' ? 'left' : 'right';
15125 pan.el.addClass(dir); // or prev
15126 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15127 cur.el.addClass(lr); // or right
15128 pan.el.addClass(lr);
15131 cur.el.on('transitionend', function() {
15132 Roo.log("trans end?");
15134 pan.el.removeClass([lr,dir]);
15135 pan.setActive(true);
15137 cur.el.removeClass([lr]);
15138 cur.setActive(false);
15140 _this.transition = false;
15142 }, this, { single: true } );
15147 cur.setActive(false);
15148 pan.setActive(true);
15153 showPanelNext : function()
15155 var i = this.indexOfPanel(this.getActivePanel());
15157 if (i >= this.tabs.length - 1 && !this.autoslide) {
15161 if (i >= this.tabs.length - 1 && this.autoslide) {
15165 this.showPanel(this.tabs[i+1]);
15168 showPanelPrev : function()
15170 var i = this.indexOfPanel(this.getActivePanel());
15172 if (i < 1 && !this.autoslide) {
15176 if (i < 1 && this.autoslide) {
15177 i = this.tabs.length;
15180 this.showPanel(this.tabs[i-1]);
15183 initBullet : function()
15191 for (var i = 0; i < this.bullets; i++){
15192 var bullet = this.el.select('.bullet-' + i, true).first();
15198 bullet.on('click', (function(e, el, o, ii, t){
15200 e.preventDefault();
15202 _this.showPanel(ii);
15204 if(_this.autoslide && _this.slideFn){
15205 clearInterval(_this.slideFn);
15206 _this.slideFn = window.setInterval(function() {
15207 _this.showPanelNext();
15211 }).createDelegate(this, [i, bullet], true));
15215 setActiveBullet : function(i)
15221 Roo.each(this.el.select('.bullet', true).elements, function(el){
15222 el.removeClass('selected');
15225 var bullet = this.el.select('.bullet-' + i, true).first();
15231 bullet.addClass('selected');
15242 Roo.apply(Roo.bootstrap.TabGroup, {
15246 * register a Navigation Group
15247 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15249 register : function(navgrp)
15251 this.groups[navgrp.navId] = navgrp;
15255 * fetch a Navigation Group based on the navigation ID
15256 * if one does not exist , it will get created.
15257 * @param {string} the navgroup to add
15258 * @returns {Roo.bootstrap.NavGroup} the navgroup
15260 get: function(navId) {
15261 if (typeof(this.groups[navId]) == 'undefined') {
15262 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15264 return this.groups[navId] ;
15279 * @class Roo.bootstrap.TabPanel
15280 * @extends Roo.bootstrap.Component
15281 * Bootstrap TabPanel class
15282 * @cfg {Boolean} active panel active
15283 * @cfg {String} html panel content
15284 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15285 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15289 * Create a new TabPanel
15290 * @param {Object} config The config object
15293 Roo.bootstrap.TabPanel = function(config){
15294 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15298 * Fires when the active status changes
15299 * @param {Roo.bootstrap.TabPanel} this
15300 * @param {Boolean} state the new state
15305 * @event beforedeactivate
15306 * Fires before a tab is de-activated - can be used to do validation on a form.
15307 * @param {Roo.bootstrap.TabPanel} this
15308 * @return {Boolean} false if there is an error
15311 'beforedeactivate': true
15314 this.tabId = this.tabId || Roo.id();
15318 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15325 getAutoCreate : function(){
15328 // item is needed for carousel - not sure if it has any effect otherwise
15329 cls: 'tab-pane item',
15330 html: this.html || ''
15334 cfg.cls += ' active';
15338 cfg.tabId = this.tabId;
15345 initEvents: function()
15347 Roo.log('-------- init events on tab panel ---------');
15349 var p = this.parent();
15350 this.navId = this.navId || p.navId;
15352 if (typeof(this.navId) != 'undefined') {
15353 // not really needed.. but just in case.. parent should be a NavGroup.
15354 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15355 Roo.log(['register', tg, this]);
15358 var i = tg.tabs.length - 1;
15360 if(this.active && tg.bullets > 0 && i < tg.bullets){
15361 tg.setActiveBullet(i);
15368 onRender : function(ct, position)
15370 // Roo.log("Call onRender: " + this.xtype);
15372 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15380 setActive: function(state)
15382 Roo.log("panel - set active " + this.tabId + "=" + state);
15384 this.active = state;
15386 this.el.removeClass('active');
15388 } else if (!this.el.hasClass('active')) {
15389 this.el.addClass('active');
15392 this.fireEvent('changed', this, state);
15409 * @class Roo.bootstrap.DateField
15410 * @extends Roo.bootstrap.Input
15411 * Bootstrap DateField class
15412 * @cfg {Number} weekStart default 0
15413 * @cfg {String} viewMode default empty, (months|years)
15414 * @cfg {String} minViewMode default empty, (months|years)
15415 * @cfg {Number} startDate default -Infinity
15416 * @cfg {Number} endDate default Infinity
15417 * @cfg {Boolean} todayHighlight default false
15418 * @cfg {Boolean} todayBtn default false
15419 * @cfg {Boolean} calendarWeeks default false
15420 * @cfg {Object} daysOfWeekDisabled default empty
15421 * @cfg {Boolean} singleMode default false (true | false)
15423 * @cfg {Boolean} keyboardNavigation default true
15424 * @cfg {String} language default en
15427 * Create a new DateField
15428 * @param {Object} config The config object
15431 Roo.bootstrap.DateField = function(config){
15432 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15436 * Fires when this field show.
15437 * @param {Roo.bootstrap.DateField} this
15438 * @param {Mixed} date The date value
15443 * Fires when this field hide.
15444 * @param {Roo.bootstrap.DateField} this
15445 * @param {Mixed} date The date value
15450 * Fires when select a date.
15451 * @param {Roo.bootstrap.DateField} this
15452 * @param {Mixed} date The date value
15458 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15461 * @cfg {String} format
15462 * The default date format string which can be overriden for localization support. The format must be
15463 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15467 * @cfg {String} altFormats
15468 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15469 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15471 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15479 todayHighlight : false,
15485 keyboardNavigation: true,
15487 calendarWeeks: false,
15489 startDate: -Infinity,
15493 daysOfWeekDisabled: [],
15497 singleMode : false,
15499 UTCDate: function()
15501 return new Date(Date.UTC.apply(Date, arguments));
15504 UTCToday: function()
15506 var today = new Date();
15507 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15510 getDate: function() {
15511 var d = this.getUTCDate();
15512 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15515 getUTCDate: function() {
15519 setDate: function(d) {
15520 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15523 setUTCDate: function(d) {
15525 this.setValue(this.formatDate(this.date));
15528 onRender: function(ct, position)
15531 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15533 this.language = this.language || 'en';
15534 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15535 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15537 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15538 this.format = this.format || 'm/d/y';
15539 this.isInline = false;
15540 this.isInput = true;
15541 this.component = this.el.select('.add-on', true).first() || false;
15542 this.component = (this.component && this.component.length === 0) ? false : this.component;
15543 this.hasInput = this.component && this.inputEL().length;
15545 if (typeof(this.minViewMode === 'string')) {
15546 switch (this.minViewMode) {
15548 this.minViewMode = 1;
15551 this.minViewMode = 2;
15554 this.minViewMode = 0;
15559 if (typeof(this.viewMode === 'string')) {
15560 switch (this.viewMode) {
15573 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15575 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15577 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15579 this.picker().on('mousedown', this.onMousedown, this);
15580 this.picker().on('click', this.onClick, this);
15582 this.picker().addClass('datepicker-dropdown');
15584 this.startViewMode = this.viewMode;
15586 if(this.singleMode){
15587 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15588 v.setVisibilityMode(Roo.Element.DISPLAY)
15592 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15593 v.setStyle('width', '189px');
15597 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15598 if(!this.calendarWeeks){
15603 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15604 v.attr('colspan', function(i, val){
15605 return parseInt(val) + 1;
15610 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15612 this.setStartDate(this.startDate);
15613 this.setEndDate(this.endDate);
15615 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15622 if(this.isInline) {
15627 picker : function()
15629 return this.pickerEl;
15630 // return this.el.select('.datepicker', true).first();
15633 fillDow: function()
15635 var dowCnt = this.weekStart;
15644 if(this.calendarWeeks){
15652 while (dowCnt < this.weekStart + 7) {
15656 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15660 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15663 fillMonths: function()
15666 var months = this.picker().select('>.datepicker-months td', true).first();
15668 months.dom.innerHTML = '';
15674 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15677 months.createChild(month);
15684 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;
15686 if (this.date < this.startDate) {
15687 this.viewDate = new Date(this.startDate);
15688 } else if (this.date > this.endDate) {
15689 this.viewDate = new Date(this.endDate);
15691 this.viewDate = new Date(this.date);
15699 var d = new Date(this.viewDate),
15700 year = d.getUTCFullYear(),
15701 month = d.getUTCMonth(),
15702 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15703 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15704 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15705 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15706 currentDate = this.date && this.date.valueOf(),
15707 today = this.UTCToday();
15709 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15711 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15713 // this.picker.select('>tfoot th.today').
15714 // .text(dates[this.language].today)
15715 // .toggle(this.todayBtn !== false);
15717 this.updateNavArrows();
15720 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15722 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15724 prevMonth.setUTCDate(day);
15726 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15728 var nextMonth = new Date(prevMonth);
15730 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15732 nextMonth = nextMonth.valueOf();
15734 var fillMonths = false;
15736 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15738 while(prevMonth.valueOf() < nextMonth) {
15741 if (prevMonth.getUTCDay() === this.weekStart) {
15743 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15751 if(this.calendarWeeks){
15752 // ISO 8601: First week contains first thursday.
15753 // ISO also states week starts on Monday, but we can be more abstract here.
15755 // Start of current week: based on weekstart/current date
15756 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15757 // Thursday of this week
15758 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15759 // First Thursday of year, year from thursday
15760 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15761 // Calendar week: ms between thursdays, div ms per day, div 7 days
15762 calWeek = (th - yth) / 864e5 / 7 + 1;
15764 fillMonths.cn.push({
15772 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15774 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15777 if (this.todayHighlight &&
15778 prevMonth.getUTCFullYear() == today.getFullYear() &&
15779 prevMonth.getUTCMonth() == today.getMonth() &&
15780 prevMonth.getUTCDate() == today.getDate()) {
15781 clsName += ' today';
15784 if (currentDate && prevMonth.valueOf() === currentDate) {
15785 clsName += ' active';
15788 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15789 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15790 clsName += ' disabled';
15793 fillMonths.cn.push({
15795 cls: 'day ' + clsName,
15796 html: prevMonth.getDate()
15799 prevMonth.setDate(prevMonth.getDate()+1);
15802 var currentYear = this.date && this.date.getUTCFullYear();
15803 var currentMonth = this.date && this.date.getUTCMonth();
15805 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15807 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15808 v.removeClass('active');
15810 if(currentYear === year && k === currentMonth){
15811 v.addClass('active');
15814 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15815 v.addClass('disabled');
15821 year = parseInt(year/10, 10) * 10;
15823 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15825 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15828 for (var i = -1; i < 11; i++) {
15829 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15831 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15839 showMode: function(dir)
15842 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15845 Roo.each(this.picker().select('>div',true).elements, function(v){
15846 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15849 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15854 if(this.isInline) return;
15856 this.picker().removeClass(['bottom', 'top']);
15858 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15860 * place to the top of element!
15864 this.picker().addClass('top');
15865 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15870 this.picker().addClass('bottom');
15872 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15875 parseDate : function(value)
15877 if(!value || value instanceof Date){
15880 var v = Date.parseDate(value, this.format);
15881 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15882 v = Date.parseDate(value, 'Y-m-d');
15884 if(!v && this.altFormats){
15885 if(!this.altFormatsArray){
15886 this.altFormatsArray = this.altFormats.split("|");
15888 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15889 v = Date.parseDate(value, this.altFormatsArray[i]);
15895 formatDate : function(date, fmt)
15897 return (!date || !(date instanceof Date)) ?
15898 date : date.dateFormat(fmt || this.format);
15901 onFocus : function()
15903 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15907 onBlur : function()
15909 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15911 var d = this.inputEl().getValue();
15920 this.picker().show();
15924 this.fireEvent('show', this, this.date);
15929 if(this.isInline) return;
15930 this.picker().hide();
15931 this.viewMode = this.startViewMode;
15934 this.fireEvent('hide', this, this.date);
15938 onMousedown: function(e)
15940 e.stopPropagation();
15941 e.preventDefault();
15946 Roo.bootstrap.DateField.superclass.keyup.call(this);
15950 setValue: function(v)
15953 // v can be a string or a date..
15956 var d = new Date(this.parseDate(v) ).clearTime();
15958 if(isNaN(d.getTime())){
15959 this.date = this.viewDate = '';
15960 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15964 v = this.formatDate(d);
15966 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15968 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15972 this.fireEvent('select', this, this.date);
15976 getValue: function()
15978 return this.formatDate(this.date);
15981 fireKey: function(e)
15983 if (!this.picker().isVisible()){
15984 if (e.keyCode == 27) // allow escape to hide and re-show picker
15989 var dateChanged = false,
15991 newDate, newViewDate;
15996 e.preventDefault();
16000 if (!this.keyboardNavigation) break;
16001 dir = e.keyCode == 37 ? -1 : 1;
16004 newDate = this.moveYear(this.date, dir);
16005 newViewDate = this.moveYear(this.viewDate, dir);
16006 } else if (e.shiftKey){
16007 newDate = this.moveMonth(this.date, dir);
16008 newViewDate = this.moveMonth(this.viewDate, dir);
16010 newDate = new Date(this.date);
16011 newDate.setUTCDate(this.date.getUTCDate() + dir);
16012 newViewDate = new Date(this.viewDate);
16013 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16015 if (this.dateWithinRange(newDate)){
16016 this.date = newDate;
16017 this.viewDate = newViewDate;
16018 this.setValue(this.formatDate(this.date));
16020 e.preventDefault();
16021 dateChanged = true;
16026 if (!this.keyboardNavigation) break;
16027 dir = e.keyCode == 38 ? -1 : 1;
16029 newDate = this.moveYear(this.date, dir);
16030 newViewDate = this.moveYear(this.viewDate, dir);
16031 } else if (e.shiftKey){
16032 newDate = this.moveMonth(this.date, dir);
16033 newViewDate = this.moveMonth(this.viewDate, dir);
16035 newDate = new Date(this.date);
16036 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16037 newViewDate = new Date(this.viewDate);
16038 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16040 if (this.dateWithinRange(newDate)){
16041 this.date = newDate;
16042 this.viewDate = newViewDate;
16043 this.setValue(this.formatDate(this.date));
16045 e.preventDefault();
16046 dateChanged = true;
16050 this.setValue(this.formatDate(this.date));
16052 e.preventDefault();
16055 this.setValue(this.formatDate(this.date));
16069 onClick: function(e)
16071 e.stopPropagation();
16072 e.preventDefault();
16074 var target = e.getTarget();
16076 if(target.nodeName.toLowerCase() === 'i'){
16077 target = Roo.get(target).dom.parentNode;
16080 var nodeName = target.nodeName;
16081 var className = target.className;
16082 var html = target.innerHTML;
16083 //Roo.log(nodeName);
16085 switch(nodeName.toLowerCase()) {
16087 switch(className) {
16093 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16094 switch(this.viewMode){
16096 this.viewDate = this.moveMonth(this.viewDate, dir);
16100 this.viewDate = this.moveYear(this.viewDate, dir);
16106 var date = new Date();
16107 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16109 this.setValue(this.formatDate(this.date));
16116 if (className.indexOf('disabled') < 0) {
16117 this.viewDate.setUTCDate(1);
16118 if (className.indexOf('month') > -1) {
16119 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16121 var year = parseInt(html, 10) || 0;
16122 this.viewDate.setUTCFullYear(year);
16126 if(this.singleMode){
16127 this.setValue(this.formatDate(this.viewDate));
16138 //Roo.log(className);
16139 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16140 var day = parseInt(html, 10) || 1;
16141 var year = this.viewDate.getUTCFullYear(),
16142 month = this.viewDate.getUTCMonth();
16144 if (className.indexOf('old') > -1) {
16151 } else if (className.indexOf('new') > -1) {
16159 //Roo.log([year,month,day]);
16160 this.date = this.UTCDate(year, month, day,0,0,0,0);
16161 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16163 //Roo.log(this.formatDate(this.date));
16164 this.setValue(this.formatDate(this.date));
16171 setStartDate: function(startDate)
16173 this.startDate = startDate || -Infinity;
16174 if (this.startDate !== -Infinity) {
16175 this.startDate = this.parseDate(this.startDate);
16178 this.updateNavArrows();
16181 setEndDate: function(endDate)
16183 this.endDate = endDate || Infinity;
16184 if (this.endDate !== Infinity) {
16185 this.endDate = this.parseDate(this.endDate);
16188 this.updateNavArrows();
16191 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16193 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16194 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16195 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16197 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16198 return parseInt(d, 10);
16201 this.updateNavArrows();
16204 updateNavArrows: function()
16206 if(this.singleMode){
16210 var d = new Date(this.viewDate),
16211 year = d.getUTCFullYear(),
16212 month = d.getUTCMonth();
16214 Roo.each(this.picker().select('.prev', true).elements, function(v){
16216 switch (this.viewMode) {
16219 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16225 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16232 Roo.each(this.picker().select('.next', true).elements, function(v){
16234 switch (this.viewMode) {
16237 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16243 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16251 moveMonth: function(date, dir)
16253 if (!dir) return date;
16254 var new_date = new Date(date.valueOf()),
16255 day = new_date.getUTCDate(),
16256 month = new_date.getUTCMonth(),
16257 mag = Math.abs(dir),
16259 dir = dir > 0 ? 1 : -1;
16262 // If going back one month, make sure month is not current month
16263 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16265 return new_date.getUTCMonth() == month;
16267 // If going forward one month, make sure month is as expected
16268 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16270 return new_date.getUTCMonth() != new_month;
16272 new_month = month + dir;
16273 new_date.setUTCMonth(new_month);
16274 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16275 if (new_month < 0 || new_month > 11)
16276 new_month = (new_month + 12) % 12;
16278 // For magnitudes >1, move one month at a time...
16279 for (var i=0; i<mag; i++)
16280 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16281 new_date = this.moveMonth(new_date, dir);
16282 // ...then reset the day, keeping it in the new month
16283 new_month = new_date.getUTCMonth();
16284 new_date.setUTCDate(day);
16286 return new_month != new_date.getUTCMonth();
16289 // Common date-resetting loop -- if date is beyond end of month, make it
16292 new_date.setUTCDate(--day);
16293 new_date.setUTCMonth(new_month);
16298 moveYear: function(date, dir)
16300 return this.moveMonth(date, dir*12);
16303 dateWithinRange: function(date)
16305 return date >= this.startDate && date <= this.endDate;
16311 this.picker().remove();
16316 Roo.apply(Roo.bootstrap.DateField, {
16327 html: '<i class="fa fa-arrow-left"/>'
16337 html: '<i class="fa fa-arrow-right"/>'
16379 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16380 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16381 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16382 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16383 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16396 navFnc: 'FullYear',
16401 navFnc: 'FullYear',
16406 Roo.apply(Roo.bootstrap.DateField, {
16410 cls: 'datepicker dropdown-menu roo-dynamic',
16414 cls: 'datepicker-days',
16418 cls: 'table-condensed',
16420 Roo.bootstrap.DateField.head,
16424 Roo.bootstrap.DateField.footer
16431 cls: 'datepicker-months',
16435 cls: 'table-condensed',
16437 Roo.bootstrap.DateField.head,
16438 Roo.bootstrap.DateField.content,
16439 Roo.bootstrap.DateField.footer
16446 cls: 'datepicker-years',
16450 cls: 'table-condensed',
16452 Roo.bootstrap.DateField.head,
16453 Roo.bootstrap.DateField.content,
16454 Roo.bootstrap.DateField.footer
16473 * @class Roo.bootstrap.TimeField
16474 * @extends Roo.bootstrap.Input
16475 * Bootstrap DateField class
16479 * Create a new TimeField
16480 * @param {Object} config The config object
16483 Roo.bootstrap.TimeField = function(config){
16484 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16488 * Fires when this field show.
16489 * @param {Roo.bootstrap.DateField} thisthis
16490 * @param {Mixed} date The date value
16495 * Fires when this field hide.
16496 * @param {Roo.bootstrap.DateField} this
16497 * @param {Mixed} date The date value
16502 * Fires when select a date.
16503 * @param {Roo.bootstrap.DateField} this
16504 * @param {Mixed} date The date value
16510 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16513 * @cfg {String} format
16514 * The default time format string which can be overriden for localization support. The format must be
16515 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16519 onRender: function(ct, position)
16522 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16524 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16526 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16528 this.pop = this.picker().select('>.datepicker-time',true).first();
16529 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16531 this.picker().on('mousedown', this.onMousedown, this);
16532 this.picker().on('click', this.onClick, this);
16534 this.picker().addClass('datepicker-dropdown');
16539 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16540 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16541 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16542 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16543 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16544 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16548 fireKey: function(e){
16549 if (!this.picker().isVisible()){
16550 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16556 e.preventDefault();
16564 this.onTogglePeriod();
16567 this.onIncrementMinutes();
16570 this.onDecrementMinutes();
16579 onClick: function(e) {
16580 e.stopPropagation();
16581 e.preventDefault();
16584 picker : function()
16586 return this.el.select('.datepicker', true).first();
16589 fillTime: function()
16591 var time = this.pop.select('tbody', true).first();
16593 time.dom.innerHTML = '';
16608 cls: 'hours-up glyphicon glyphicon-chevron-up'
16628 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16649 cls: 'timepicker-hour',
16664 cls: 'timepicker-minute',
16679 cls: 'btn btn-primary period',
16701 cls: 'hours-down glyphicon glyphicon-chevron-down'
16721 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16739 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16746 var hours = this.time.getHours();
16747 var minutes = this.time.getMinutes();
16760 hours = hours - 12;
16764 hours = '0' + hours;
16768 minutes = '0' + minutes;
16771 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16772 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16773 this.pop.select('button', true).first().dom.innerHTML = period;
16779 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16781 var cls = ['bottom'];
16783 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16790 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16795 this.picker().addClass(cls.join('-'));
16799 Roo.each(cls, function(c){
16801 _this.picker().setTop(_this.inputEl().getHeight());
16805 _this.picker().setTop(0 - _this.picker().getHeight());
16810 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16814 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16821 onFocus : function()
16823 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16827 onBlur : function()
16829 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16835 this.picker().show();
16840 this.fireEvent('show', this, this.date);
16845 this.picker().hide();
16848 this.fireEvent('hide', this, this.date);
16851 setTime : function()
16854 this.setValue(this.time.format(this.format));
16856 this.fireEvent('select', this, this.date);
16861 onMousedown: function(e){
16862 e.stopPropagation();
16863 e.preventDefault();
16866 onIncrementHours: function()
16868 Roo.log('onIncrementHours');
16869 this.time = this.time.add(Date.HOUR, 1);
16874 onDecrementHours: function()
16876 Roo.log('onDecrementHours');
16877 this.time = this.time.add(Date.HOUR, -1);
16881 onIncrementMinutes: function()
16883 Roo.log('onIncrementMinutes');
16884 this.time = this.time.add(Date.MINUTE, 1);
16888 onDecrementMinutes: function()
16890 Roo.log('onDecrementMinutes');
16891 this.time = this.time.add(Date.MINUTE, -1);
16895 onTogglePeriod: function()
16897 Roo.log('onTogglePeriod');
16898 this.time = this.time.add(Date.HOUR, 12);
16905 Roo.apply(Roo.bootstrap.TimeField, {
16935 cls: 'btn btn-info ok',
16947 Roo.apply(Roo.bootstrap.TimeField, {
16951 cls: 'datepicker dropdown-menu',
16955 cls: 'datepicker-time',
16959 cls: 'table-condensed',
16961 Roo.bootstrap.TimeField.content,
16962 Roo.bootstrap.TimeField.footer
16981 * @class Roo.bootstrap.MonthField
16982 * @extends Roo.bootstrap.Input
16983 * Bootstrap MonthField class
16985 * @cfg {String} language default en
16988 * Create a new MonthField
16989 * @param {Object} config The config object
16992 Roo.bootstrap.MonthField = function(config){
16993 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16998 * Fires when this field show.
16999 * @param {Roo.bootstrap.MonthField} this
17000 * @param {Mixed} date The date value
17005 * Fires when this field hide.
17006 * @param {Roo.bootstrap.MonthField} this
17007 * @param {Mixed} date The date value
17012 * Fires when select a date.
17013 * @param {Roo.bootstrap.MonthField} this
17014 * @param {String} oldvalue The old value
17015 * @param {String} newvalue The new value
17021 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17023 onRender: function(ct, position)
17026 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17028 this.language = this.language || 'en';
17029 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17030 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17032 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17033 this.isInline = false;
17034 this.isInput = true;
17035 this.component = this.el.select('.add-on', true).first() || false;
17036 this.component = (this.component && this.component.length === 0) ? false : this.component;
17037 this.hasInput = this.component && this.inputEL().length;
17039 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17041 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17043 this.picker().on('mousedown', this.onMousedown, this);
17044 this.picker().on('click', this.onClick, this);
17046 this.picker().addClass('datepicker-dropdown');
17048 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17049 v.setStyle('width', '189px');
17056 if(this.isInline) {
17062 setValue: function(v, suppressEvent)
17064 var o = this.getValue();
17066 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17070 if(suppressEvent !== true){
17071 this.fireEvent('select', this, o, v);
17076 getValue: function()
17081 onClick: function(e)
17083 e.stopPropagation();
17084 e.preventDefault();
17086 var target = e.getTarget();
17088 if(target.nodeName.toLowerCase() === 'i'){
17089 target = Roo.get(target).dom.parentNode;
17092 var nodeName = target.nodeName;
17093 var className = target.className;
17094 var html = target.innerHTML;
17096 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17100 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17102 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17108 picker : function()
17110 return this.pickerEl;
17113 fillMonths: function()
17116 var months = this.picker().select('>.datepicker-months td', true).first();
17118 months.dom.innerHTML = '';
17124 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17127 months.createChild(month);
17136 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17137 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17140 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17141 e.removeClass('active');
17143 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17144 e.addClass('active');
17151 if(this.isInline) return;
17153 this.picker().removeClass(['bottom', 'top']);
17155 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17157 * place to the top of element!
17161 this.picker().addClass('top');
17162 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17167 this.picker().addClass('bottom');
17169 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17172 onFocus : function()
17174 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17178 onBlur : function()
17180 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17182 var d = this.inputEl().getValue();
17191 this.picker().show();
17192 this.picker().select('>.datepicker-months', true).first().show();
17196 this.fireEvent('show', this, this.date);
17201 if(this.isInline) return;
17202 this.picker().hide();
17203 this.fireEvent('hide', this, this.date);
17207 onMousedown: function(e)
17209 e.stopPropagation();
17210 e.preventDefault();
17215 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17219 fireKey: function(e)
17221 if (!this.picker().isVisible()){
17222 if (e.keyCode == 27) // allow escape to hide and re-show picker
17232 e.preventDefault();
17236 dir = e.keyCode == 37 ? -1 : 1;
17238 this.vIndex = this.vIndex + dir;
17240 if(this.vIndex < 0){
17244 if(this.vIndex > 11){
17248 if(isNaN(this.vIndex)){
17252 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17258 dir = e.keyCode == 38 ? -1 : 1;
17260 this.vIndex = this.vIndex + dir * 4;
17262 if(this.vIndex < 0){
17266 if(this.vIndex > 11){
17270 if(isNaN(this.vIndex)){
17274 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17279 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17280 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17284 e.preventDefault();
17287 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17288 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17304 this.picker().remove();
17309 Roo.apply(Roo.bootstrap.MonthField, {
17328 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17329 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17334 Roo.apply(Roo.bootstrap.MonthField, {
17338 cls: 'datepicker dropdown-menu roo-dynamic',
17342 cls: 'datepicker-months',
17346 cls: 'table-condensed',
17348 Roo.bootstrap.DateField.content
17368 * @class Roo.bootstrap.CheckBox
17369 * @extends Roo.bootstrap.Input
17370 * Bootstrap CheckBox class
17372 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17373 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17374 * @cfg {String} boxLabel The text that appears beside the checkbox
17375 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17376 * @cfg {Boolean} checked initnal the element
17377 * @cfg {Boolean} inline inline the element (default false)
17378 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17381 * Create a new CheckBox
17382 * @param {Object} config The config object
17385 Roo.bootstrap.CheckBox = function(config){
17386 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17391 * Fires when the element is checked or unchecked.
17392 * @param {Roo.bootstrap.CheckBox} this This input
17393 * @param {Boolean} checked The new checked value
17400 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17402 inputType: 'checkbox',
17410 getAutoCreate : function()
17412 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17418 cfg.cls = 'form-group ' + this.inputType; //input-group
17421 cfg.cls += ' ' + this.inputType + '-inline';
17427 type : this.inputType,
17428 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17429 cls : 'roo-' + this.inputType, //'form-box',
17430 placeholder : this.placeholder || ''
17434 if (this.weight) { // Validity check?
17435 cfg.cls += " " + this.inputType + "-" + this.weight;
17438 if (this.disabled) {
17439 input.disabled=true;
17443 input.checked = this.checked;
17447 input.name = this.name;
17451 input.cls += ' input-' + this.size;
17456 ['xs','sm','md','lg'].map(function(size){
17457 if (settings[size]) {
17458 cfg.cls += ' col-' + size + '-' + settings[size];
17462 var inputblock = input;
17464 if (this.before || this.after) {
17467 cls : 'input-group',
17472 inputblock.cn.push({
17474 cls : 'input-group-addon',
17479 inputblock.cn.push(input);
17482 inputblock.cn.push({
17484 cls : 'input-group-addon',
17491 if (align ==='left' && this.fieldLabel.length) {
17492 Roo.log("left and has label");
17498 cls : 'control-label col-md-' + this.labelWidth,
17499 html : this.fieldLabel
17503 cls : "col-md-" + (12 - this.labelWidth),
17510 } else if ( this.fieldLabel.length) {
17515 tag: this.boxLabel ? 'span' : 'label',
17517 cls: 'control-label box-input-label',
17518 //cls : 'input-group-addon',
17519 html : this.fieldLabel
17529 Roo.log(" no label && no align");
17530 cfg.cn = [ inputblock ] ;
17535 var boxLabelCfg = {
17537 //'for': id, // box label is handled by onclick - so no for...
17539 html: this.boxLabel
17543 boxLabelCfg.tooltip = this.tooltip;
17546 cfg.cn.push(boxLabelCfg);
17556 * return the real input element.
17558 inputEl: function ()
17560 return this.el.select('input.roo-' + this.inputType,true).first();
17563 labelEl: function()
17565 return this.el.select('label.control-label',true).first();
17567 /* depricated... */
17571 return this.labelEl();
17574 initEvents : function()
17576 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17578 this.inputEl().on('click', this.onClick, this);
17580 if (this.boxLabel) {
17581 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17584 this.startValue = this.getValue();
17587 Roo.bootstrap.CheckBox.register(this);
17591 onClick : function()
17593 this.setChecked(!this.checked);
17596 setChecked : function(state,suppressEvent)
17598 this.startValue = this.getValue();
17600 if(this.inputType == 'radio'){
17602 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17603 e.dom.checked = false;
17606 this.inputEl().dom.checked = true;
17608 this.inputEl().dom.value = this.inputValue;
17610 if(suppressEvent !== true){
17611 this.fireEvent('check', this, true);
17619 this.checked = state;
17621 this.inputEl().dom.checked = state;
17623 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17625 if(suppressEvent !== true){
17626 this.fireEvent('check', this, state);
17632 getValue : function()
17634 if(this.inputType == 'radio'){
17635 return this.getGroupValue();
17638 return this.inputEl().getValue();
17642 getGroupValue : function()
17644 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17648 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17651 setValue : function(v,suppressEvent)
17653 if(this.inputType == 'radio'){
17654 this.setGroupValue(v, suppressEvent);
17658 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17663 setGroupValue : function(v, suppressEvent)
17665 this.startValue = this.getValue();
17667 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17668 e.dom.checked = false;
17670 if(e.dom.value == v){
17671 e.dom.checked = true;
17675 if(suppressEvent !== true){
17676 this.fireEvent('check', this, true);
17684 validate : function()
17688 (this.inputType == 'radio' && this.validateRadio()) ||
17689 (this.inputType == 'checkbox' && this.validateCheckbox())
17695 this.markInvalid();
17699 validateRadio : function()
17703 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17704 if(!e.dom.checked){
17716 validateCheckbox : function()
17719 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17722 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17730 for(var i in group){
17735 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17742 * Mark this field as valid
17744 markValid : function()
17746 if(this.allowBlank){
17752 this.fireEvent('valid', this);
17754 if(this.inputType == 'radio'){
17755 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17756 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17757 e.findParent('.form-group', false, true).addClass(_this.validClass);
17764 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17765 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17769 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17775 for(var i in group){
17776 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17777 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17782 * Mark this field as invalid
17783 * @param {String} msg The validation message
17785 markInvalid : function(msg)
17787 if(this.allowBlank){
17793 this.fireEvent('invalid', this, msg);
17795 if(this.inputType == 'radio'){
17796 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17797 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17798 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17805 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17806 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17810 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17816 for(var i in group){
17817 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17818 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17825 Roo.apply(Roo.bootstrap.CheckBox, {
17830 * register a CheckBox Group
17831 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17833 register : function(checkbox)
17835 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17836 this.groups[checkbox.groupId] = {};
17839 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17843 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17847 * fetch a CheckBox Group based on the group ID
17848 * @param {string} the group ID
17849 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17851 get: function(groupId) {
17852 if (typeof(this.groups[groupId]) == 'undefined') {
17856 return this.groups[groupId] ;
17868 *<div class="radio">
17870 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17871 Option one is this and that—be sure to include why it's great
17878 *<label class="radio-inline">fieldLabel</label>
17879 *<label class="radio-inline">
17880 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17888 * @class Roo.bootstrap.Radio
17889 * @extends Roo.bootstrap.CheckBox
17890 * Bootstrap Radio class
17893 * Create a new Radio
17894 * @param {Object} config The config object
17897 Roo.bootstrap.Radio = function(config){
17898 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17902 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17904 inputType: 'radio',
17908 getAutoCreate : function()
17910 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17911 align = align || 'left'; // default...
17918 tag : this.inline ? 'span' : 'div',
17923 var inline = this.inline ? ' radio-inline' : '';
17927 // does not need for, as we wrap the input with it..
17929 cls : 'control-label box-label' + inline,
17932 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17936 //cls : 'control-label' + inline,
17937 html : this.fieldLabel,
17938 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17947 type : this.inputType,
17948 //value : (!this.checked) ? this.valueOff : this.inputValue,
17949 value : this.inputValue,
17951 placeholder : this.placeholder || '' // ?? needed????
17954 if (this.weight) { // Validity check?
17955 input.cls += " radio-" + this.weight;
17957 if (this.disabled) {
17958 input.disabled=true;
17962 input.checked = this.checked;
17966 input.name = this.name;
17970 input.cls += ' input-' + this.size;
17973 //?? can span's inline have a width??
17976 ['xs','sm','md','lg'].map(function(size){
17977 if (settings[size]) {
17978 cfg.cls += ' col-' + size + '-' + settings[size];
17982 var inputblock = input;
17984 if (this.before || this.after) {
17987 cls : 'input-group',
17992 inputblock.cn.push({
17994 cls : 'input-group-addon',
17998 inputblock.cn.push(input);
18000 inputblock.cn.push({
18002 cls : 'input-group-addon',
18010 if (this.fieldLabel && this.fieldLabel.length) {
18011 cfg.cn.push(fieldLabel);
18014 // normal bootstrap puts the input inside the label.
18015 // however with our styled version - it has to go after the input.
18017 //lbl.cn.push(inputblock);
18021 cls: 'radio' + inline,
18028 cfg.cn.push( lblwrap);
18033 html: this.boxLabel
18042 initEvents : function()
18044 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18046 this.inputEl().on('click', this.onClick, this);
18047 if (this.boxLabel) {
18048 Roo.log('find label')
18049 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18054 inputEl: function ()
18056 return this.el.select('input.roo-radio',true).first();
18058 onClick : function()
18061 this.setChecked(true);
18064 setChecked : function(state,suppressEvent)
18067 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18068 v.dom.checked = false;
18071 Roo.log(this.inputEl().dom);
18072 this.checked = state;
18073 this.inputEl().dom.checked = state;
18075 if(suppressEvent !== true){
18076 this.fireEvent('check', this, state);
18079 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18083 getGroupValue : function()
18086 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18087 if(v.dom.checked == true){
18088 value = v.dom.value;
18096 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18097 * @return {Mixed} value The field value
18099 getValue : function(){
18100 return this.getGroupValue();
18106 //<script type="text/javascript">
18109 * Based Ext JS Library 1.1.1
18110 * Copyright(c) 2006-2007, Ext JS, LLC.
18116 * @class Roo.HtmlEditorCore
18117 * @extends Roo.Component
18118 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18120 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18123 Roo.HtmlEditorCore = function(config){
18126 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18131 * @event initialize
18132 * Fires when the editor is fully initialized (including the iframe)
18133 * @param {Roo.HtmlEditorCore} this
18138 * Fires when the editor is first receives the focus. Any insertion must wait
18139 * until after this event.
18140 * @param {Roo.HtmlEditorCore} this
18144 * @event beforesync
18145 * Fires before the textarea is updated with content from the editor iframe. Return false
18146 * to cancel the sync.
18147 * @param {Roo.HtmlEditorCore} this
18148 * @param {String} html
18152 * @event beforepush
18153 * Fires before the iframe editor is updated with content from the textarea. Return false
18154 * to cancel the push.
18155 * @param {Roo.HtmlEditorCore} this
18156 * @param {String} html
18161 * Fires when the textarea is updated with content from the editor iframe.
18162 * @param {Roo.HtmlEditorCore} this
18163 * @param {String} html
18168 * Fires when the iframe editor is updated with content from the textarea.
18169 * @param {Roo.HtmlEditorCore} this
18170 * @param {String} html
18175 * @event editorevent
18176 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18177 * @param {Roo.HtmlEditorCore} this
18183 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18185 // defaults : white / black...
18186 this.applyBlacklists();
18193 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18197 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18203 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18208 * @cfg {Number} height (in pixels)
18212 * @cfg {Number} width (in pixels)
18217 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18220 stylesheets: false,
18225 // private properties
18226 validationEvent : false,
18228 initialized : false,
18230 sourceEditMode : false,
18231 onFocus : Roo.emptyFn,
18233 hideMode:'offsets',
18237 // blacklist + whitelisted elements..
18244 * Protected method that will not generally be called directly. It
18245 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18246 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18248 getDocMarkup : function(){
18252 // inherit styels from page...??
18253 if (this.stylesheets === false) {
18255 Roo.get(document.head).select('style').each(function(node) {
18256 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18259 Roo.get(document.head).select('link').each(function(node) {
18260 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18263 } else if (!this.stylesheets.length) {
18265 st = '<style type="text/css">' +
18266 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18272 st += '<style type="text/css">' +
18273 'IMG { cursor: pointer } ' +
18277 return '<html><head>' + st +
18278 //<style type="text/css">' +
18279 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18281 ' </head><body class="roo-htmleditor-body"></body></html>';
18285 onRender : function(ct, position)
18288 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18289 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18292 this.el.dom.style.border = '0 none';
18293 this.el.dom.setAttribute('tabIndex', -1);
18294 this.el.addClass('x-hidden hide');
18298 if(Roo.isIE){ // fix IE 1px bogus margin
18299 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18303 this.frameId = Roo.id();
18307 var iframe = this.owner.wrap.createChild({
18309 cls: 'form-control', // bootstrap..
18311 name: this.frameId,
18312 frameBorder : 'no',
18313 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18318 this.iframe = iframe.dom;
18320 this.assignDocWin();
18322 this.doc.designMode = 'on';
18325 this.doc.write(this.getDocMarkup());
18329 var task = { // must defer to wait for browser to be ready
18331 //console.log("run task?" + this.doc.readyState);
18332 this.assignDocWin();
18333 if(this.doc.body || this.doc.readyState == 'complete'){
18335 this.doc.designMode="on";
18339 Roo.TaskMgr.stop(task);
18340 this.initEditor.defer(10, this);
18347 Roo.TaskMgr.start(task);
18352 onResize : function(w, h)
18354 Roo.log('resize: ' +w + ',' + h );
18355 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18359 if(typeof w == 'number'){
18361 this.iframe.style.width = w + 'px';
18363 if(typeof h == 'number'){
18365 this.iframe.style.height = h + 'px';
18367 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18374 * Toggles the editor between standard and source edit mode.
18375 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18377 toggleSourceEdit : function(sourceEditMode){
18379 this.sourceEditMode = sourceEditMode === true;
18381 if(this.sourceEditMode){
18383 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18386 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18387 //this.iframe.className = '';
18390 //this.setSize(this.owner.wrap.getSize());
18391 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18398 * Protected method that will not generally be called directly. If you need/want
18399 * custom HTML cleanup, this is the method you should override.
18400 * @param {String} html The HTML to be cleaned
18401 * return {String} The cleaned HTML
18403 cleanHtml : function(html){
18404 html = String(html);
18405 if(html.length > 5){
18406 if(Roo.isSafari){ // strip safari nonsense
18407 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18410 if(html == ' '){
18417 * HTML Editor -> Textarea
18418 * Protected method that will not generally be called directly. Syncs the contents
18419 * of the editor iframe with the textarea.
18421 syncValue : function(){
18422 if(this.initialized){
18423 var bd = (this.doc.body || this.doc.documentElement);
18424 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18425 var html = bd.innerHTML;
18427 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18428 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18430 html = '<div style="'+m[0]+'">' + html + '</div>';
18433 html = this.cleanHtml(html);
18434 // fix up the special chars.. normaly like back quotes in word...
18435 // however we do not want to do this with chinese..
18436 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18437 var cc = b.charCodeAt();
18439 (cc >= 0x4E00 && cc < 0xA000 ) ||
18440 (cc >= 0x3400 && cc < 0x4E00 ) ||
18441 (cc >= 0xf900 && cc < 0xfb00 )
18447 if(this.owner.fireEvent('beforesync', this, html) !== false){
18448 this.el.dom.value = html;
18449 this.owner.fireEvent('sync', this, html);
18455 * Protected method that will not generally be called directly. Pushes the value of the textarea
18456 * into the iframe editor.
18458 pushValue : function(){
18459 if(this.initialized){
18460 var v = this.el.dom.value.trim();
18462 // if(v.length < 1){
18466 if(this.owner.fireEvent('beforepush', this, v) !== false){
18467 var d = (this.doc.body || this.doc.documentElement);
18469 this.cleanUpPaste();
18470 this.el.dom.value = d.innerHTML;
18471 this.owner.fireEvent('push', this, v);
18477 deferFocus : function(){
18478 this.focus.defer(10, this);
18482 focus : function(){
18483 if(this.win && !this.sourceEditMode){
18490 assignDocWin: function()
18492 var iframe = this.iframe;
18495 this.doc = iframe.contentWindow.document;
18496 this.win = iframe.contentWindow;
18498 // if (!Roo.get(this.frameId)) {
18501 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18502 // this.win = Roo.get(this.frameId).dom.contentWindow;
18504 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18508 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18509 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18514 initEditor : function(){
18515 //console.log("INIT EDITOR");
18516 this.assignDocWin();
18520 this.doc.designMode="on";
18522 this.doc.write(this.getDocMarkup());
18525 var dbody = (this.doc.body || this.doc.documentElement);
18526 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18527 // this copies styles from the containing element into thsi one..
18528 // not sure why we need all of this..
18529 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18531 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18532 //ss['background-attachment'] = 'fixed'; // w3c
18533 dbody.bgProperties = 'fixed'; // ie
18534 //Roo.DomHelper.applyStyles(dbody, ss);
18535 Roo.EventManager.on(this.doc, {
18536 //'mousedown': this.onEditorEvent,
18537 'mouseup': this.onEditorEvent,
18538 'dblclick': this.onEditorEvent,
18539 'click': this.onEditorEvent,
18540 'keyup': this.onEditorEvent,
18545 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18547 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18548 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18550 this.initialized = true;
18552 this.owner.fireEvent('initialize', this);
18557 onDestroy : function(){
18563 //for (var i =0; i < this.toolbars.length;i++) {
18564 // // fixme - ask toolbars for heights?
18565 // this.toolbars[i].onDestroy();
18568 //this.wrap.dom.innerHTML = '';
18569 //this.wrap.remove();
18574 onFirstFocus : function(){
18576 this.assignDocWin();
18579 this.activated = true;
18582 if(Roo.isGecko){ // prevent silly gecko errors
18584 var s = this.win.getSelection();
18585 if(!s.focusNode || s.focusNode.nodeType != 3){
18586 var r = s.getRangeAt(0);
18587 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18592 this.execCmd('useCSS', true);
18593 this.execCmd('styleWithCSS', false);
18596 this.owner.fireEvent('activate', this);
18600 adjustFont: function(btn){
18601 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18602 //if(Roo.isSafari){ // safari
18605 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18606 if(Roo.isSafari){ // safari
18607 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18608 v = (v < 10) ? 10 : v;
18609 v = (v > 48) ? 48 : v;
18610 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18615 v = Math.max(1, v+adjust);
18617 this.execCmd('FontSize', v );
18620 onEditorEvent : function(e)
18622 this.owner.fireEvent('editorevent', this, e);
18623 // this.updateToolbar();
18624 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18627 insertTag : function(tg)
18629 // could be a bit smarter... -> wrap the current selected tRoo..
18630 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18632 range = this.createRange(this.getSelection());
18633 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18634 wrappingNode.appendChild(range.extractContents());
18635 range.insertNode(wrappingNode);
18642 this.execCmd("formatblock", tg);
18646 insertText : function(txt)
18650 var range = this.createRange();
18651 range.deleteContents();
18652 //alert(Sender.getAttribute('label'));
18654 range.insertNode(this.doc.createTextNode(txt));
18660 * Executes a Midas editor command on the editor document and performs necessary focus and
18661 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18662 * @param {String} cmd The Midas command
18663 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18665 relayCmd : function(cmd, value){
18667 this.execCmd(cmd, value);
18668 this.owner.fireEvent('editorevent', this);
18669 //this.updateToolbar();
18670 this.owner.deferFocus();
18674 * Executes a Midas editor command directly on the editor document.
18675 * For visual commands, you should use {@link #relayCmd} instead.
18676 * <b>This should only be called after the editor is initialized.</b>
18677 * @param {String} cmd The Midas command
18678 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18680 execCmd : function(cmd, value){
18681 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18688 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18690 * @param {String} text | dom node..
18692 insertAtCursor : function(text)
18697 if(!this.activated){
18703 var r = this.doc.selection.createRange();
18714 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18718 // from jquery ui (MIT licenced)
18720 var win = this.win;
18722 if (win.getSelection && win.getSelection().getRangeAt) {
18723 range = win.getSelection().getRangeAt(0);
18724 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18725 range.insertNode(node);
18726 } else if (win.document.selection && win.document.selection.createRange) {
18727 // no firefox support
18728 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18729 win.document.selection.createRange().pasteHTML(txt);
18731 // no firefox support
18732 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18733 this.execCmd('InsertHTML', txt);
18742 mozKeyPress : function(e){
18744 var c = e.getCharCode(), cmd;
18747 c = String.fromCharCode(c).toLowerCase();
18761 this.cleanUpPaste.defer(100, this);
18769 e.preventDefault();
18777 fixKeys : function(){ // load time branching for fastest keydown performance
18779 return function(e){
18780 var k = e.getKey(), r;
18783 r = this.doc.selection.createRange();
18786 r.pasteHTML('    ');
18793 r = this.doc.selection.createRange();
18795 var target = r.parentElement();
18796 if(!target || target.tagName.toLowerCase() != 'li'){
18798 r.pasteHTML('<br />');
18804 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18805 this.cleanUpPaste.defer(100, this);
18811 }else if(Roo.isOpera){
18812 return function(e){
18813 var k = e.getKey();
18817 this.execCmd('InsertHTML','    ');
18820 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18821 this.cleanUpPaste.defer(100, this);
18826 }else if(Roo.isSafari){
18827 return function(e){
18828 var k = e.getKey();
18832 this.execCmd('InsertText','\t');
18836 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18837 this.cleanUpPaste.defer(100, this);
18845 getAllAncestors: function()
18847 var p = this.getSelectedNode();
18850 a.push(p); // push blank onto stack..
18851 p = this.getParentElement();
18855 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18859 a.push(this.doc.body);
18863 lastSelNode : false,
18866 getSelection : function()
18868 this.assignDocWin();
18869 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18872 getSelectedNode: function()
18874 // this may only work on Gecko!!!
18876 // should we cache this!!!!
18881 var range = this.createRange(this.getSelection()).cloneRange();
18884 var parent = range.parentElement();
18886 var testRange = range.duplicate();
18887 testRange.moveToElementText(parent);
18888 if (testRange.inRange(range)) {
18891 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18894 parent = parent.parentElement;
18899 // is ancestor a text element.
18900 var ac = range.commonAncestorContainer;
18901 if (ac.nodeType == 3) {
18902 ac = ac.parentNode;
18905 var ar = ac.childNodes;
18908 var other_nodes = [];
18909 var has_other_nodes = false;
18910 for (var i=0;i<ar.length;i++) {
18911 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18914 // fullly contained node.
18916 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18921 // probably selected..
18922 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18923 other_nodes.push(ar[i]);
18927 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18932 has_other_nodes = true;
18934 if (!nodes.length && other_nodes.length) {
18935 nodes= other_nodes;
18937 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18943 createRange: function(sel)
18945 // this has strange effects when using with
18946 // top toolbar - not sure if it's a great idea.
18947 //this.editor.contentWindow.focus();
18948 if (typeof sel != "undefined") {
18950 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18952 return this.doc.createRange();
18955 return this.doc.createRange();
18958 getParentElement: function()
18961 this.assignDocWin();
18962 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18964 var range = this.createRange(sel);
18967 var p = range.commonAncestorContainer;
18968 while (p.nodeType == 3) { // text node
18979 * Range intersection.. the hard stuff...
18983 * [ -- selected range --- ]
18987 * if end is before start or hits it. fail.
18988 * if start is after end or hits it fail.
18990 * if either hits (but other is outside. - then it's not
18996 // @see http://www.thismuchiknow.co.uk/?p=64.
18997 rangeIntersectsNode : function(range, node)
18999 var nodeRange = node.ownerDocument.createRange();
19001 nodeRange.selectNode(node);
19003 nodeRange.selectNodeContents(node);
19006 var rangeStartRange = range.cloneRange();
19007 rangeStartRange.collapse(true);
19009 var rangeEndRange = range.cloneRange();
19010 rangeEndRange.collapse(false);
19012 var nodeStartRange = nodeRange.cloneRange();
19013 nodeStartRange.collapse(true);
19015 var nodeEndRange = nodeRange.cloneRange();
19016 nodeEndRange.collapse(false);
19018 return rangeStartRange.compareBoundaryPoints(
19019 Range.START_TO_START, nodeEndRange) == -1 &&
19020 rangeEndRange.compareBoundaryPoints(
19021 Range.START_TO_START, nodeStartRange) == 1;
19025 rangeCompareNode : function(range, node)
19027 var nodeRange = node.ownerDocument.createRange();
19029 nodeRange.selectNode(node);
19031 nodeRange.selectNodeContents(node);
19035 range.collapse(true);
19037 nodeRange.collapse(true);
19039 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19040 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19042 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19044 var nodeIsBefore = ss == 1;
19045 var nodeIsAfter = ee == -1;
19047 if (nodeIsBefore && nodeIsAfter)
19049 if (!nodeIsBefore && nodeIsAfter)
19050 return 1; //right trailed.
19052 if (nodeIsBefore && !nodeIsAfter)
19053 return 2; // left trailed.
19058 // private? - in a new class?
19059 cleanUpPaste : function()
19061 // cleans up the whole document..
19062 Roo.log('cleanuppaste');
19064 this.cleanUpChildren(this.doc.body);
19065 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19066 if (clean != this.doc.body.innerHTML) {
19067 this.doc.body.innerHTML = clean;
19072 cleanWordChars : function(input) {// change the chars to hex code
19073 var he = Roo.HtmlEditorCore;
19075 var output = input;
19076 Roo.each(he.swapCodes, function(sw) {
19077 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19079 output = output.replace(swapper, sw[1]);
19086 cleanUpChildren : function (n)
19088 if (!n.childNodes.length) {
19091 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19092 this.cleanUpChild(n.childNodes[i]);
19099 cleanUpChild : function (node)
19102 //console.log(node);
19103 if (node.nodeName == "#text") {
19104 // clean up silly Windows -- stuff?
19107 if (node.nodeName == "#comment") {
19108 node.parentNode.removeChild(node);
19109 // clean up silly Windows -- stuff?
19112 var lcname = node.tagName.toLowerCase();
19113 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19114 // whitelist of tags..
19116 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19118 node.parentNode.removeChild(node);
19123 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19125 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19126 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19128 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19129 // remove_keep_children = true;
19132 if (remove_keep_children) {
19133 this.cleanUpChildren(node);
19134 // inserts everything just before this node...
19135 while (node.childNodes.length) {
19136 var cn = node.childNodes[0];
19137 node.removeChild(cn);
19138 node.parentNode.insertBefore(cn, node);
19140 node.parentNode.removeChild(node);
19144 if (!node.attributes || !node.attributes.length) {
19145 this.cleanUpChildren(node);
19149 function cleanAttr(n,v)
19152 if (v.match(/^\./) || v.match(/^\//)) {
19155 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19158 if (v.match(/^#/)) {
19161 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19162 node.removeAttribute(n);
19166 var cwhite = this.cwhite;
19167 var cblack = this.cblack;
19169 function cleanStyle(n,v)
19171 if (v.match(/expression/)) { //XSS?? should we even bother..
19172 node.removeAttribute(n);
19176 var parts = v.split(/;/);
19179 Roo.each(parts, function(p) {
19180 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19184 var l = p.split(':').shift().replace(/\s+/g,'');
19185 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19187 if ( cwhite.length && cblack.indexOf(l) > -1) {
19188 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19189 //node.removeAttribute(n);
19193 // only allow 'c whitelisted system attributes'
19194 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19195 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19196 //node.removeAttribute(n);
19206 if (clean.length) {
19207 node.setAttribute(n, clean.join(';'));
19209 node.removeAttribute(n);
19215 for (var i = node.attributes.length-1; i > -1 ; i--) {
19216 var a = node.attributes[i];
19219 if (a.name.toLowerCase().substr(0,2)=='on') {
19220 node.removeAttribute(a.name);
19223 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19224 node.removeAttribute(a.name);
19227 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19228 cleanAttr(a.name,a.value); // fixme..
19231 if (a.name == 'style') {
19232 cleanStyle(a.name,a.value);
19235 /// clean up MS crap..
19236 // tecnically this should be a list of valid class'es..
19239 if (a.name == 'class') {
19240 if (a.value.match(/^Mso/)) {
19241 node.className = '';
19244 if (a.value.match(/body/)) {
19245 node.className = '';
19256 this.cleanUpChildren(node);
19262 * Clean up MS wordisms...
19264 cleanWord : function(node)
19269 this.cleanWord(this.doc.body);
19272 if (node.nodeName == "#text") {
19273 // clean up silly Windows -- stuff?
19276 if (node.nodeName == "#comment") {
19277 node.parentNode.removeChild(node);
19278 // clean up silly Windows -- stuff?
19282 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19283 node.parentNode.removeChild(node);
19287 // remove - but keep children..
19288 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19289 while (node.childNodes.length) {
19290 var cn = node.childNodes[0];
19291 node.removeChild(cn);
19292 node.parentNode.insertBefore(cn, node);
19294 node.parentNode.removeChild(node);
19295 this.iterateChildren(node, this.cleanWord);
19299 if (node.className.length) {
19301 var cn = node.className.split(/\W+/);
19303 Roo.each(cn, function(cls) {
19304 if (cls.match(/Mso[a-zA-Z]+/)) {
19309 node.className = cna.length ? cna.join(' ') : '';
19311 node.removeAttribute("class");
19315 if (node.hasAttribute("lang")) {
19316 node.removeAttribute("lang");
19319 if (node.hasAttribute("style")) {
19321 var styles = node.getAttribute("style").split(";");
19323 Roo.each(styles, function(s) {
19324 if (!s.match(/:/)) {
19327 var kv = s.split(":");
19328 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19331 // what ever is left... we allow.
19334 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19335 if (!nstyle.length) {
19336 node.removeAttribute('style');
19339 this.iterateChildren(node, this.cleanWord);
19345 * iterateChildren of a Node, calling fn each time, using this as the scole..
19346 * @param {DomNode} node node to iterate children of.
19347 * @param {Function} fn method of this class to call on each item.
19349 iterateChildren : function(node, fn)
19351 if (!node.childNodes.length) {
19354 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19355 fn.call(this, node.childNodes[i])
19361 * cleanTableWidths.
19363 * Quite often pasting from word etc.. results in tables with column and widths.
19364 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19367 cleanTableWidths : function(node)
19372 this.cleanTableWidths(this.doc.body);
19377 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19380 Roo.log(node.tagName);
19381 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19382 this.iterateChildren(node, this.cleanTableWidths);
19385 if (node.hasAttribute('width')) {
19386 node.removeAttribute('width');
19390 if (node.hasAttribute("style")) {
19393 var styles = node.getAttribute("style").split(";");
19395 Roo.each(styles, function(s) {
19396 if (!s.match(/:/)) {
19399 var kv = s.split(":");
19400 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
19403 // what ever is left... we allow.
19406 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19407 if (!nstyle.length) {
19408 node.removeAttribute('style');
19412 this.iterateChildren(node, this.cleanTableWidths);
19420 domToHTML : function(currentElement, depth, nopadtext) {
19422 depth = depth || 0;
19423 nopadtext = nopadtext || false;
19425 if (!currentElement) {
19426 return this.domToHTML(this.doc.body);
19429 //Roo.log(currentElement);
19431 var allText = false;
19432 var nodeName = currentElement.nodeName;
19433 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19435 if (nodeName == '#text') {
19437 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19442 if (nodeName != 'BODY') {
19445 // Prints the node tagName, such as <A>, <IMG>, etc
19448 for(i = 0; i < currentElement.attributes.length;i++) {
19450 var aname = currentElement.attributes.item(i).name;
19451 if (!currentElement.attributes.item(i).value.length) {
19454 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19457 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19466 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19469 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19474 // Traverse the tree
19476 var currentElementChild = currentElement.childNodes.item(i);
19477 var allText = true;
19478 var innerHTML = '';
19480 while (currentElementChild) {
19481 // Formatting code (indent the tree so it looks nice on the screen)
19482 var nopad = nopadtext;
19483 if (lastnode == 'SPAN') {
19487 if (currentElementChild.nodeName == '#text') {
19488 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19489 toadd = nopadtext ? toadd : toadd.trim();
19490 if (!nopad && toadd.length > 80) {
19491 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19493 innerHTML += toadd;
19496 currentElementChild = currentElement.childNodes.item(i);
19502 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19504 // Recursively traverse the tree structure of the child node
19505 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19506 lastnode = currentElementChild.nodeName;
19508 currentElementChild=currentElement.childNodes.item(i);
19514 // The remaining code is mostly for formatting the tree
19515 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19520 ret+= "</"+tagName+">";
19526 applyBlacklists : function()
19528 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19529 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19533 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19534 if (b.indexOf(tag) > -1) {
19537 this.white.push(tag);
19541 Roo.each(w, function(tag) {
19542 if (b.indexOf(tag) > -1) {
19545 if (this.white.indexOf(tag) > -1) {
19548 this.white.push(tag);
19553 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19554 if (w.indexOf(tag) > -1) {
19557 this.black.push(tag);
19561 Roo.each(b, function(tag) {
19562 if (w.indexOf(tag) > -1) {
19565 if (this.black.indexOf(tag) > -1) {
19568 this.black.push(tag);
19573 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19574 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19578 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19579 if (b.indexOf(tag) > -1) {
19582 this.cwhite.push(tag);
19586 Roo.each(w, function(tag) {
19587 if (b.indexOf(tag) > -1) {
19590 if (this.cwhite.indexOf(tag) > -1) {
19593 this.cwhite.push(tag);
19598 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19599 if (w.indexOf(tag) > -1) {
19602 this.cblack.push(tag);
19606 Roo.each(b, function(tag) {
19607 if (w.indexOf(tag) > -1) {
19610 if (this.cblack.indexOf(tag) > -1) {
19613 this.cblack.push(tag);
19618 setStylesheets : function(stylesheets)
19620 if(typeof(stylesheets) == 'string'){
19621 Roo.get(this.iframe.contentDocument.head).createChild({
19623 rel : 'stylesheet',
19632 Roo.each(stylesheets, function(s) {
19637 Roo.get(_this.iframe.contentDocument.head).createChild({
19639 rel : 'stylesheet',
19648 removeStylesheets : function()
19652 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19657 // hide stuff that is not compatible
19671 * @event specialkey
19675 * @cfg {String} fieldClass @hide
19678 * @cfg {String} focusClass @hide
19681 * @cfg {String} autoCreate @hide
19684 * @cfg {String} inputType @hide
19687 * @cfg {String} invalidClass @hide
19690 * @cfg {String} invalidText @hide
19693 * @cfg {String} msgFx @hide
19696 * @cfg {String} validateOnBlur @hide
19700 Roo.HtmlEditorCore.white = [
19701 'area', 'br', 'img', 'input', 'hr', 'wbr',
19703 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19704 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19705 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19706 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19707 'table', 'ul', 'xmp',
19709 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19712 'dir', 'menu', 'ol', 'ul', 'dl',
19718 Roo.HtmlEditorCore.black = [
19719 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19721 'base', 'basefont', 'bgsound', 'blink', 'body',
19722 'frame', 'frameset', 'head', 'html', 'ilayer',
19723 'iframe', 'layer', 'link', 'meta', 'object',
19724 'script', 'style' ,'title', 'xml' // clean later..
19726 Roo.HtmlEditorCore.clean = [
19727 'script', 'style', 'title', 'xml'
19729 Roo.HtmlEditorCore.remove = [
19734 Roo.HtmlEditorCore.ablack = [
19738 Roo.HtmlEditorCore.aclean = [
19739 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19743 Roo.HtmlEditorCore.pwhite= [
19744 'http', 'https', 'mailto'
19747 // white listed style attributes.
19748 Roo.HtmlEditorCore.cwhite= [
19749 // 'text-align', /// default is to allow most things..
19755 // black listed style attributes.
19756 Roo.HtmlEditorCore.cblack= [
19757 // 'font-size' -- this can be set by the project
19761 Roo.HtmlEditorCore.swapCodes =[
19780 * @class Roo.bootstrap.HtmlEditor
19781 * @extends Roo.bootstrap.TextArea
19782 * Bootstrap HtmlEditor class
19785 * Create a new HtmlEditor
19786 * @param {Object} config The config object
19789 Roo.bootstrap.HtmlEditor = function(config){
19790 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19791 if (!this.toolbars) {
19792 this.toolbars = [];
19794 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19797 * @event initialize
19798 * Fires when the editor is fully initialized (including the iframe)
19799 * @param {HtmlEditor} this
19804 * Fires when the editor is first receives the focus. Any insertion must wait
19805 * until after this event.
19806 * @param {HtmlEditor} this
19810 * @event beforesync
19811 * Fires before the textarea is updated with content from the editor iframe. Return false
19812 * to cancel the sync.
19813 * @param {HtmlEditor} this
19814 * @param {String} html
19818 * @event beforepush
19819 * Fires before the iframe editor is updated with content from the textarea. Return false
19820 * to cancel the push.
19821 * @param {HtmlEditor} this
19822 * @param {String} html
19827 * Fires when the textarea is updated with content from the editor iframe.
19828 * @param {HtmlEditor} this
19829 * @param {String} html
19834 * Fires when the iframe editor is updated with content from the textarea.
19835 * @param {HtmlEditor} this
19836 * @param {String} html
19840 * @event editmodechange
19841 * Fires when the editor switches edit modes
19842 * @param {HtmlEditor} this
19843 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19845 editmodechange: true,
19847 * @event editorevent
19848 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19849 * @param {HtmlEditor} this
19853 * @event firstfocus
19854 * Fires when on first focus - needed by toolbars..
19855 * @param {HtmlEditor} this
19860 * Auto save the htmlEditor value as a file into Events
19861 * @param {HtmlEditor} this
19865 * @event savedpreview
19866 * preview the saved version of htmlEditor
19867 * @param {HtmlEditor} this
19874 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19878 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19883 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19888 * @cfg {Number} height (in pixels)
19892 * @cfg {Number} width (in pixels)
19897 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19900 stylesheets: false,
19905 // private properties
19906 validationEvent : false,
19908 initialized : false,
19911 onFocus : Roo.emptyFn,
19913 hideMode:'offsets',
19916 tbContainer : false,
19918 toolbarContainer :function() {
19919 return this.wrap.select('.x-html-editor-tb',true).first();
19923 * Protected method that will not generally be called directly. It
19924 * is called when the editor creates its toolbar. Override this method if you need to
19925 * add custom toolbar buttons.
19926 * @param {HtmlEditor} editor
19928 createToolbar : function(){
19930 Roo.log("create toolbars");
19932 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19933 this.toolbars[0].render(this.toolbarContainer());
19937 // if (!editor.toolbars || !editor.toolbars.length) {
19938 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19941 // for (var i =0 ; i < editor.toolbars.length;i++) {
19942 // editor.toolbars[i] = Roo.factory(
19943 // typeof(editor.toolbars[i]) == 'string' ?
19944 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19945 // Roo.bootstrap.HtmlEditor);
19946 // editor.toolbars[i].init(editor);
19952 onRender : function(ct, position)
19954 // Roo.log("Call onRender: " + this.xtype);
19956 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19958 this.wrap = this.inputEl().wrap({
19959 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19962 this.editorcore.onRender(ct, position);
19964 if (this.resizable) {
19965 this.resizeEl = new Roo.Resizable(this.wrap, {
19969 minHeight : this.height,
19970 height: this.height,
19971 handles : this.resizable,
19974 resize : function(r, w, h) {
19975 _t.onResize(w,h); // -something
19981 this.createToolbar(this);
19984 if(!this.width && this.resizable){
19985 this.setSize(this.wrap.getSize());
19987 if (this.resizeEl) {
19988 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19989 // should trigger onReize..
19995 onResize : function(w, h)
19997 Roo.log('resize: ' +w + ',' + h );
19998 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20002 if(this.inputEl() ){
20003 if(typeof w == 'number'){
20004 var aw = w - this.wrap.getFrameWidth('lr');
20005 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20008 if(typeof h == 'number'){
20009 var tbh = -11; // fixme it needs to tool bar size!
20010 for (var i =0; i < this.toolbars.length;i++) {
20011 // fixme - ask toolbars for heights?
20012 tbh += this.toolbars[i].el.getHeight();
20013 //if (this.toolbars[i].footer) {
20014 // tbh += this.toolbars[i].footer.el.getHeight();
20022 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20023 ah -= 5; // knock a few pixes off for look..
20024 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20028 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20029 this.editorcore.onResize(ew,eh);
20034 * Toggles the editor between standard and source edit mode.
20035 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20037 toggleSourceEdit : function(sourceEditMode)
20039 this.editorcore.toggleSourceEdit(sourceEditMode);
20041 if(this.editorcore.sourceEditMode){
20042 Roo.log('editor - showing textarea');
20045 // Roo.log(this.syncValue());
20047 this.inputEl().removeClass(['hide', 'x-hidden']);
20048 this.inputEl().dom.removeAttribute('tabIndex');
20049 this.inputEl().focus();
20051 Roo.log('editor - hiding textarea');
20053 // Roo.log(this.pushValue());
20056 this.inputEl().addClass(['hide', 'x-hidden']);
20057 this.inputEl().dom.setAttribute('tabIndex', -1);
20058 //this.deferFocus();
20061 if(this.resizable){
20062 this.setSize(this.wrap.getSize());
20065 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20068 // private (for BoxComponent)
20069 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20071 // private (for BoxComponent)
20072 getResizeEl : function(){
20076 // private (for BoxComponent)
20077 getPositionEl : function(){
20082 initEvents : function(){
20083 this.originalValue = this.getValue();
20087 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20090 // markInvalid : Roo.emptyFn,
20092 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20095 // clearInvalid : Roo.emptyFn,
20097 setValue : function(v){
20098 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20099 this.editorcore.pushValue();
20104 deferFocus : function(){
20105 this.focus.defer(10, this);
20109 focus : function(){
20110 this.editorcore.focus();
20116 onDestroy : function(){
20122 for (var i =0; i < this.toolbars.length;i++) {
20123 // fixme - ask toolbars for heights?
20124 this.toolbars[i].onDestroy();
20127 this.wrap.dom.innerHTML = '';
20128 this.wrap.remove();
20133 onFirstFocus : function(){
20134 //Roo.log("onFirstFocus");
20135 this.editorcore.onFirstFocus();
20136 for (var i =0; i < this.toolbars.length;i++) {
20137 this.toolbars[i].onFirstFocus();
20143 syncValue : function()
20145 this.editorcore.syncValue();
20148 pushValue : function()
20150 this.editorcore.pushValue();
20154 // hide stuff that is not compatible
20168 * @event specialkey
20172 * @cfg {String} fieldClass @hide
20175 * @cfg {String} focusClass @hide
20178 * @cfg {String} autoCreate @hide
20181 * @cfg {String} inputType @hide
20184 * @cfg {String} invalidClass @hide
20187 * @cfg {String} invalidText @hide
20190 * @cfg {String} msgFx @hide
20193 * @cfg {String} validateOnBlur @hide
20202 Roo.namespace('Roo.bootstrap.htmleditor');
20204 * @class Roo.bootstrap.HtmlEditorToolbar1
20209 new Roo.bootstrap.HtmlEditor({
20212 new Roo.bootstrap.HtmlEditorToolbar1({
20213 disable : { fonts: 1 , format: 1, ..., ... , ...],
20219 * @cfg {Object} disable List of elements to disable..
20220 * @cfg {Array} btns List of additional buttons.
20224 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20227 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20230 Roo.apply(this, config);
20232 // default disabled, based on 'good practice'..
20233 this.disable = this.disable || {};
20234 Roo.applyIf(this.disable, {
20237 specialElements : true
20239 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20241 this.editor = config.editor;
20242 this.editorcore = config.editor.editorcore;
20244 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20246 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20247 // dont call parent... till later.
20249 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20254 editorcore : false,
20259 "h1","h2","h3","h4","h5","h6",
20261 "abbr", "acronym", "address", "cite", "samp", "var",
20265 onRender : function(ct, position)
20267 // Roo.log("Call onRender: " + this.xtype);
20269 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20271 this.el.dom.style.marginBottom = '0';
20273 var editorcore = this.editorcore;
20274 var editor= this.editor;
20277 var btn = function(id,cmd , toggle, handler){
20279 var event = toggle ? 'toggle' : 'click';
20284 xns: Roo.bootstrap,
20287 enableToggle:toggle !== false,
20289 pressed : toggle ? false : null,
20292 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20293 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20302 xns: Roo.bootstrap,
20303 glyphicon : 'font',
20307 xns: Roo.bootstrap,
20311 Roo.each(this.formats, function(f) {
20312 style.menu.items.push({
20314 xns: Roo.bootstrap,
20315 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20320 editorcore.insertTag(this.tagname);
20327 children.push(style);
20330 btn('bold',false,true);
20331 btn('italic',false,true);
20332 btn('align-left', 'justifyleft',true);
20333 btn('align-center', 'justifycenter',true);
20334 btn('align-right' , 'justifyright',true);
20335 btn('link', false, false, function(btn) {
20336 //Roo.log("create link?");
20337 var url = prompt(this.createLinkText, this.defaultLinkValue);
20338 if(url && url != 'http:/'+'/'){
20339 this.editorcore.relayCmd('createlink', url);
20342 btn('list','insertunorderedlist',true);
20343 btn('pencil', false,true, function(btn){
20346 this.toggleSourceEdit(btn.pressed);
20352 xns: Roo.bootstrap,
20357 xns: Roo.bootstrap,
20362 cog.menu.items.push({
20364 xns: Roo.bootstrap,
20365 html : Clean styles,
20370 editorcore.insertTag(this.tagname);
20379 this.xtype = 'NavSimplebar';
20381 for(var i=0;i< children.length;i++) {
20383 this.buttons.add(this.addxtypeChild(children[i]));
20387 editor.on('editorevent', this.updateToolbar, this);
20389 onBtnClick : function(id)
20391 this.editorcore.relayCmd(id);
20392 this.editorcore.focus();
20396 * Protected method that will not generally be called directly. It triggers
20397 * a toolbar update by reading the markup state of the current selection in the editor.
20399 updateToolbar: function(){
20401 if(!this.editorcore.activated){
20402 this.editor.onFirstFocus(); // is this neeed?
20406 var btns = this.buttons;
20407 var doc = this.editorcore.doc;
20408 btns.get('bold').setActive(doc.queryCommandState('bold'));
20409 btns.get('italic').setActive(doc.queryCommandState('italic'));
20410 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20412 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20413 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20414 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20416 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20417 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20420 var ans = this.editorcore.getAllAncestors();
20421 if (this.formatCombo) {
20424 var store = this.formatCombo.store;
20425 this.formatCombo.setValue("");
20426 for (var i =0; i < ans.length;i++) {
20427 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20429 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20437 // hides menus... - so this cant be on a menu...
20438 Roo.bootstrap.MenuMgr.hideAll();
20440 Roo.bootstrap.MenuMgr.hideAll();
20441 //this.editorsyncValue();
20443 onFirstFocus: function() {
20444 this.buttons.each(function(item){
20448 toggleSourceEdit : function(sourceEditMode){
20451 if(sourceEditMode){
20452 Roo.log("disabling buttons");
20453 this.buttons.each( function(item){
20454 if(item.cmd != 'pencil'){
20460 Roo.log("enabling buttons");
20461 if(this.editorcore.initialized){
20462 this.buttons.each( function(item){
20468 Roo.log("calling toggole on editor");
20469 // tell the editor that it's been pressed..
20470 this.editor.toggleSourceEdit(sourceEditMode);
20480 * @class Roo.bootstrap.Table.AbstractSelectionModel
20481 * @extends Roo.util.Observable
20482 * Abstract base class for grid SelectionModels. It provides the interface that should be
20483 * implemented by descendant classes. This class should not be directly instantiated.
20486 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20487 this.locked = false;
20488 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20492 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20493 /** @ignore Called by the grid automatically. Do not call directly. */
20494 init : function(grid){
20500 * Locks the selections.
20503 this.locked = true;
20507 * Unlocks the selections.
20509 unlock : function(){
20510 this.locked = false;
20514 * Returns true if the selections are locked.
20515 * @return {Boolean}
20517 isLocked : function(){
20518 return this.locked;
20522 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20523 * @class Roo.bootstrap.Table.RowSelectionModel
20524 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20525 * It supports multiple selections and keyboard selection/navigation.
20527 * @param {Object} config
20530 Roo.bootstrap.Table.RowSelectionModel = function(config){
20531 Roo.apply(this, config);
20532 this.selections = new Roo.util.MixedCollection(false, function(o){
20537 this.lastActive = false;
20541 * @event selectionchange
20542 * Fires when the selection changes
20543 * @param {SelectionModel} this
20545 "selectionchange" : true,
20547 * @event afterselectionchange
20548 * Fires after the selection changes (eg. by key press or clicking)
20549 * @param {SelectionModel} this
20551 "afterselectionchange" : true,
20553 * @event beforerowselect
20554 * Fires when a row is selected being selected, return false to cancel.
20555 * @param {SelectionModel} this
20556 * @param {Number} rowIndex The selected index
20557 * @param {Boolean} keepExisting False if other selections will be cleared
20559 "beforerowselect" : true,
20562 * Fires when a row is selected.
20563 * @param {SelectionModel} this
20564 * @param {Number} rowIndex The selected index
20565 * @param {Roo.data.Record} r The record
20567 "rowselect" : true,
20569 * @event rowdeselect
20570 * Fires when a row is deselected.
20571 * @param {SelectionModel} this
20572 * @param {Number} rowIndex The selected index
20574 "rowdeselect" : true
20576 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20577 this.locked = false;
20580 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20582 * @cfg {Boolean} singleSelect
20583 * True to allow selection of only one row at a time (defaults to false)
20585 singleSelect : false,
20588 initEvents : function(){
20590 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20591 this.grid.on("mousedown", this.handleMouseDown, this);
20592 }else{ // allow click to work like normal
20593 this.grid.on("rowclick", this.handleDragableRowClick, this);
20596 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20597 "up" : function(e){
20599 this.selectPrevious(e.shiftKey);
20600 }else if(this.last !== false && this.lastActive !== false){
20601 var last = this.last;
20602 this.selectRange(this.last, this.lastActive-1);
20603 this.grid.getView().focusRow(this.lastActive);
20604 if(last !== false){
20608 this.selectFirstRow();
20610 this.fireEvent("afterselectionchange", this);
20612 "down" : function(e){
20614 this.selectNext(e.shiftKey);
20615 }else if(this.last !== false && this.lastActive !== false){
20616 var last = this.last;
20617 this.selectRange(this.last, this.lastActive+1);
20618 this.grid.getView().focusRow(this.lastActive);
20619 if(last !== false){
20623 this.selectFirstRow();
20625 this.fireEvent("afterselectionchange", this);
20630 var view = this.grid.view;
20631 view.on("refresh", this.onRefresh, this);
20632 view.on("rowupdated", this.onRowUpdated, this);
20633 view.on("rowremoved", this.onRemove, this);
20637 onRefresh : function(){
20638 var ds = this.grid.dataSource, i, v = this.grid.view;
20639 var s = this.selections;
20640 s.each(function(r){
20641 if((i = ds.indexOfId(r.id)) != -1){
20650 onRemove : function(v, index, r){
20651 this.selections.remove(r);
20655 onRowUpdated : function(v, index, r){
20656 if(this.isSelected(r)){
20657 v.onRowSelect(index);
20663 * @param {Array} records The records to select
20664 * @param {Boolean} keepExisting (optional) True to keep existing selections
20666 selectRecords : function(records, keepExisting){
20668 this.clearSelections();
20670 var ds = this.grid.dataSource;
20671 for(var i = 0, len = records.length; i < len; i++){
20672 this.selectRow(ds.indexOf(records[i]), true);
20677 * Gets the number of selected rows.
20680 getCount : function(){
20681 return this.selections.length;
20685 * Selects the first row in the grid.
20687 selectFirstRow : function(){
20692 * Select the last row.
20693 * @param {Boolean} keepExisting (optional) True to keep existing selections
20695 selectLastRow : function(keepExisting){
20696 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20700 * Selects the row immediately following the last selected row.
20701 * @param {Boolean} keepExisting (optional) True to keep existing selections
20703 selectNext : function(keepExisting){
20704 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20705 this.selectRow(this.last+1, keepExisting);
20706 this.grid.getView().focusRow(this.last);
20711 * Selects the row that precedes the last selected row.
20712 * @param {Boolean} keepExisting (optional) True to keep existing selections
20714 selectPrevious : function(keepExisting){
20716 this.selectRow(this.last-1, keepExisting);
20717 this.grid.getView().focusRow(this.last);
20722 * Returns the selected records
20723 * @return {Array} Array of selected records
20725 getSelections : function(){
20726 return [].concat(this.selections.items);
20730 * Returns the first selected record.
20733 getSelected : function(){
20734 return this.selections.itemAt(0);
20739 * Clears all selections.
20741 clearSelections : function(fast){
20742 if(this.locked) return;
20744 var ds = this.grid.dataSource;
20745 var s = this.selections;
20746 s.each(function(r){
20747 this.deselectRow(ds.indexOfId(r.id));
20751 this.selections.clear();
20758 * Selects all rows.
20760 selectAll : function(){
20761 if(this.locked) return;
20762 this.selections.clear();
20763 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20764 this.selectRow(i, true);
20769 * Returns True if there is a selection.
20770 * @return {Boolean}
20772 hasSelection : function(){
20773 return this.selections.length > 0;
20777 * Returns True if the specified row is selected.
20778 * @param {Number/Record} record The record or index of the record to check
20779 * @return {Boolean}
20781 isSelected : function(index){
20782 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20783 return (r && this.selections.key(r.id) ? true : false);
20787 * Returns True if the specified record id is selected.
20788 * @param {String} id The id of record to check
20789 * @return {Boolean}
20791 isIdSelected : function(id){
20792 return (this.selections.key(id) ? true : false);
20796 handleMouseDown : function(e, t){
20797 var view = this.grid.getView(), rowIndex;
20798 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20801 if(e.shiftKey && this.last !== false){
20802 var last = this.last;
20803 this.selectRange(last, rowIndex, e.ctrlKey);
20804 this.last = last; // reset the last
20805 view.focusRow(rowIndex);
20807 var isSelected = this.isSelected(rowIndex);
20808 if(e.button !== 0 && isSelected){
20809 view.focusRow(rowIndex);
20810 }else if(e.ctrlKey && isSelected){
20811 this.deselectRow(rowIndex);
20812 }else if(!isSelected){
20813 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20814 view.focusRow(rowIndex);
20817 this.fireEvent("afterselectionchange", this);
20820 handleDragableRowClick : function(grid, rowIndex, e)
20822 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20823 this.selectRow(rowIndex, false);
20824 grid.view.focusRow(rowIndex);
20825 this.fireEvent("afterselectionchange", this);
20830 * Selects multiple rows.
20831 * @param {Array} rows Array of the indexes of the row to select
20832 * @param {Boolean} keepExisting (optional) True to keep existing selections
20834 selectRows : function(rows, keepExisting){
20836 this.clearSelections();
20838 for(var i = 0, len = rows.length; i < len; i++){
20839 this.selectRow(rows[i], true);
20844 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20845 * @param {Number} startRow The index of the first row in the range
20846 * @param {Number} endRow The index of the last row in the range
20847 * @param {Boolean} keepExisting (optional) True to retain existing selections
20849 selectRange : function(startRow, endRow, keepExisting){
20850 if(this.locked) return;
20852 this.clearSelections();
20854 if(startRow <= endRow){
20855 for(var i = startRow; i <= endRow; i++){
20856 this.selectRow(i, true);
20859 for(var i = startRow; i >= endRow; i--){
20860 this.selectRow(i, true);
20866 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20867 * @param {Number} startRow The index of the first row in the range
20868 * @param {Number} endRow The index of the last row in the range
20870 deselectRange : function(startRow, endRow, preventViewNotify){
20871 if(this.locked) return;
20872 for(var i = startRow; i <= endRow; i++){
20873 this.deselectRow(i, preventViewNotify);
20879 * @param {Number} row The index of the row to select
20880 * @param {Boolean} keepExisting (optional) True to keep existing selections
20882 selectRow : function(index, keepExisting, preventViewNotify){
20883 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20884 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20885 if(!keepExisting || this.singleSelect){
20886 this.clearSelections();
20888 var r = this.grid.dataSource.getAt(index);
20889 this.selections.add(r);
20890 this.last = this.lastActive = index;
20891 if(!preventViewNotify){
20892 this.grid.getView().onRowSelect(index);
20894 this.fireEvent("rowselect", this, index, r);
20895 this.fireEvent("selectionchange", this);
20901 * @param {Number} row The index of the row to deselect
20903 deselectRow : function(index, preventViewNotify){
20904 if(this.locked) return;
20905 if(this.last == index){
20908 if(this.lastActive == index){
20909 this.lastActive = false;
20911 var r = this.grid.dataSource.getAt(index);
20912 this.selections.remove(r);
20913 if(!preventViewNotify){
20914 this.grid.getView().onRowDeselect(index);
20916 this.fireEvent("rowdeselect", this, index);
20917 this.fireEvent("selectionchange", this);
20921 restoreLast : function(){
20923 this.last = this._last;
20928 acceptsNav : function(row, col, cm){
20929 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20933 onEditorKey : function(field, e){
20934 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20939 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20941 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20943 }else if(k == e.ENTER && !e.ctrlKey){
20947 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20949 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20951 }else if(k == e.ESC){
20955 g.startEditing(newCell[0], newCell[1]);
20960 * Ext JS Library 1.1.1
20961 * Copyright(c) 2006-2007, Ext JS, LLC.
20963 * Originally Released Under LGPL - original licence link has changed is not relivant.
20966 * <script type="text/javascript">
20970 * @class Roo.bootstrap.PagingToolbar
20972 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20974 * Create a new PagingToolbar
20975 * @param {Object} config The config object
20977 Roo.bootstrap.PagingToolbar = function(config)
20979 // old args format still supported... - xtype is prefered..
20980 // created from xtype...
20981 var ds = config.dataSource;
20982 this.toolbarItems = [];
20983 if (config.items) {
20984 this.toolbarItems = config.items;
20985 // config.items = [];
20988 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20995 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20999 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21001 * @cfg {Roo.data.Store} dataSource
21002 * The underlying data store providing the paged data
21005 * @cfg {String/HTMLElement/Element} container
21006 * container The id or element that will contain the toolbar
21009 * @cfg {Boolean} displayInfo
21010 * True to display the displayMsg (defaults to false)
21013 * @cfg {Number} pageSize
21014 * The number of records to display per page (defaults to 20)
21018 * @cfg {String} displayMsg
21019 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21021 displayMsg : 'Displaying {0} - {1} of {2}',
21023 * @cfg {String} emptyMsg
21024 * The message to display when no records are found (defaults to "No data to display")
21026 emptyMsg : 'No data to display',
21028 * Customizable piece of the default paging text (defaults to "Page")
21031 beforePageText : "Page",
21033 * Customizable piece of the default paging text (defaults to "of %0")
21036 afterPageText : "of {0}",
21038 * Customizable piece of the default paging text (defaults to "First Page")
21041 firstText : "First Page",
21043 * Customizable piece of the default paging text (defaults to "Previous Page")
21046 prevText : "Previous Page",
21048 * Customizable piece of the default paging text (defaults to "Next Page")
21051 nextText : "Next Page",
21053 * Customizable piece of the default paging text (defaults to "Last Page")
21056 lastText : "Last Page",
21058 * Customizable piece of the default paging text (defaults to "Refresh")
21061 refreshText : "Refresh",
21065 onRender : function(ct, position)
21067 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21068 this.navgroup.parentId = this.id;
21069 this.navgroup.onRender(this.el, null);
21070 // add the buttons to the navgroup
21072 if(this.displayInfo){
21073 Roo.log(this.el.select('ul.navbar-nav',true).first());
21074 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21075 this.displayEl = this.el.select('.x-paging-info', true).first();
21076 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21077 // this.displayEl = navel.el.select('span',true).first();
21083 Roo.each(_this.buttons, function(e){
21084 Roo.factory(e).onRender(_this.el, null);
21088 Roo.each(_this.toolbarItems, function(e) {
21089 _this.navgroup.addItem(e);
21093 this.first = this.navgroup.addItem({
21094 tooltip: this.firstText,
21096 icon : 'fa fa-backward',
21098 preventDefault: true,
21099 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21102 this.prev = this.navgroup.addItem({
21103 tooltip: this.prevText,
21105 icon : 'fa fa-step-backward',
21107 preventDefault: true,
21108 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21110 //this.addSeparator();
21113 var field = this.navgroup.addItem( {
21115 cls : 'x-paging-position',
21117 html : this.beforePageText +
21118 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21119 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21122 this.field = field.el.select('input', true).first();
21123 this.field.on("keydown", this.onPagingKeydown, this);
21124 this.field.on("focus", function(){this.dom.select();});
21127 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21128 //this.field.setHeight(18);
21129 //this.addSeparator();
21130 this.next = this.navgroup.addItem({
21131 tooltip: this.nextText,
21133 html : ' <i class="fa fa-step-forward">',
21135 preventDefault: true,
21136 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21138 this.last = this.navgroup.addItem({
21139 tooltip: this.lastText,
21140 icon : 'fa fa-forward',
21143 preventDefault: true,
21144 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21146 //this.addSeparator();
21147 this.loading = this.navgroup.addItem({
21148 tooltip: this.refreshText,
21149 icon: 'fa fa-refresh',
21150 preventDefault: true,
21151 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21157 updateInfo : function(){
21158 if(this.displayEl){
21159 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21160 var msg = count == 0 ?
21164 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21166 this.displayEl.update(msg);
21171 onLoad : function(ds, r, o){
21172 this.cursor = o.params ? o.params.start : 0;
21173 var d = this.getPageData(),
21177 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21178 this.field.dom.value = ap;
21179 this.first.setDisabled(ap == 1);
21180 this.prev.setDisabled(ap == 1);
21181 this.next.setDisabled(ap == ps);
21182 this.last.setDisabled(ap == ps);
21183 this.loading.enable();
21188 getPageData : function(){
21189 var total = this.ds.getTotalCount();
21192 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21193 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21198 onLoadError : function(){
21199 this.loading.enable();
21203 onPagingKeydown : function(e){
21204 var k = e.getKey();
21205 var d = this.getPageData();
21207 var v = this.field.dom.value, pageNum;
21208 if(!v || isNaN(pageNum = parseInt(v, 10))){
21209 this.field.dom.value = d.activePage;
21212 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21213 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21216 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))
21218 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21219 this.field.dom.value = pageNum;
21220 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21223 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21225 var v = this.field.dom.value, pageNum;
21226 var increment = (e.shiftKey) ? 10 : 1;
21227 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21229 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21230 this.field.dom.value = d.activePage;
21233 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21235 this.field.dom.value = parseInt(v, 10) + increment;
21236 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21237 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21244 beforeLoad : function(){
21246 this.loading.disable();
21251 onClick : function(which){
21260 ds.load({params:{start: 0, limit: this.pageSize}});
21263 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21266 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21269 var total = ds.getTotalCount();
21270 var extra = total % this.pageSize;
21271 var lastStart = extra ? (total - extra) : total-this.pageSize;
21272 ds.load({params:{start: lastStart, limit: this.pageSize}});
21275 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21281 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21282 * @param {Roo.data.Store} store The data store to unbind
21284 unbind : function(ds){
21285 ds.un("beforeload", this.beforeLoad, this);
21286 ds.un("load", this.onLoad, this);
21287 ds.un("loadexception", this.onLoadError, this);
21288 ds.un("remove", this.updateInfo, this);
21289 ds.un("add", this.updateInfo, this);
21290 this.ds = undefined;
21294 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21295 * @param {Roo.data.Store} store The data store to bind
21297 bind : function(ds){
21298 ds.on("beforeload", this.beforeLoad, this);
21299 ds.on("load", this.onLoad, this);
21300 ds.on("loadexception", this.onLoadError, this);
21301 ds.on("remove", this.updateInfo, this);
21302 ds.on("add", this.updateInfo, this);
21313 * @class Roo.bootstrap.MessageBar
21314 * @extends Roo.bootstrap.Component
21315 * Bootstrap MessageBar class
21316 * @cfg {String} html contents of the MessageBar
21317 * @cfg {String} weight (info | success | warning | danger) default info
21318 * @cfg {String} beforeClass insert the bar before the given class
21319 * @cfg {Boolean} closable (true | false) default false
21320 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21323 * Create a new Element
21324 * @param {Object} config The config object
21327 Roo.bootstrap.MessageBar = function(config){
21328 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21331 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21337 beforeClass: 'bootstrap-sticky-wrap',
21339 getAutoCreate : function(){
21343 cls: 'alert alert-dismissable alert-' + this.weight,
21348 html: this.html || ''
21354 cfg.cls += ' alert-messages-fixed';
21368 onRender : function(ct, position)
21370 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21373 var cfg = Roo.apply({}, this.getAutoCreate());
21377 cfg.cls += ' ' + this.cls;
21380 cfg.style = this.style;
21382 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21384 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21387 this.el.select('>button.close').on('click', this.hide, this);
21393 if (!this.rendered) {
21399 this.fireEvent('show', this);
21405 if (!this.rendered) {
21411 this.fireEvent('hide', this);
21414 update : function()
21416 // var e = this.el.dom.firstChild;
21418 // if(this.closable){
21419 // e = e.nextSibling;
21422 // e.data = this.html || '';
21424 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21440 * @class Roo.bootstrap.Graph
21441 * @extends Roo.bootstrap.Component
21442 * Bootstrap Graph class
21446 @cfg {String} graphtype bar | vbar | pie
21447 @cfg {number} g_x coodinator | centre x (pie)
21448 @cfg {number} g_y coodinator | centre y (pie)
21449 @cfg {number} g_r radius (pie)
21450 @cfg {number} g_height height of the chart (respected by all elements in the set)
21451 @cfg {number} g_width width of the chart (respected by all elements in the set)
21452 @cfg {Object} title The title of the chart
21455 -opts (object) options for the chart
21457 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21458 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21460 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.
21461 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21463 o stretch (boolean)
21465 -opts (object) options for the pie
21468 o startAngle (number)
21469 o endAngle (number)
21473 * Create a new Input
21474 * @param {Object} config The config object
21477 Roo.bootstrap.Graph = function(config){
21478 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21484 * The img click event for the img.
21485 * @param {Roo.EventObject} e
21491 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21502 //g_colors: this.colors,
21509 getAutoCreate : function(){
21520 onRender : function(ct,position){
21521 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21522 this.raphael = Raphael(this.el.dom);
21524 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21525 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21526 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21527 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21529 r.text(160, 10, "Single Series Chart").attr(txtattr);
21530 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21531 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21532 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21534 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21535 r.barchart(330, 10, 300, 220, data1);
21536 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21537 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21540 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21541 // r.barchart(30, 30, 560, 250, xdata, {
21542 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21543 // axis : "0 0 1 1",
21544 // axisxlabels : xdata
21545 // //yvalues : cols,
21548 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21550 // this.load(null,xdata,{
21551 // axis : "0 0 1 1",
21552 // axisxlabels : xdata
21557 load : function(graphtype,xdata,opts){
21558 this.raphael.clear();
21560 graphtype = this.graphtype;
21565 var r = this.raphael,
21566 fin = function () {
21567 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21569 fout = function () {
21570 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21572 pfin = function() {
21573 this.sector.stop();
21574 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21577 this.label[0].stop();
21578 this.label[0].attr({ r: 7.5 });
21579 this.label[1].attr({ "font-weight": 800 });
21582 pfout = function() {
21583 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21586 this.label[0].animate({ r: 5 }, 500, "bounce");
21587 this.label[1].attr({ "font-weight": 400 });
21593 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21596 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21599 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21600 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21602 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21609 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21614 setTitle: function(o)
21619 initEvents: function() {
21622 this.el.on('click', this.onClick, this);
21626 onClick : function(e)
21628 Roo.log('img onclick');
21629 this.fireEvent('click', this, e);
21641 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21644 * @class Roo.bootstrap.dash.NumberBox
21645 * @extends Roo.bootstrap.Component
21646 * Bootstrap NumberBox class
21647 * @cfg {String} headline Box headline
21648 * @cfg {String} content Box content
21649 * @cfg {String} icon Box icon
21650 * @cfg {String} footer Footer text
21651 * @cfg {String} fhref Footer href
21654 * Create a new NumberBox
21655 * @param {Object} config The config object
21659 Roo.bootstrap.dash.NumberBox = function(config){
21660 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21664 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21673 getAutoCreate : function(){
21677 cls : 'small-box ',
21685 cls : 'roo-headline',
21686 html : this.headline
21690 cls : 'roo-content',
21691 html : this.content
21705 cls : 'ion ' + this.icon
21714 cls : 'small-box-footer',
21715 href : this.fhref || '#',
21719 cfg.cn.push(footer);
21726 onRender : function(ct,position){
21727 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21734 setHeadline: function (value)
21736 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21739 setFooter: function (value, href)
21741 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21744 this.el.select('a.small-box-footer',true).first().attr('href', href);
21749 setContent: function (value)
21751 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21754 initEvents: function()
21768 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21771 * @class Roo.bootstrap.dash.TabBox
21772 * @extends Roo.bootstrap.Component
21773 * Bootstrap TabBox class
21774 * @cfg {String} title Title of the TabBox
21775 * @cfg {String} icon Icon of the TabBox
21776 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21777 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21780 * Create a new TabBox
21781 * @param {Object} config The config object
21785 Roo.bootstrap.dash.TabBox = function(config){
21786 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21791 * When a pane is added
21792 * @param {Roo.bootstrap.dash.TabPane} pane
21796 * @event activatepane
21797 * When a pane is activated
21798 * @param {Roo.bootstrap.dash.TabPane} pane
21800 "activatepane" : true
21808 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21813 tabScrollable : false,
21815 getChildContainer : function()
21817 return this.el.select('.tab-content', true).first();
21820 getAutoCreate : function(){
21824 cls: 'pull-left header',
21832 cls: 'fa ' + this.icon
21838 cls: 'nav nav-tabs pull-right',
21844 if(this.tabScrollable){
21851 cls: 'nav nav-tabs pull-right',
21862 cls: 'nav-tabs-custom',
21867 cls: 'tab-content no-padding',
21875 initEvents : function()
21877 //Roo.log('add add pane handler');
21878 this.on('addpane', this.onAddPane, this);
21881 * Updates the box title
21882 * @param {String} html to set the title to.
21884 setTitle : function(value)
21886 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21888 onAddPane : function(pane)
21890 this.panes.push(pane);
21891 //Roo.log('addpane');
21893 // tabs are rendere left to right..
21894 if(!this.showtabs){
21898 var ctr = this.el.select('.nav-tabs', true).first();
21901 var existing = ctr.select('.nav-tab',true);
21902 var qty = existing.getCount();;
21905 var tab = ctr.createChild({
21907 cls : 'nav-tab' + (qty ? '' : ' active'),
21915 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21918 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21920 pane.el.addClass('active');
21925 onTabClick : function(ev,un,ob,pane)
21927 //Roo.log('tab - prev default');
21928 ev.preventDefault();
21931 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21932 pane.tab.addClass('active');
21933 //Roo.log(pane.title);
21934 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21935 // technically we should have a deactivate event.. but maybe add later.
21936 // and it should not de-activate the selected tab...
21937 this.fireEvent('activatepane', pane);
21938 pane.el.addClass('active');
21939 pane.fireEvent('activate');
21944 getActivePane : function()
21947 Roo.each(this.panes, function(p) {
21948 if(p.el.hasClass('active')){
21969 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21971 * @class Roo.bootstrap.TabPane
21972 * @extends Roo.bootstrap.Component
21973 * Bootstrap TabPane class
21974 * @cfg {Boolean} active (false | true) Default false
21975 * @cfg {String} title title of panel
21979 * Create a new TabPane
21980 * @param {Object} config The config object
21983 Roo.bootstrap.dash.TabPane = function(config){
21984 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21990 * When a pane is activated
21991 * @param {Roo.bootstrap.dash.TabPane} pane
21998 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22003 // the tabBox that this is attached to.
22006 getAutoCreate : function()
22014 cfg.cls += ' active';
22019 initEvents : function()
22021 //Roo.log('trigger add pane handler');
22022 this.parent().fireEvent('addpane', this)
22026 * Updates the tab title
22027 * @param {String} html to set the title to.
22029 setTitle: function(str)
22035 this.tab.select('a', true).first().dom.innerHTML = str;
22052 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22055 * @class Roo.bootstrap.menu.Menu
22056 * @extends Roo.bootstrap.Component
22057 * Bootstrap Menu class - container for Menu
22058 * @cfg {String} html Text of the menu
22059 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22060 * @cfg {String} icon Font awesome icon
22061 * @cfg {String} pos Menu align to (top | bottom) default bottom
22065 * Create a new Menu
22066 * @param {Object} config The config object
22070 Roo.bootstrap.menu.Menu = function(config){
22071 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22075 * @event beforeshow
22076 * Fires before this menu is displayed
22077 * @param {Roo.bootstrap.menu.Menu} this
22081 * @event beforehide
22082 * Fires before this menu is hidden
22083 * @param {Roo.bootstrap.menu.Menu} this
22088 * Fires after this menu is displayed
22089 * @param {Roo.bootstrap.menu.Menu} this
22094 * Fires after this menu is hidden
22095 * @param {Roo.bootstrap.menu.Menu} this
22100 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22101 * @param {Roo.bootstrap.menu.Menu} this
22102 * @param {Roo.EventObject} e
22109 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22113 weight : 'default',
22118 getChildContainer : function() {
22119 if(this.isSubMenu){
22123 return this.el.select('ul.dropdown-menu', true).first();
22126 getAutoCreate : function()
22131 cls : 'roo-menu-text',
22139 cls : 'fa ' + this.icon
22150 cls : 'dropdown-button btn btn-' + this.weight,
22155 cls : 'dropdown-toggle btn btn-' + this.weight,
22165 cls : 'dropdown-menu'
22171 if(this.pos == 'top'){
22172 cfg.cls += ' dropup';
22175 if(this.isSubMenu){
22178 cls : 'dropdown-menu'
22185 onRender : function(ct, position)
22187 this.isSubMenu = ct.hasClass('dropdown-submenu');
22189 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22192 initEvents : function()
22194 if(this.isSubMenu){
22198 this.hidden = true;
22200 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22201 this.triggerEl.on('click', this.onTriggerPress, this);
22203 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22204 this.buttonEl.on('click', this.onClick, this);
22210 if(this.isSubMenu){
22214 return this.el.select('ul.dropdown-menu', true).first();
22217 onClick : function(e)
22219 this.fireEvent("click", this, e);
22222 onTriggerPress : function(e)
22224 if (this.isVisible()) {
22231 isVisible : function(){
22232 return !this.hidden;
22237 this.fireEvent("beforeshow", this);
22239 this.hidden = false;
22240 this.el.addClass('open');
22242 Roo.get(document).on("mouseup", this.onMouseUp, this);
22244 this.fireEvent("show", this);
22251 this.fireEvent("beforehide", this);
22253 this.hidden = true;
22254 this.el.removeClass('open');
22256 Roo.get(document).un("mouseup", this.onMouseUp);
22258 this.fireEvent("hide", this);
22261 onMouseUp : function()
22275 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22278 * @class Roo.bootstrap.menu.Item
22279 * @extends Roo.bootstrap.Component
22280 * Bootstrap MenuItem class
22281 * @cfg {Boolean} submenu (true | false) default false
22282 * @cfg {String} html text of the item
22283 * @cfg {String} href the link
22284 * @cfg {Boolean} disable (true | false) default false
22285 * @cfg {Boolean} preventDefault (true | false) default true
22286 * @cfg {String} icon Font awesome icon
22287 * @cfg {String} pos Submenu align to (left | right) default right
22291 * Create a new Item
22292 * @param {Object} config The config object
22296 Roo.bootstrap.menu.Item = function(config){
22297 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22301 * Fires when the mouse is hovering over this menu
22302 * @param {Roo.bootstrap.menu.Item} this
22303 * @param {Roo.EventObject} e
22308 * Fires when the mouse exits this menu
22309 * @param {Roo.bootstrap.menu.Item} this
22310 * @param {Roo.EventObject} e
22316 * The raw click event for the entire grid.
22317 * @param {Roo.EventObject} e
22323 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22328 preventDefault: true,
22333 getAutoCreate : function()
22338 cls : 'roo-menu-item-text',
22346 cls : 'fa ' + this.icon
22355 href : this.href || '#',
22362 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22366 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22368 if(this.pos == 'left'){
22369 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22376 initEvents : function()
22378 this.el.on('mouseover', this.onMouseOver, this);
22379 this.el.on('mouseout', this.onMouseOut, this);
22381 this.el.select('a', true).first().on('click', this.onClick, this);
22385 onClick : function(e)
22387 if(this.preventDefault){
22388 e.preventDefault();
22391 this.fireEvent("click", this, e);
22394 onMouseOver : function(e)
22396 if(this.submenu && this.pos == 'left'){
22397 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22400 this.fireEvent("mouseover", this, e);
22403 onMouseOut : function(e)
22405 this.fireEvent("mouseout", this, e);
22417 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22420 * @class Roo.bootstrap.menu.Separator
22421 * @extends Roo.bootstrap.Component
22422 * Bootstrap Separator class
22425 * Create a new Separator
22426 * @param {Object} config The config object
22430 Roo.bootstrap.menu.Separator = function(config){
22431 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22434 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22436 getAutoCreate : function(){
22457 * @class Roo.bootstrap.Tooltip
22458 * Bootstrap Tooltip class
22459 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22460 * to determine which dom element triggers the tooltip.
22462 * It needs to add support for additional attributes like tooltip-position
22465 * Create a new Toolti
22466 * @param {Object} config The config object
22469 Roo.bootstrap.Tooltip = function(config){
22470 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22473 Roo.apply(Roo.bootstrap.Tooltip, {
22475 * @function init initialize tooltip monitoring.
22479 currentTip : false,
22480 currentRegion : false,
22486 Roo.get(document).on('mouseover', this.enter ,this);
22487 Roo.get(document).on('mouseout', this.leave, this);
22490 this.currentTip = new Roo.bootstrap.Tooltip();
22493 enter : function(ev)
22495 var dom = ev.getTarget();
22497 //Roo.log(['enter',dom]);
22498 var el = Roo.fly(dom);
22499 if (this.currentEl) {
22501 //Roo.log(this.currentEl);
22502 //Roo.log(this.currentEl.contains(dom));
22503 if (this.currentEl == el) {
22506 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22514 if (this.currentTip.el) {
22515 this.currentTip.el.hide(); // force hiding...
22520 // you can not look for children, as if el is the body.. then everythign is the child..
22521 if (!el.attr('tooltip')) { //
22522 if (!el.select("[tooltip]").elements.length) {
22525 // is the mouse over this child...?
22526 bindEl = el.select("[tooltip]").first();
22527 var xy = ev.getXY();
22528 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22529 //Roo.log("not in region.");
22532 //Roo.log("child element over..");
22535 this.currentEl = bindEl;
22536 this.currentTip.bind(bindEl);
22537 this.currentRegion = Roo.lib.Region.getRegion(dom);
22538 this.currentTip.enter();
22541 leave : function(ev)
22543 var dom = ev.getTarget();
22544 //Roo.log(['leave',dom]);
22545 if (!this.currentEl) {
22550 if (dom != this.currentEl.dom) {
22553 var xy = ev.getXY();
22554 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22557 // only activate leave if mouse cursor is outside... bounding box..
22562 if (this.currentTip) {
22563 this.currentTip.leave();
22565 //Roo.log('clear currentEl');
22566 this.currentEl = false;
22571 'left' : ['r-l', [-2,0], 'right'],
22572 'right' : ['l-r', [2,0], 'left'],
22573 'bottom' : ['t-b', [0,2], 'top'],
22574 'top' : [ 'b-t', [0,-2], 'bottom']
22580 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22585 delay : null, // can be { show : 300 , hide: 500}
22589 hoverState : null, //???
22591 placement : 'bottom',
22593 getAutoCreate : function(){
22600 cls : 'tooltip-arrow'
22603 cls : 'tooltip-inner'
22610 bind : function(el)
22616 enter : function () {
22618 if (this.timeout != null) {
22619 clearTimeout(this.timeout);
22622 this.hoverState = 'in';
22623 //Roo.log("enter - show");
22624 if (!this.delay || !this.delay.show) {
22629 this.timeout = setTimeout(function () {
22630 if (_t.hoverState == 'in') {
22633 }, this.delay.show);
22637 clearTimeout(this.timeout);
22639 this.hoverState = 'out';
22640 if (!this.delay || !this.delay.hide) {
22646 this.timeout = setTimeout(function () {
22647 //Roo.log("leave - timeout");
22649 if (_t.hoverState == 'out') {
22651 Roo.bootstrap.Tooltip.currentEl = false;
22659 this.render(document.body);
22662 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22664 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22666 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22668 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22670 var placement = typeof this.placement == 'function' ?
22671 this.placement.call(this, this.el, on_el) :
22674 var autoToken = /\s?auto?\s?/i;
22675 var autoPlace = autoToken.test(placement);
22677 placement = placement.replace(autoToken, '') || 'top';
22681 //this.el.setXY([0,0]);
22683 //this.el.dom.style.display='block';
22684 this.el.addClass(placement);
22686 //this.el.appendTo(on_el);
22688 var p = this.getPosition();
22689 var box = this.el.getBox();
22694 var align = Roo.bootstrap.Tooltip.alignment[placement];
22695 this.el.alignTo(this.bindEl, align[0],align[1]);
22696 //var arrow = this.el.select('.arrow',true).first();
22697 //arrow.set(align[2],
22699 this.el.addClass('in fade');
22700 this.hoverState = null;
22702 if (this.el.hasClass('fade')) {
22713 //this.el.setXY([0,0]);
22714 this.el.removeClass('in');
22730 * @class Roo.bootstrap.LocationPicker
22731 * @extends Roo.bootstrap.Component
22732 * Bootstrap LocationPicker class
22733 * @cfg {Number} latitude Position when init default 0
22734 * @cfg {Number} longitude Position when init default 0
22735 * @cfg {Number} zoom default 15
22736 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22737 * @cfg {Boolean} mapTypeControl default false
22738 * @cfg {Boolean} disableDoubleClickZoom default false
22739 * @cfg {Boolean} scrollwheel default true
22740 * @cfg {Boolean} streetViewControl default false
22741 * @cfg {Number} radius default 0
22742 * @cfg {String} locationName
22743 * @cfg {Boolean} draggable default true
22744 * @cfg {Boolean} enableAutocomplete default false
22745 * @cfg {Boolean} enableReverseGeocode default true
22746 * @cfg {String} markerTitle
22749 * Create a new LocationPicker
22750 * @param {Object} config The config object
22754 Roo.bootstrap.LocationPicker = function(config){
22756 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22761 * Fires when the picker initialized.
22762 * @param {Roo.bootstrap.LocationPicker} this
22763 * @param {Google Location} location
22767 * @event positionchanged
22768 * Fires when the picker position changed.
22769 * @param {Roo.bootstrap.LocationPicker} this
22770 * @param {Google Location} location
22772 positionchanged : true,
22775 * Fires when the map resize.
22776 * @param {Roo.bootstrap.LocationPicker} this
22781 * Fires when the map show.
22782 * @param {Roo.bootstrap.LocationPicker} this
22787 * Fires when the map hide.
22788 * @param {Roo.bootstrap.LocationPicker} this
22793 * Fires when click the map.
22794 * @param {Roo.bootstrap.LocationPicker} this
22795 * @param {Map event} e
22799 * @event mapRightClick
22800 * Fires when right click the map.
22801 * @param {Roo.bootstrap.LocationPicker} this
22802 * @param {Map event} e
22804 mapRightClick : true,
22806 * @event markerClick
22807 * Fires when click the marker.
22808 * @param {Roo.bootstrap.LocationPicker} this
22809 * @param {Map event} e
22811 markerClick : true,
22813 * @event markerRightClick
22814 * Fires when right click the marker.
22815 * @param {Roo.bootstrap.LocationPicker} this
22816 * @param {Map event} e
22818 markerRightClick : true,
22820 * @event OverlayViewDraw
22821 * Fires when OverlayView Draw
22822 * @param {Roo.bootstrap.LocationPicker} this
22824 OverlayViewDraw : true,
22826 * @event OverlayViewOnAdd
22827 * Fires when OverlayView Draw
22828 * @param {Roo.bootstrap.LocationPicker} this
22830 OverlayViewOnAdd : true,
22832 * @event OverlayViewOnRemove
22833 * Fires when OverlayView Draw
22834 * @param {Roo.bootstrap.LocationPicker} this
22836 OverlayViewOnRemove : true,
22838 * @event OverlayViewShow
22839 * Fires when OverlayView Draw
22840 * @param {Roo.bootstrap.LocationPicker} this
22841 * @param {Pixel} cpx
22843 OverlayViewShow : true,
22845 * @event OverlayViewHide
22846 * Fires when OverlayView Draw
22847 * @param {Roo.bootstrap.LocationPicker} this
22849 OverlayViewHide : true
22854 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22856 gMapContext: false,
22862 mapTypeControl: false,
22863 disableDoubleClickZoom: false,
22865 streetViewControl: false,
22869 enableAutocomplete: false,
22870 enableReverseGeocode: true,
22873 getAutoCreate: function()
22878 cls: 'roo-location-picker'
22884 initEvents: function(ct, position)
22886 if(!this.el.getWidth() || this.isApplied()){
22890 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22895 initial: function()
22897 if(!this.mapTypeId){
22898 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22901 this.gMapContext = this.GMapContext();
22903 this.initOverlayView();
22905 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22909 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22910 _this.setPosition(_this.gMapContext.marker.position);
22913 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22914 _this.fireEvent('mapClick', this, event);
22918 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22919 _this.fireEvent('mapRightClick', this, event);
22923 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22924 _this.fireEvent('markerClick', this, event);
22928 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22929 _this.fireEvent('markerRightClick', this, event);
22933 this.setPosition(this.gMapContext.location);
22935 this.fireEvent('initial', this, this.gMapContext.location);
22938 initOverlayView: function()
22942 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22946 _this.fireEvent('OverlayViewDraw', _this);
22951 _this.fireEvent('OverlayViewOnAdd', _this);
22954 onRemove: function()
22956 _this.fireEvent('OverlayViewOnRemove', _this);
22959 show: function(cpx)
22961 _this.fireEvent('OverlayViewShow', _this, cpx);
22966 _this.fireEvent('OverlayViewHide', _this);
22972 fromLatLngToContainerPixel: function(event)
22974 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22977 isApplied: function()
22979 return this.getGmapContext() == false ? false : true;
22982 getGmapContext: function()
22984 return this.gMapContext
22987 GMapContext: function()
22989 var position = new google.maps.LatLng(this.latitude, this.longitude);
22991 var _map = new google.maps.Map(this.el.dom, {
22994 mapTypeId: this.mapTypeId,
22995 mapTypeControl: this.mapTypeControl,
22996 disableDoubleClickZoom: this.disableDoubleClickZoom,
22997 scrollwheel: this.scrollwheel,
22998 streetViewControl: this.streetViewControl,
22999 locationName: this.locationName,
23000 draggable: this.draggable,
23001 enableAutocomplete: this.enableAutocomplete,
23002 enableReverseGeocode: this.enableReverseGeocode
23005 var _marker = new google.maps.Marker({
23006 position: position,
23008 title: this.markerTitle,
23009 draggable: this.draggable
23016 location: position,
23017 radius: this.radius,
23018 locationName: this.locationName,
23019 addressComponents: {
23020 formatted_address: null,
23021 addressLine1: null,
23022 addressLine2: null,
23024 streetNumber: null,
23028 stateOrProvince: null
23031 domContainer: this.el.dom,
23032 geodecoder: new google.maps.Geocoder()
23036 drawCircle: function(center, radius, options)
23038 if (this.gMapContext.circle != null) {
23039 this.gMapContext.circle.setMap(null);
23043 options = Roo.apply({}, options, {
23044 strokeColor: "#0000FF",
23045 strokeOpacity: .35,
23047 fillColor: "#0000FF",
23051 options.map = this.gMapContext.map;
23052 options.radius = radius;
23053 options.center = center;
23054 this.gMapContext.circle = new google.maps.Circle(options);
23055 return this.gMapContext.circle;
23061 setPosition: function(location)
23063 this.gMapContext.location = location;
23064 this.gMapContext.marker.setPosition(location);
23065 this.gMapContext.map.panTo(location);
23066 this.drawCircle(location, this.gMapContext.radius, {});
23070 if (this.gMapContext.settings.enableReverseGeocode) {
23071 this.gMapContext.geodecoder.geocode({
23072 latLng: this.gMapContext.location
23073 }, function(results, status) {
23075 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23076 _this.gMapContext.locationName = results[0].formatted_address;
23077 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23079 _this.fireEvent('positionchanged', this, location);
23086 this.fireEvent('positionchanged', this, location);
23091 google.maps.event.trigger(this.gMapContext.map, "resize");
23093 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23095 this.fireEvent('resize', this);
23098 setPositionByLatLng: function(latitude, longitude)
23100 this.setPosition(new google.maps.LatLng(latitude, longitude));
23103 getCurrentPosition: function()
23106 latitude: this.gMapContext.location.lat(),
23107 longitude: this.gMapContext.location.lng()
23111 getAddressName: function()
23113 return this.gMapContext.locationName;
23116 getAddressComponents: function()
23118 return this.gMapContext.addressComponents;
23121 address_component_from_google_geocode: function(address_components)
23125 for (var i = 0; i < address_components.length; i++) {
23126 var component = address_components[i];
23127 if (component.types.indexOf("postal_code") >= 0) {
23128 result.postalCode = component.short_name;
23129 } else if (component.types.indexOf("street_number") >= 0) {
23130 result.streetNumber = component.short_name;
23131 } else if (component.types.indexOf("route") >= 0) {
23132 result.streetName = component.short_name;
23133 } else if (component.types.indexOf("neighborhood") >= 0) {
23134 result.city = component.short_name;
23135 } else if (component.types.indexOf("locality") >= 0) {
23136 result.city = component.short_name;
23137 } else if (component.types.indexOf("sublocality") >= 0) {
23138 result.district = component.short_name;
23139 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23140 result.stateOrProvince = component.short_name;
23141 } else if (component.types.indexOf("country") >= 0) {
23142 result.country = component.short_name;
23146 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23147 result.addressLine2 = "";
23151 setZoomLevel: function(zoom)
23153 this.gMapContext.map.setZoom(zoom);
23166 this.fireEvent('show', this);
23177 this.fireEvent('hide', this);
23182 Roo.apply(Roo.bootstrap.LocationPicker, {
23184 OverlayView : function(map, options)
23186 options = options || {};
23200 * @class Roo.bootstrap.Alert
23201 * @extends Roo.bootstrap.Component
23202 * Bootstrap Alert class
23203 * @cfg {String} title The title of alert
23204 * @cfg {String} html The content of alert
23205 * @cfg {String} weight ( success | info | warning | danger )
23206 * @cfg {String} faicon font-awesomeicon
23209 * Create a new alert
23210 * @param {Object} config The config object
23214 Roo.bootstrap.Alert = function(config){
23215 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23219 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23226 getAutoCreate : function()
23235 cls : 'roo-alert-icon'
23240 cls : 'roo-alert-title',
23245 cls : 'roo-alert-text',
23252 cfg.cn[0].cls += ' fa ' + this.faicon;
23256 cfg.cls += ' alert-' + this.weight;
23262 initEvents: function()
23264 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23267 setTitle : function(str)
23269 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23272 setText : function(str)
23274 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23277 setWeight : function(weight)
23280 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23283 this.weight = weight;
23285 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23288 setIcon : function(icon)
23291 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23296 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);