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(['xs', 'sm', 'md', 'lg'], function(size){
1380 if(!_this[size + 'Url']){
1386 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1387 html: _this.html || cfg.html,
1388 src: _this[size + 'Url']
1391 img.cls += ' roo-image-responsive-' + size;
1393 var s = ['xs', 'sm', 'md', 'lg'];
1395 Roo.each(s.splice(s.indexOf(size), 1), function(ss){
1396 img.cls += ' hidden-' + ss;
1399 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1400 cfg.cls += ' img-' + _this.border;
1404 cfg.alt = _this.alt;
1417 a.target = _this.target;
1421 cfg.cn.push((_this.href) ? a : img);
1428 createSingleImg : function()
1432 cls: (this.imgResponsive) ? 'img-responsive' : '',
1436 cfg.html = this.html || cfg.html;
1438 cfg.src = this.src || cfg.src;
1440 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1441 cfg.cls += ' img-' + this.border;
1458 a.target = this.target;
1463 return (this.href) ? a : cfg;
1466 initEvents: function()
1469 this.el.on('click', this.onClick, this);
1474 onClick : function(e)
1476 Roo.log('img onclick');
1477 this.fireEvent('click', this, e);
1491 * @class Roo.bootstrap.Link
1492 * @extends Roo.bootstrap.Component
1493 * Bootstrap Link Class
1494 * @cfg {String} alt image alternative text
1495 * @cfg {String} href a tag href
1496 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1497 * @cfg {String} html the content of the link.
1498 * @cfg {String} anchor name for the anchor link
1500 * @cfg {Boolean} preventDefault (true | false) default false
1504 * Create a new Input
1505 * @param {Object} config The config object
1508 Roo.bootstrap.Link = function(config){
1509 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1515 * The img click event for the img.
1516 * @param {Roo.EventObject} e
1522 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1526 preventDefault: false,
1530 getAutoCreate : function()
1536 // anchor's do not require html/href...
1537 if (this.anchor === false) {
1538 cfg.html = this.html || '';
1539 cfg.href = this.href || '#';
1541 cfg.name = this.anchor;
1542 if (this.html !== false) {
1543 cfg.html = this.html;
1545 if (this.href !== false) {
1546 cfg.href = this.href;
1550 if(this.alt !== false){
1555 if(this.target !== false) {
1556 cfg.target = this.target;
1562 initEvents: function() {
1564 if(!this.href || this.preventDefault){
1565 this.el.on('click', this.onClick, this);
1569 onClick : function(e)
1571 if(this.preventDefault){
1574 //Roo.log('img onclick');
1575 this.fireEvent('click', this, e);
1588 * @class Roo.bootstrap.Header
1589 * @extends Roo.bootstrap.Component
1590 * Bootstrap Header class
1591 * @cfg {String} html content of header
1592 * @cfg {Number} level (1|2|3|4|5|6) default 1
1595 * Create a new Header
1596 * @param {Object} config The config object
1600 Roo.bootstrap.Header = function(config){
1601 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1604 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1612 getAutoCreate : function(){
1617 tag: 'h' + (1 *this.level),
1618 html: this.html || ''
1630 * Ext JS Library 1.1.1
1631 * Copyright(c) 2006-2007, Ext JS, LLC.
1633 * Originally Released Under LGPL - original licence link has changed is not relivant.
1636 * <script type="text/javascript">
1640 * @class Roo.bootstrap.MenuMgr
1641 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1644 Roo.bootstrap.MenuMgr = function(){
1645 var menus, active, groups = {}, attached = false, lastShow = new Date();
1647 // private - called when first menu is created
1650 active = new Roo.util.MixedCollection();
1651 Roo.get(document).addKeyListener(27, function(){
1652 if(active.length > 0){
1660 if(active && active.length > 0){
1661 var c = active.clone();
1671 if(active.length < 1){
1672 Roo.get(document).un("mouseup", onMouseDown);
1680 var last = active.last();
1681 lastShow = new Date();
1684 Roo.get(document).on("mouseup", onMouseDown);
1689 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1690 m.parentMenu.activeChild = m;
1691 }else if(last && last.isVisible()){
1692 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1697 function onBeforeHide(m){
1699 m.activeChild.hide();
1701 if(m.autoHideTimer){
1702 clearTimeout(m.autoHideTimer);
1703 delete m.autoHideTimer;
1708 function onBeforeShow(m){
1709 var pm = m.parentMenu;
1710 if(!pm && !m.allowOtherMenus){
1712 }else if(pm && pm.activeChild && active != m){
1713 pm.activeChild.hide();
1717 // private this should really trigger on mouseup..
1718 function onMouseDown(e){
1719 Roo.log("on Mouse Up");
1720 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1730 function onBeforeCheck(mi, state){
1732 var g = groups[mi.group];
1733 for(var i = 0, l = g.length; i < l; i++){
1735 g[i].setChecked(false);
1744 * Hides all menus that are currently visible
1746 hideAll : function(){
1751 register : function(menu){
1755 menus[menu.id] = menu;
1756 menu.on("beforehide", onBeforeHide);
1757 menu.on("hide", onHide);
1758 menu.on("beforeshow", onBeforeShow);
1759 menu.on("show", onShow);
1761 if(g && menu.events["checkchange"]){
1765 groups[g].push(menu);
1766 menu.on("checkchange", onCheck);
1771 * Returns a {@link Roo.menu.Menu} object
1772 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1773 * be used to generate and return a new Menu instance.
1775 get : function(menu){
1776 if(typeof menu == "string"){ // menu id
1778 }else if(menu.events){ // menu instance
1781 /*else if(typeof menu.length == 'number'){ // array of menu items?
1782 return new Roo.bootstrap.Menu({items:menu});
1783 }else{ // otherwise, must be a config
1784 return new Roo.bootstrap.Menu(menu);
1791 unregister : function(menu){
1792 delete menus[menu.id];
1793 menu.un("beforehide", onBeforeHide);
1794 menu.un("hide", onHide);
1795 menu.un("beforeshow", onBeforeShow);
1796 menu.un("show", onShow);
1798 if(g && menu.events["checkchange"]){
1799 groups[g].remove(menu);
1800 menu.un("checkchange", onCheck);
1805 registerCheckable : function(menuItem){
1806 var g = menuItem.group;
1811 groups[g].push(menuItem);
1812 menuItem.on("beforecheckchange", onBeforeCheck);
1817 unregisterCheckable : function(menuItem){
1818 var g = menuItem.group;
1820 groups[g].remove(menuItem);
1821 menuItem.un("beforecheckchange", onBeforeCheck);
1833 * @class Roo.bootstrap.Menu
1834 * @extends Roo.bootstrap.Component
1835 * Bootstrap Menu class - container for MenuItems
1836 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1840 * @param {Object} config The config object
1844 Roo.bootstrap.Menu = function(config){
1845 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1846 if (this.registerMenu) {
1847 Roo.bootstrap.MenuMgr.register(this);
1852 * Fires before this menu is displayed
1853 * @param {Roo.menu.Menu} this
1858 * Fires before this menu is hidden
1859 * @param {Roo.menu.Menu} this
1864 * Fires after this menu is displayed
1865 * @param {Roo.menu.Menu} this
1870 * Fires after this menu is hidden
1871 * @param {Roo.menu.Menu} this
1876 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1877 * @param {Roo.menu.Menu} this
1878 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1879 * @param {Roo.EventObject} e
1884 * Fires when the mouse is hovering over 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 the mouse exits this menu
1893 * @param {Roo.menu.Menu} this
1894 * @param {Roo.EventObject} e
1895 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1900 * Fires when a menu item contained in this menu is clicked
1901 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1902 * @param {Roo.EventObject} e
1906 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1909 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1913 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1916 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1918 registerMenu : true,
1920 menuItems :false, // stores the menu items..
1926 getChildContainer : function() {
1930 getAutoCreate : function(){
1932 //if (['right'].indexOf(this.align)!==-1) {
1933 // cfg.cn[1].cls += ' pull-right'
1939 cls : 'dropdown-menu' ,
1940 style : 'z-index:1000'
1944 if (this.type === 'submenu') {
1945 cfg.cls = 'submenu active';
1947 if (this.type === 'treeview') {
1948 cfg.cls = 'treeview-menu';
1953 initEvents : function() {
1955 // Roo.log("ADD event");
1956 // Roo.log(this.triggerEl.dom);
1957 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1959 this.triggerEl.addClass('dropdown-toggle');
1960 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1962 this.el.on("mouseover", this.onMouseOver, this);
1963 this.el.on("mouseout", this.onMouseOut, this);
1967 findTargetItem : function(e){
1968 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1972 //Roo.log(t); Roo.log(t.id);
1974 //Roo.log(this.menuitems);
1975 return this.menuitems.get(t.id);
1977 //return this.items.get(t.menuItemId);
1982 onClick : function(e){
1983 Roo.log("menu.onClick");
1984 var t = this.findTargetItem(e);
1985 if(!t || t.isContainer){
1990 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1991 if(t == this.activeItem && t.shouldDeactivate(e)){
1992 this.activeItem.deactivate();
1993 delete this.activeItem;
1997 this.setActiveItem(t, true);
2005 Roo.log('pass click event');
2009 this.fireEvent("click", this, t, e);
2013 onMouseOver : function(e){
2014 var t = this.findTargetItem(e);
2017 // if(t.canActivate && !t.disabled){
2018 // this.setActiveItem(t, true);
2022 this.fireEvent("mouseover", this, e, t);
2024 isVisible : function(){
2025 return !this.hidden;
2027 onMouseOut : function(e){
2028 var t = this.findTargetItem(e);
2031 // if(t == this.activeItem && t.shouldDeactivate(e)){
2032 // this.activeItem.deactivate();
2033 // delete this.activeItem;
2036 this.fireEvent("mouseout", this, e, t);
2041 * Displays this menu relative to another element
2042 * @param {String/HTMLElement/Roo.Element} element The element to align to
2043 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2044 * the element (defaults to this.defaultAlign)
2045 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2047 show : function(el, pos, parentMenu){
2048 this.parentMenu = parentMenu;
2052 this.fireEvent("beforeshow", this);
2053 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2056 * Displays this menu at a specific xy position
2057 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2058 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2060 showAt : function(xy, parentMenu, /* private: */_e){
2061 this.parentMenu = parentMenu;
2066 this.fireEvent("beforeshow", this);
2067 //xy = this.el.adjustForConstraints(xy);
2071 this.hideMenuItems();
2072 this.hidden = false;
2073 this.triggerEl.addClass('open');
2075 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2076 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2081 this.fireEvent("show", this);
2087 this.doFocus.defer(50, this);
2091 doFocus : function(){
2093 this.focusEl.focus();
2098 * Hides this menu and optionally all parent menus
2099 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2101 hide : function(deep){
2103 this.hideMenuItems();
2104 if(this.el && this.isVisible()){
2105 this.fireEvent("beforehide", this);
2106 if(this.activeItem){
2107 this.activeItem.deactivate();
2108 this.activeItem = null;
2110 this.triggerEl.removeClass('open');;
2112 this.fireEvent("hide", this);
2114 if(deep === true && this.parentMenu){
2115 this.parentMenu.hide(true);
2119 onTriggerPress : function(e)
2122 Roo.log('trigger press');
2123 //Roo.log(e.getTarget());
2124 // Roo.log(this.triggerEl.dom);
2125 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2129 if (this.isVisible()) {
2134 this.show(this.triggerEl, false, false);
2143 hideMenuItems : function()
2145 //$(backdrop).remove()
2146 Roo.select('.open',true).each(function(aa) {
2148 aa.removeClass('open');
2149 //var parent = getParent($(this))
2150 //var relatedTarget = { relatedTarget: this }
2152 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2153 //if (e.isDefaultPrevented()) return
2154 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2157 addxtypeChild : function (tree, cntr) {
2158 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2160 this.menuitems.add(comp);
2181 * @class Roo.bootstrap.MenuItem
2182 * @extends Roo.bootstrap.Component
2183 * Bootstrap MenuItem class
2184 * @cfg {String} html the menu label
2185 * @cfg {String} href the link
2186 * @cfg {Boolean} preventDefault (true | false) default true
2187 * @cfg {Boolean} isContainer (true | false) default false
2191 * Create a new MenuItem
2192 * @param {Object} config The config object
2196 Roo.bootstrap.MenuItem = function(config){
2197 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2202 * The raw click event for the entire grid.
2203 * @param {Roo.bootstrap.MenuItem} this
2204 * @param {Roo.EventObject} e
2210 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2214 preventDefault: true,
2215 isContainer : false,
2217 getAutoCreate : function(){
2219 if(this.isContainer){
2222 cls: 'dropdown-menu-item'
2228 cls: 'dropdown-menu-item',
2237 if (this.parent().type == 'treeview') {
2238 cfg.cls = 'treeview-menu';
2241 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2242 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2246 initEvents: function() {
2248 //this.el.select('a').on('click', this.onClick, this);
2251 onClick : function(e)
2253 Roo.log('item on click ');
2254 //if(this.preventDefault){
2255 // e.preventDefault();
2257 //this.parent().hideMenuItems();
2259 this.fireEvent('click', this, e);
2278 * @class Roo.bootstrap.MenuSeparator
2279 * @extends Roo.bootstrap.Component
2280 * Bootstrap MenuSeparator class
2283 * Create a new MenuItem
2284 * @param {Object} config The config object
2288 Roo.bootstrap.MenuSeparator = function(config){
2289 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2292 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2294 getAutoCreate : function(){
2313 * @class Roo.bootstrap.Modal
2314 * @extends Roo.bootstrap.Component
2315 * Bootstrap Modal class
2316 * @cfg {String} title Title of dialog
2317 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2318 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2319 * @cfg {Boolean} specificTitle default false
2320 * @cfg {Array} buttons Array of buttons or standard button set..
2321 * @cfg {String} buttonPosition (left|right|center) default right
2322 * @cfg {Boolean} animate default true
2323 * @cfg {Boolean} allow_close default true
2326 * Create a new Modal Dialog
2327 * @param {Object} config The config object
2330 Roo.bootstrap.Modal = function(config){
2331 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2336 * The raw btnclick event for the button
2337 * @param {Roo.EventObject} e
2341 this.buttons = this.buttons || [];
2344 this.tmpl = Roo.factory(this.tmpl);
2349 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2351 title : 'test dialog',
2361 specificTitle: false,
2363 buttonPosition: 'right',
2377 onRender : function(ct, position)
2379 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2382 var cfg = Roo.apply({}, this.getAutoCreate());
2385 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2387 //if (!cfg.name.length) {
2391 cfg.cls += ' ' + this.cls;
2394 cfg.style = this.style;
2396 this.el = Roo.get(document.body).createChild(cfg, position);
2398 //var type = this.el.dom.type;
2403 if(this.tabIndex !== undefined){
2404 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2408 this.bodyEl = this.el.select('.modal-body',true).first();
2409 this.closeEl = this.el.select('.modal-header .close', true).first();
2410 this.footerEl = this.el.select('.modal-footer',true).first();
2411 this.titleEl = this.el.select('.modal-title',true).first();
2415 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2416 this.maskEl.enableDisplayMode("block");
2418 //this.el.addClass("x-dlg-modal");
2420 if (this.buttons.length) {
2421 Roo.each(this.buttons, function(bb) {
2422 b = Roo.apply({}, bb);
2423 b.xns = b.xns || Roo.bootstrap;
2424 b.xtype = b.xtype || 'Button';
2425 if (typeof(b.listeners) == 'undefined') {
2426 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2429 var btn = Roo.factory(b);
2431 btn.onRender(this.el.select('.modal-footer div').first());
2435 // render the children.
2438 if(typeof(this.items) != 'undefined'){
2439 var items = this.items;
2442 for(var i =0;i < items.length;i++) {
2443 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2447 this.items = nitems;
2449 // where are these used - they used to be body/close/footer
2453 //this.el.addClass([this.fieldClass, this.cls]);
2456 getAutoCreate : function(){
2461 html : this.html || ''
2466 cls : 'modal-title',
2470 if(this.specificTitle){
2476 if (this.allow_close) {
2487 style : 'display: none',
2490 cls: "modal-dialog",
2493 cls : "modal-content",
2496 cls : 'modal-header',
2501 cls : 'modal-footer',
2505 cls: 'btn-' + this.buttonPosition
2522 modal.cls += ' fade';
2528 getChildContainer : function() {
2533 getButtonContainer : function() {
2534 return this.el.select('.modal-footer div',true).first();
2537 initEvents : function()
2539 if (this.allow_close) {
2540 this.closeEl.on('click', this.hide, this);
2546 if (!this.rendered) {
2550 this.el.setStyle('display', 'block');
2554 (function(){ _this.el.addClass('in'); }).defer(50);
2556 this.el.addClass('in');
2559 // not sure how we can show data in here..
2561 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2564 Roo.get(document.body).addClass("x-body-masked");
2565 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2567 this.el.setStyle('zIndex', '10001');
2569 this.fireEvent('show', this);
2576 Roo.get(document.body).removeClass("x-body-masked");
2577 this.el.removeClass('in');
2581 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2583 this.el.setStyle('display', 'none');
2586 this.fireEvent('hide', this);
2589 addButton : function(str, cb)
2593 var b = Roo.apply({}, { html : str } );
2594 b.xns = b.xns || Roo.bootstrap;
2595 b.xtype = b.xtype || 'Button';
2596 if (typeof(b.listeners) == 'undefined') {
2597 b.listeners = { click : cb.createDelegate(this) };
2600 var btn = Roo.factory(b);
2602 btn.onRender(this.el.select('.modal-footer div').first());
2608 setDefaultButton : function(btn)
2610 //this.el.select('.modal-footer').()
2612 resizeTo: function(w,h)
2616 setContentSize : function(w, h)
2620 onButtonClick: function(btn,e)
2623 this.fireEvent('btnclick', btn.name, e);
2626 * Set the title of the Dialog
2627 * @param {String} str new Title
2629 setTitle: function(str) {
2630 this.titleEl.dom.innerHTML = str;
2633 * Set the body of the Dialog
2634 * @param {String} str new Title
2636 setBody: function(str) {
2637 this.bodyEl.dom.innerHTML = str;
2640 * Set the body of the Dialog using the template
2641 * @param {Obj} data - apply this data to the template and replace the body contents.
2643 applyBody: function(obj)
2646 Roo.log("Error - using apply Body without a template");
2649 this.tmpl.overwrite(this.bodyEl, obj);
2655 Roo.apply(Roo.bootstrap.Modal, {
2657 * Button config that displays a single OK button
2666 * Button config that displays Yes and No buttons
2682 * Button config that displays OK and Cancel buttons
2697 * Button config that displays Yes, No and Cancel buttons
2720 * messagebox - can be used as a replace
2724 * @class Roo.MessageBox
2725 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2729 Roo.Msg.alert('Status', 'Changes saved successfully.');
2731 // Prompt for user data:
2732 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2734 // process text value...
2738 // Show a dialog using config options:
2740 title:'Save Changes?',
2741 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2742 buttons: Roo.Msg.YESNOCANCEL,
2749 Roo.bootstrap.MessageBox = function(){
2750 var dlg, opt, mask, waitTimer;
2751 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2752 var buttons, activeTextEl, bwidth;
2756 var handleButton = function(button){
2758 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2762 var handleHide = function(){
2764 dlg.el.removeClass(opt.cls);
2767 // Roo.TaskMgr.stop(waitTimer);
2768 // waitTimer = null;
2773 var updateButtons = function(b){
2776 buttons["ok"].hide();
2777 buttons["cancel"].hide();
2778 buttons["yes"].hide();
2779 buttons["no"].hide();
2780 //dlg.footer.dom.style.display = 'none';
2783 dlg.footerEl.dom.style.display = '';
2784 for(var k in buttons){
2785 if(typeof buttons[k] != "function"){
2788 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2789 width += buttons[k].el.getWidth()+15;
2799 var handleEsc = function(d, k, e){
2800 if(opt && opt.closable !== false){
2810 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2811 * @return {Roo.BasicDialog} The BasicDialog element
2813 getDialog : function(){
2815 dlg = new Roo.bootstrap.Modal( {
2818 //constraintoviewport:false,
2820 //collapsible : false,
2825 //buttonAlign:"center",
2826 closeClick : function(){
2827 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2830 handleButton("cancel");
2835 dlg.on("hide", handleHide);
2837 //dlg.addKeyListener(27, handleEsc);
2839 this.buttons = buttons;
2840 var bt = this.buttonText;
2841 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2842 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2843 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2844 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2846 bodyEl = dlg.bodyEl.createChild({
2848 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2849 '<textarea class="roo-mb-textarea"></textarea>' +
2850 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2852 msgEl = bodyEl.dom.firstChild;
2853 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2854 textboxEl.enableDisplayMode();
2855 textboxEl.addKeyListener([10,13], function(){
2856 if(dlg.isVisible() && opt && opt.buttons){
2859 }else if(opt.buttons.yes){
2860 handleButton("yes");
2864 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2865 textareaEl.enableDisplayMode();
2866 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2867 progressEl.enableDisplayMode();
2868 var pf = progressEl.dom.firstChild;
2870 pp = Roo.get(pf.firstChild);
2871 pp.setHeight(pf.offsetHeight);
2879 * Updates the message box body text
2880 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2881 * the XHTML-compliant non-breaking space character '&#160;')
2882 * @return {Roo.MessageBox} This message box
2884 updateText : function(text){
2885 if(!dlg.isVisible() && !opt.width){
2886 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2888 msgEl.innerHTML = text || ' ';
2890 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2891 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2893 Math.min(opt.width || cw , this.maxWidth),
2894 Math.max(opt.minWidth || this.minWidth, bwidth)
2897 activeTextEl.setWidth(w);
2899 if(dlg.isVisible()){
2900 dlg.fixedcenter = false;
2902 // to big, make it scroll. = But as usual stupid IE does not support
2905 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2906 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2907 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2909 bodyEl.dom.style.height = '';
2910 bodyEl.dom.style.overflowY = '';
2913 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2915 bodyEl.dom.style.overflowX = '';
2918 dlg.setContentSize(w, bodyEl.getHeight());
2919 if(dlg.isVisible()){
2920 dlg.fixedcenter = true;
2926 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2927 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2928 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2929 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2930 * @return {Roo.MessageBox} This message box
2932 updateProgress : function(value, text){
2934 this.updateText(text);
2936 if (pp) { // weird bug on my firefox - for some reason this is not defined
2937 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2943 * Returns true if the message box is currently displayed
2944 * @return {Boolean} True if the message box is visible, else false
2946 isVisible : function(){
2947 return dlg && dlg.isVisible();
2951 * Hides the message box if it is displayed
2954 if(this.isVisible()){
2960 * Displays a new message box, or reinitializes an existing message box, based on the config options
2961 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2962 * The following config object properties are supported:
2964 Property Type Description
2965 ---------- --------------- ------------------------------------------------------------------------------------
2966 animEl String/Element An id or Element from which the message box should animate as it opens and
2967 closes (defaults to undefined)
2968 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2969 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2970 closable Boolean False to hide the top-right close button (defaults to true). Note that
2971 progress and wait dialogs will ignore this property and always hide the
2972 close button as they can only be closed programmatically.
2973 cls String A custom CSS class to apply to the message box element
2974 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2975 displayed (defaults to 75)
2976 fn Function A callback function to execute after closing the dialog. The arguments to the
2977 function will be btn (the name of the button that was clicked, if applicable,
2978 e.g. "ok"), and text (the value of the active text field, if applicable).
2979 Progress and wait dialogs will ignore this option since they do not respond to
2980 user actions and can only be closed programmatically, so any required function
2981 should be called by the same code after it closes the dialog.
2982 icon String A CSS class that provides a background image to be used as an icon for
2983 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2984 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2985 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2986 modal Boolean False to allow user interaction with the page while the message box is
2987 displayed (defaults to true)
2988 msg String A string that will replace the existing message box body text (defaults
2989 to the XHTML-compliant non-breaking space character ' ')
2990 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2991 progress Boolean True to display a progress bar (defaults to false)
2992 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2993 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2994 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2995 title String The title text
2996 value String The string value to set into the active textbox element if displayed
2997 wait Boolean True to display a progress bar (defaults to false)
2998 width Number The width of the dialog in pixels
3005 msg: 'Please enter your address:',
3007 buttons: Roo.MessageBox.OKCANCEL,
3010 animEl: 'addAddressBtn'
3013 * @param {Object} config Configuration options
3014 * @return {Roo.MessageBox} This message box
3016 show : function(options)
3019 // this causes nightmares if you show one dialog after another
3020 // especially on callbacks..
3022 if(this.isVisible()){
3025 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3026 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3027 Roo.log("New Dialog Message:" + options.msg )
3028 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3029 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3032 var d = this.getDialog();
3034 d.setTitle(opt.title || " ");
3035 d.closeEl.setDisplayed(opt.closable !== false);
3036 activeTextEl = textboxEl;
3037 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3042 textareaEl.setHeight(typeof opt.multiline == "number" ?
3043 opt.multiline : this.defaultTextHeight);
3044 activeTextEl = textareaEl;
3053 progressEl.setDisplayed(opt.progress === true);
3054 this.updateProgress(0);
3055 activeTextEl.dom.value = opt.value || "";
3057 dlg.setDefaultButton(activeTextEl);
3059 var bs = opt.buttons;
3063 }else if(bs && bs.yes){
3064 db = buttons["yes"];
3066 dlg.setDefaultButton(db);
3068 bwidth = updateButtons(opt.buttons);
3069 this.updateText(opt.msg);
3071 d.el.addClass(opt.cls);
3073 d.proxyDrag = opt.proxyDrag === true;
3074 d.modal = opt.modal !== false;
3075 d.mask = opt.modal !== false ? mask : false;
3077 // force it to the end of the z-index stack so it gets a cursor in FF
3078 document.body.appendChild(dlg.el.dom);
3079 d.animateTarget = null;
3080 d.show(options.animEl);
3086 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3087 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3088 * and closing the message box when the process is complete.
3089 * @param {String} title The title bar text
3090 * @param {String} msg The message box body text
3091 * @return {Roo.MessageBox} This message box
3093 progress : function(title, msg){
3100 minWidth: this.minProgressWidth,
3107 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3108 * If a callback function is passed it will be called after the user clicks the button, and the
3109 * id of the button that was clicked will be passed as the only parameter to the callback
3110 * (could also be the top-right close button).
3111 * @param {String} title The title bar text
3112 * @param {String} msg The message box body text
3113 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3114 * @param {Object} scope (optional) The scope of the callback function
3115 * @return {Roo.MessageBox} This message box
3117 alert : function(title, msg, fn, scope){
3130 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3131 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3132 * You are responsible for closing the message box when the process is complete.
3133 * @param {String} msg The message box body text
3134 * @param {String} title (optional) The title bar text
3135 * @return {Roo.MessageBox} This message box
3137 wait : function(msg, title){
3148 waitTimer = Roo.TaskMgr.start({
3150 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3158 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3159 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3160 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3161 * @param {String} title The title bar text
3162 * @param {String} msg The message box body text
3163 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3164 * @param {Object} scope (optional) The scope of the callback function
3165 * @return {Roo.MessageBox} This message box
3167 confirm : function(title, msg, fn, scope){
3171 buttons: this.YESNO,
3180 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3181 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3182 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3183 * (could also be the top-right close button) and the text that was entered will be passed as the two
3184 * parameters to the callback.
3185 * @param {String} title The title bar text
3186 * @param {String} msg The message box body text
3187 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3188 * @param {Object} scope (optional) The scope of the callback function
3189 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3190 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3191 * @return {Roo.MessageBox} This message box
3193 prompt : function(title, msg, fn, scope, multiline){
3197 buttons: this.OKCANCEL,
3202 multiline: multiline,
3209 * Button config that displays a single OK button
3214 * Button config that displays Yes and No buttons
3217 YESNO : {yes:true, no:true},
3219 * Button config that displays OK and Cancel buttons
3222 OKCANCEL : {ok:true, cancel:true},
3224 * Button config that displays Yes, No and Cancel buttons
3227 YESNOCANCEL : {yes:true, no:true, cancel:true},
3230 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3233 defaultTextHeight : 75,
3235 * The maximum width in pixels of the message box (defaults to 600)
3240 * The minimum width in pixels of the message box (defaults to 100)
3245 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3246 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3249 minProgressWidth : 250,
3251 * An object containing the default button text strings that can be overriden for localized language support.
3252 * Supported properties are: ok, cancel, yes and no.
3253 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3266 * Shorthand for {@link Roo.MessageBox}
3268 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3269 Roo.Msg = Roo.Msg || Roo.MessageBox;
3278 * @class Roo.bootstrap.Navbar
3279 * @extends Roo.bootstrap.Component
3280 * Bootstrap Navbar class
3283 * Create a new Navbar
3284 * @param {Object} config The config object
3288 Roo.bootstrap.Navbar = function(config){
3289 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3293 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3302 getAutoCreate : function(){
3305 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3309 initEvents :function ()
3311 //Roo.log(this.el.select('.navbar-toggle',true));
3312 this.el.select('.navbar-toggle',true).on('click', function() {
3313 // Roo.log('click');
3314 this.el.select('.navbar-collapse',true).toggleClass('in');
3322 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3324 var size = this.el.getSize();
3325 this.maskEl.setSize(size.width, size.height);
3326 this.maskEl.enableDisplayMode("block");
3335 getChildContainer : function()
3337 if (this.el.select('.collapse').getCount()) {
3338 return this.el.select('.collapse',true).first();
3371 * @class Roo.bootstrap.NavSimplebar
3372 * @extends Roo.bootstrap.Navbar
3373 * Bootstrap Sidebar class
3375 * @cfg {Boolean} inverse is inverted color
3377 * @cfg {String} type (nav | pills | tabs)
3378 * @cfg {Boolean} arrangement stacked | justified
3379 * @cfg {String} align (left | right) alignment
3381 * @cfg {Boolean} main (true|false) main nav bar? default false
3382 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3384 * @cfg {String} tag (header|footer|nav|div) default is nav
3390 * Create a new Sidebar
3391 * @param {Object} config The config object
3395 Roo.bootstrap.NavSimplebar = function(config){
3396 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3399 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3415 getAutoCreate : function(){
3419 tag : this.tag || 'div',
3432 this.type = this.type || 'nav';
3433 if (['tabs','pills'].indexOf(this.type)!==-1) {
3434 cfg.cn[0].cls += ' nav-' + this.type
3438 if (this.type!=='nav') {
3439 Roo.log('nav type must be nav/tabs/pills')
3441 cfg.cn[0].cls += ' navbar-nav'
3447 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3448 cfg.cn[0].cls += ' nav-' + this.arrangement;
3452 if (this.align === 'right') {
3453 cfg.cn[0].cls += ' navbar-right';
3457 cfg.cls += ' navbar-inverse';
3484 * @class Roo.bootstrap.NavHeaderbar
3485 * @extends Roo.bootstrap.NavSimplebar
3486 * Bootstrap Sidebar class
3488 * @cfg {String} brand what is brand
3489 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3490 * @cfg {String} brand_href href of the brand
3491 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3492 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3493 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3494 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3497 * Create a new Sidebar
3498 * @param {Object} config The config object
3502 Roo.bootstrap.NavHeaderbar = function(config){
3503 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3507 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3514 desktopCenter : false,
3517 getAutoCreate : function(){
3520 tag: this.nav || 'nav',
3527 if (this.desktopCenter) {
3528 cn.push({cls : 'container', cn : []});
3535 cls: 'navbar-header',
3540 cls: 'navbar-toggle',
3541 'data-toggle': 'collapse',
3546 html: 'Toggle navigation'
3568 cls: 'collapse navbar-collapse',
3572 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3574 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3575 cfg.cls += ' navbar-' + this.position;
3577 // tag can override this..
3579 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3582 if (this.brand !== '') {
3585 href: this.brand_href ? this.brand_href : '#',
3586 cls: 'navbar-brand',
3594 cfg.cls += ' main-nav';
3602 getHeaderChildContainer : function()
3604 if (this.el.select('.navbar-header').getCount()) {
3605 return this.el.select('.navbar-header',true).first();
3608 return this.getChildContainer();
3612 initEvents : function()
3614 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3616 if (this.autohide) {
3621 Roo.get(document).on('scroll',function(e) {
3622 var ns = Roo.get(document).getScroll().top;
3623 var os = prevScroll;
3627 ft.removeClass('slideDown');
3628 ft.addClass('slideUp');
3631 ft.removeClass('slideUp');
3632 ft.addClass('slideDown');
3653 * @class Roo.bootstrap.NavSidebar
3654 * @extends Roo.bootstrap.Navbar
3655 * Bootstrap Sidebar class
3658 * Create a new Sidebar
3659 * @param {Object} config The config object
3663 Roo.bootstrap.NavSidebar = function(config){
3664 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3667 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3669 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3671 getAutoCreate : function(){
3676 cls: 'sidebar sidebar-nav'
3698 * @class Roo.bootstrap.NavGroup
3699 * @extends Roo.bootstrap.Component
3700 * Bootstrap NavGroup class
3701 * @cfg {String} align (left|right)
3702 * @cfg {Boolean} inverse
3703 * @cfg {String} type (nav|pills|tab) default nav
3704 * @cfg {String} navId - reference Id for navbar.
3708 * Create a new nav group
3709 * @param {Object} config The config object
3712 Roo.bootstrap.NavGroup = function(config){
3713 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3716 Roo.bootstrap.NavGroup.register(this);
3720 * Fires when the active item changes
3721 * @param {Roo.bootstrap.NavGroup} this
3722 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3723 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3730 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3741 getAutoCreate : function()
3743 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3750 if (['tabs','pills'].indexOf(this.type)!==-1) {
3751 cfg.cls += ' nav-' + this.type
3753 if (this.type!=='nav') {
3754 Roo.log('nav type must be nav/tabs/pills')
3756 cfg.cls += ' navbar-nav'
3759 if (this.parent().sidebar) {
3762 cls: 'dashboard-menu sidebar-menu'
3768 if (this.form === true) {
3774 if (this.align === 'right') {
3775 cfg.cls += ' navbar-right';
3777 cfg.cls += ' navbar-left';
3781 if (this.align === 'right') {
3782 cfg.cls += ' navbar-right';
3786 cfg.cls += ' navbar-inverse';
3794 * sets the active Navigation item
3795 * @param {Roo.bootstrap.NavItem} the new current navitem
3797 setActiveItem : function(item)
3800 Roo.each(this.navItems, function(v){
3805 v.setActive(false, true);
3812 item.setActive(true, true);
3813 this.fireEvent('changed', this, item, prev);
3818 * gets the active Navigation item
3819 * @return {Roo.bootstrap.NavItem} the current navitem
3821 getActive : function()
3825 Roo.each(this.navItems, function(v){
3836 indexOfNav : function()
3840 Roo.each(this.navItems, function(v,i){
3851 * adds a Navigation item
3852 * @param {Roo.bootstrap.NavItem} the navitem to add
3854 addItem : function(cfg)
3856 var cn = new Roo.bootstrap.NavItem(cfg);
3858 cn.parentId = this.id;
3859 cn.onRender(this.el, null);
3863 * register a Navigation item
3864 * @param {Roo.bootstrap.NavItem} the navitem to add
3866 register : function(item)
3868 this.navItems.push( item);
3869 item.navId = this.navId;
3874 * clear all the Navigation item
3877 clearAll : function()
3880 this.el.dom.innerHTML = '';
3883 getNavItem: function(tabId)
3886 Roo.each(this.navItems, function(e) {
3887 if (e.tabId == tabId) {
3897 setActiveNext : function()
3899 var i = this.indexOfNav(this.getActive());
3900 if (i > this.navItems.length) {
3903 this.setActiveItem(this.navItems[i+1]);
3905 setActivePrev : function()
3907 var i = this.indexOfNav(this.getActive());
3911 this.setActiveItem(this.navItems[i-1]);
3913 clearWasActive : function(except) {
3914 Roo.each(this.navItems, function(e) {
3915 if (e.tabId != except.tabId && e.was_active) {
3916 e.was_active = false;
3923 getWasActive : function ()
3926 Roo.each(this.navItems, function(e) {
3941 Roo.apply(Roo.bootstrap.NavGroup, {
3945 * register a Navigation Group
3946 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3948 register : function(navgrp)
3950 this.groups[navgrp.navId] = navgrp;
3954 * fetch a Navigation Group based on the navigation ID
3955 * @param {string} the navgroup to add
3956 * @returns {Roo.bootstrap.NavGroup} the navgroup
3958 get: function(navId) {
3959 if (typeof(this.groups[navId]) == 'undefined') {
3961 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3963 return this.groups[navId] ;
3978 * @class Roo.bootstrap.NavItem
3979 * @extends Roo.bootstrap.Component
3980 * Bootstrap Navbar.NavItem class
3981 * @cfg {String} href link to
3982 * @cfg {String} html content of button
3983 * @cfg {String} badge text inside badge
3984 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3985 * @cfg {String} glyphicon name of glyphicon
3986 * @cfg {String} icon name of font awesome icon
3987 * @cfg {Boolean} active Is item active
3988 * @cfg {Boolean} disabled Is item disabled
3990 * @cfg {Boolean} preventDefault (true | false) default false
3991 * @cfg {String} tabId the tab that this item activates.
3992 * @cfg {String} tagtype (a|span) render as a href or span?
3993 * @cfg {Boolean} animateRef (true|false) link to element default false
3996 * Create a new Navbar Item
3997 * @param {Object} config The config object
3999 Roo.bootstrap.NavItem = function(config){
4000 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4005 * The raw click event for the entire grid.
4006 * @param {Roo.EventObject} e
4011 * Fires when the active item active state changes
4012 * @param {Roo.bootstrap.NavItem} this
4013 * @param {boolean} state the new state
4019 * Fires when scroll to element
4020 * @param {Roo.bootstrap.NavItem} this
4021 * @param {Object} options
4022 * @param {Roo.EventObject} e
4030 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4038 preventDefault : false,
4045 getAutoCreate : function(){
4053 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4055 if (this.disabled) {
4056 cfg.cls += ' disabled';
4059 if (this.href || this.html || this.glyphicon || this.icon) {
4063 href : this.href || "#",
4064 html: this.html || ''
4069 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4072 if(this.glyphicon) {
4073 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4078 cfg.cn[0].html += " <span class='caret'></span>";
4082 if (this.badge !== '') {
4084 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4092 initEvents: function()
4094 if (typeof (this.menu) != 'undefined') {
4095 this.menu.parentType = this.xtype;
4096 this.menu.triggerEl = this.el;
4097 this.menu = this.addxtype(Roo.apply({}, this.menu));
4100 this.el.select('a',true).on('click', this.onClick, this);
4102 if(this.tagtype == 'span'){
4103 this.el.select('span',true).on('click', this.onClick, this);
4106 // at this point parent should be available..
4107 this.parent().register(this);
4110 onClick : function(e)
4113 this.preventDefault ||
4120 if (this.disabled) {
4124 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4125 if (tg && tg.transition) {
4126 Roo.log("waiting for the transitionend");
4132 //Roo.log("fire event clicked");
4133 if(this.fireEvent('click', this, e) === false){
4137 if(this.tagtype == 'span'){
4141 //Roo.log(this.href);
4142 var ael = this.el.select('a',true).first();
4145 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4146 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4147 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4148 return; // ignore... - it's a 'hash' to another page.
4152 this.scrollToElement(e);
4156 var p = this.parent();
4158 if (['tabs','pills'].indexOf(p.type)!==-1) {
4159 if (typeof(p.setActiveItem) !== 'undefined') {
4160 p.setActiveItem(this);
4164 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4165 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4166 // remove the collapsed menu expand...
4167 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4171 isActive: function () {
4174 setActive : function(state, fire, is_was_active)
4176 if (this.active && !state & this.navId) {
4177 this.was_active = true;
4178 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4180 nv.clearWasActive(this);
4184 this.active = state;
4187 this.el.removeClass('active');
4188 } else if (!this.el.hasClass('active')) {
4189 this.el.addClass('active');
4192 this.fireEvent('changed', this, state);
4195 // show a panel if it's registered and related..
4197 if (!this.navId || !this.tabId || !state || is_was_active) {
4201 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4205 var pan = tg.getPanelByName(this.tabId);
4209 // if we can not flip to new panel - go back to old nav highlight..
4210 if (false == tg.showPanel(pan)) {
4211 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4213 var onav = nv.getWasActive();
4215 onav.setActive(true, false, true);
4224 // this should not be here...
4225 setDisabled : function(state)
4227 this.disabled = state;
4229 this.el.removeClass('disabled');
4230 } else if (!this.el.hasClass('disabled')) {
4231 this.el.addClass('disabled');
4237 * Fetch the element to display the tooltip on.
4238 * @return {Roo.Element} defaults to this.el
4240 tooltipEl : function()
4242 return this.el.select('' + this.tagtype + '', true).first();
4245 scrollToElement : function(e)
4247 var c = document.body;
4250 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4252 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4253 c = document.documentElement;
4256 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4262 var o = target.calcOffsetsTo(c);
4269 this.fireEvent('scrollto', this, options, e);
4271 Roo.get(c).scrollTo('top', options.value, true);
4284 * <span> icon </span>
4285 * <span> text </span>
4286 * <span>badge </span>
4290 * @class Roo.bootstrap.NavSidebarItem
4291 * @extends Roo.bootstrap.NavItem
4292 * Bootstrap Navbar.NavSidebarItem class
4294 * Create a new Navbar Button
4295 * @param {Object} config The config object
4297 Roo.bootstrap.NavSidebarItem = function(config){
4298 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4303 * The raw click event for the entire grid.
4304 * @param {Roo.EventObject} e
4309 * Fires when the active item active state changes
4310 * @param {Roo.bootstrap.NavSidebarItem} this
4311 * @param {boolean} state the new state
4319 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4322 getAutoCreate : function(){
4327 href : this.href || '#',
4339 html : this.html || ''
4344 cfg.cls += ' active';
4348 if (this.glyphicon || this.icon) {
4349 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4350 a.cn.push({ tag : 'i', cls : c }) ;
4355 if (this.badge !== '') {
4356 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4360 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4361 a.cls += 'dropdown-toggle treeview' ;
4385 * @class Roo.bootstrap.Row
4386 * @extends Roo.bootstrap.Component
4387 * Bootstrap Row class (contains columns...)
4391 * @param {Object} config The config object
4394 Roo.bootstrap.Row = function(config){
4395 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4398 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4400 getAutoCreate : function(){
4419 * @class Roo.bootstrap.Element
4420 * @extends Roo.bootstrap.Component
4421 * Bootstrap Element class
4422 * @cfg {String} html contents of the element
4423 * @cfg {String} tag tag of the element
4424 * @cfg {String} cls class of the element
4425 * @cfg {Boolean} preventDefault (true|false) default false
4426 * @cfg {Boolean} clickable (true|false) default false
4429 * Create a new Element
4430 * @param {Object} config The config object
4433 Roo.bootstrap.Element = function(config){
4434 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4440 * When a element is chick
4441 * @param {Roo.bootstrap.Element} this
4442 * @param {Roo.EventObject} e
4448 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4453 preventDefault: false,
4456 getAutoCreate : function(){
4467 initEvents: function()
4469 Roo.bootstrap.Element.superclass.initEvents.call(this);
4472 this.el.on('click', this.onClick, this);
4477 onClick : function(e)
4479 if(this.preventDefault){
4483 this.fireEvent('click', this, e);
4486 getValue : function()
4488 return this.el.dom.innerHTML;
4491 setValue : function(value)
4493 this.el.dom.innerHTML = value;
4508 * @class Roo.bootstrap.Pagination
4509 * @extends Roo.bootstrap.Component
4510 * Bootstrap Pagination class
4511 * @cfg {String} size xs | sm | md | lg
4512 * @cfg {Boolean} inverse false | true
4515 * Create a new Pagination
4516 * @param {Object} config The config object
4519 Roo.bootstrap.Pagination = function(config){
4520 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4523 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4529 getAutoCreate : function(){
4535 cfg.cls += ' inverse';
4541 cfg.cls += " " + this.cls;
4559 * @class Roo.bootstrap.PaginationItem
4560 * @extends Roo.bootstrap.Component
4561 * Bootstrap PaginationItem class
4562 * @cfg {String} html text
4563 * @cfg {String} href the link
4564 * @cfg {Boolean} preventDefault (true | false) default true
4565 * @cfg {Boolean} active (true | false) default false
4566 * @cfg {Boolean} disabled default false
4570 * Create a new PaginationItem
4571 * @param {Object} config The config object
4575 Roo.bootstrap.PaginationItem = function(config){
4576 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4581 * The raw click event for the entire grid.
4582 * @param {Roo.EventObject} e
4588 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4592 preventDefault: true,
4597 getAutoCreate : function(){
4603 href : this.href ? this.href : '#',
4604 html : this.html ? this.html : ''
4614 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4618 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4624 initEvents: function() {
4626 this.el.on('click', this.onClick, this);
4629 onClick : function(e)
4631 Roo.log('PaginationItem on click ');
4632 if(this.preventDefault){
4640 this.fireEvent('click', this, e);
4656 * @class Roo.bootstrap.Slider
4657 * @extends Roo.bootstrap.Component
4658 * Bootstrap Slider class
4661 * Create a new Slider
4662 * @param {Object} config The config object
4665 Roo.bootstrap.Slider = function(config){
4666 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4669 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4671 getAutoCreate : function(){
4675 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4679 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4691 * Ext JS Library 1.1.1
4692 * Copyright(c) 2006-2007, Ext JS, LLC.
4694 * Originally Released Under LGPL - original licence link has changed is not relivant.
4697 * <script type="text/javascript">
4702 * @class Roo.grid.ColumnModel
4703 * @extends Roo.util.Observable
4704 * This is the default implementation of a ColumnModel used by the Grid. It defines
4705 * the columns in the grid.
4708 var colModel = new Roo.grid.ColumnModel([
4709 {header: "Ticker", width: 60, sortable: true, locked: true},
4710 {header: "Company Name", width: 150, sortable: true},
4711 {header: "Market Cap.", width: 100, sortable: true},
4712 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4713 {header: "Employees", width: 100, sortable: true, resizable: false}
4718 * The config options listed for this class are options which may appear in each
4719 * individual column definition.
4720 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4722 * @param {Object} config An Array of column config objects. See this class's
4723 * config objects for details.
4725 Roo.grid.ColumnModel = function(config){
4727 * The config passed into the constructor
4729 this.config = config;
4732 // if no id, create one
4733 // if the column does not have a dataIndex mapping,
4734 // map it to the order it is in the config
4735 for(var i = 0, len = config.length; i < len; i++){
4737 if(typeof c.dataIndex == "undefined"){
4740 if(typeof c.renderer == "string"){
4741 c.renderer = Roo.util.Format[c.renderer];
4743 if(typeof c.id == "undefined"){
4746 if(c.editor && c.editor.xtype){
4747 c.editor = Roo.factory(c.editor, Roo.grid);
4749 if(c.editor && c.editor.isFormField){
4750 c.editor = new Roo.grid.GridEditor(c.editor);
4752 this.lookup[c.id] = c;
4756 * The width of columns which have no width specified (defaults to 100)
4759 this.defaultWidth = 100;
4762 * Default sortable of columns which have no sortable specified (defaults to false)
4765 this.defaultSortable = false;
4769 * @event widthchange
4770 * Fires when the width of a column changes.
4771 * @param {ColumnModel} this
4772 * @param {Number} columnIndex The column index
4773 * @param {Number} newWidth The new width
4775 "widthchange": true,
4777 * @event headerchange
4778 * Fires when the text of a header changes.
4779 * @param {ColumnModel} this
4780 * @param {Number} columnIndex The column index
4781 * @param {Number} newText The new header text
4783 "headerchange": true,
4785 * @event hiddenchange
4786 * Fires when a column is hidden or "unhidden".
4787 * @param {ColumnModel} this
4788 * @param {Number} columnIndex The column index
4789 * @param {Boolean} hidden true if hidden, false otherwise
4791 "hiddenchange": true,
4793 * @event columnmoved
4794 * Fires when a column is moved.
4795 * @param {ColumnModel} this
4796 * @param {Number} oldIndex
4797 * @param {Number} newIndex
4799 "columnmoved" : true,
4801 * @event columlockchange
4802 * Fires when a column's locked state is changed
4803 * @param {ColumnModel} this
4804 * @param {Number} colIndex
4805 * @param {Boolean} locked true if locked
4807 "columnlockchange" : true
4809 Roo.grid.ColumnModel.superclass.constructor.call(this);
4811 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4813 * @cfg {String} header The header text to display in the Grid view.
4816 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4817 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4818 * specified, the column's index is used as an index into the Record's data Array.
4821 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4822 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4825 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4826 * Defaults to the value of the {@link #defaultSortable} property.
4827 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4830 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4833 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4836 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4839 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4842 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4843 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4844 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4845 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4848 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4851 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4854 * @cfg {String} cursor (Optional)
4857 * @cfg {String} tooltip (Optional)
4860 * Returns the id of the column at the specified index.
4861 * @param {Number} index The column index
4862 * @return {String} the id
4864 getColumnId : function(index){
4865 return this.config[index].id;
4869 * Returns the column for a specified id.
4870 * @param {String} id The column id
4871 * @return {Object} the column
4873 getColumnById : function(id){
4874 return this.lookup[id];
4879 * Returns the column for a specified dataIndex.
4880 * @param {String} dataIndex The column dataIndex
4881 * @return {Object|Boolean} the column or false if not found
4883 getColumnByDataIndex: function(dataIndex){
4884 var index = this.findColumnIndex(dataIndex);
4885 return index > -1 ? this.config[index] : false;
4889 * Returns the index for a specified column id.
4890 * @param {String} id The column id
4891 * @return {Number} the index, or -1 if not found
4893 getIndexById : function(id){
4894 for(var i = 0, len = this.config.length; i < len; i++){
4895 if(this.config[i].id == id){
4903 * Returns the index for a specified column dataIndex.
4904 * @param {String} dataIndex The column dataIndex
4905 * @return {Number} the index, or -1 if not found
4908 findColumnIndex : function(dataIndex){
4909 for(var i = 0, len = this.config.length; i < len; i++){
4910 if(this.config[i].dataIndex == dataIndex){
4918 moveColumn : function(oldIndex, newIndex){
4919 var c = this.config[oldIndex];
4920 this.config.splice(oldIndex, 1);
4921 this.config.splice(newIndex, 0, c);
4922 this.dataMap = null;
4923 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4926 isLocked : function(colIndex){
4927 return this.config[colIndex].locked === true;
4930 setLocked : function(colIndex, value, suppressEvent){
4931 if(this.isLocked(colIndex) == value){
4934 this.config[colIndex].locked = value;
4936 this.fireEvent("columnlockchange", this, colIndex, value);
4940 getTotalLockedWidth : function(){
4942 for(var i = 0; i < this.config.length; i++){
4943 if(this.isLocked(i) && !this.isHidden(i)){
4944 this.totalWidth += this.getColumnWidth(i);
4950 getLockedCount : function(){
4951 for(var i = 0, len = this.config.length; i < len; i++){
4952 if(!this.isLocked(i)){
4959 * Returns the number of columns.
4962 getColumnCount : function(visibleOnly){
4963 if(visibleOnly === true){
4965 for(var i = 0, len = this.config.length; i < len; i++){
4966 if(!this.isHidden(i)){
4972 return this.config.length;
4976 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4977 * @param {Function} fn
4978 * @param {Object} scope (optional)
4979 * @return {Array} result
4981 getColumnsBy : function(fn, scope){
4983 for(var i = 0, len = this.config.length; i < len; i++){
4984 var c = this.config[i];
4985 if(fn.call(scope||this, c, i) === true){
4993 * Returns true if the specified column is sortable.
4994 * @param {Number} col The column index
4997 isSortable : function(col){
4998 if(typeof this.config[col].sortable == "undefined"){
4999 return this.defaultSortable;
5001 return this.config[col].sortable;
5005 * Returns the rendering (formatting) function defined for the column.
5006 * @param {Number} col The column index.
5007 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5009 getRenderer : function(col){
5010 if(!this.config[col].renderer){
5011 return Roo.grid.ColumnModel.defaultRenderer;
5013 return this.config[col].renderer;
5017 * Sets the rendering (formatting) function for a column.
5018 * @param {Number} col The column index
5019 * @param {Function} fn The function to use to process the cell's raw data
5020 * to return HTML markup for the grid view. The render function is called with
5021 * the following parameters:<ul>
5022 * <li>Data value.</li>
5023 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5024 * <li>css A CSS style string to apply to the table cell.</li>
5025 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5026 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5027 * <li>Row index</li>
5028 * <li>Column index</li>
5029 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5031 setRenderer : function(col, fn){
5032 this.config[col].renderer = fn;
5036 * Returns the width for the specified column.
5037 * @param {Number} col The column index
5040 getColumnWidth : function(col){
5041 return this.config[col].width * 1 || this.defaultWidth;
5045 * Sets the width for a column.
5046 * @param {Number} col The column index
5047 * @param {Number} width The new width
5049 setColumnWidth : function(col, width, suppressEvent){
5050 this.config[col].width = width;
5051 this.totalWidth = null;
5053 this.fireEvent("widthchange", this, col, width);
5058 * Returns the total width of all columns.
5059 * @param {Boolean} includeHidden True to include hidden column widths
5062 getTotalWidth : function(includeHidden){
5063 if(!this.totalWidth){
5064 this.totalWidth = 0;
5065 for(var i = 0, len = this.config.length; i < len; i++){
5066 if(includeHidden || !this.isHidden(i)){
5067 this.totalWidth += this.getColumnWidth(i);
5071 return this.totalWidth;
5075 * Returns the header for the specified column.
5076 * @param {Number} col The column index
5079 getColumnHeader : function(col){
5080 return this.config[col].header;
5084 * Sets the header for a column.
5085 * @param {Number} col The column index
5086 * @param {String} header The new header
5088 setColumnHeader : function(col, header){
5089 this.config[col].header = header;
5090 this.fireEvent("headerchange", this, col, header);
5094 * Returns the tooltip for the specified column.
5095 * @param {Number} col The column index
5098 getColumnTooltip : function(col){
5099 return this.config[col].tooltip;
5102 * Sets the tooltip for a column.
5103 * @param {Number} col The column index
5104 * @param {String} tooltip The new tooltip
5106 setColumnTooltip : function(col, tooltip){
5107 this.config[col].tooltip = tooltip;
5111 * Returns the dataIndex for the specified column.
5112 * @param {Number} col The column index
5115 getDataIndex : function(col){
5116 return this.config[col].dataIndex;
5120 * Sets the dataIndex for a column.
5121 * @param {Number} col The column index
5122 * @param {Number} dataIndex The new dataIndex
5124 setDataIndex : function(col, dataIndex){
5125 this.config[col].dataIndex = dataIndex;
5131 * Returns true if the cell is editable.
5132 * @param {Number} colIndex The column index
5133 * @param {Number} rowIndex The row index
5136 isCellEditable : function(colIndex, rowIndex){
5137 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5141 * Returns the editor defined for the cell/column.
5142 * return false or null to disable editing.
5143 * @param {Number} colIndex The column index
5144 * @param {Number} rowIndex The row index
5147 getCellEditor : function(colIndex, rowIndex){
5148 return this.config[colIndex].editor;
5152 * Sets if a column is editable.
5153 * @param {Number} col The column index
5154 * @param {Boolean} editable True if the column is editable
5156 setEditable : function(col, editable){
5157 this.config[col].editable = editable;
5162 * Returns true if the column is hidden.
5163 * @param {Number} colIndex The column index
5166 isHidden : function(colIndex){
5167 return this.config[colIndex].hidden;
5172 * Returns true if the column width cannot be changed
5174 isFixed : function(colIndex){
5175 return this.config[colIndex].fixed;
5179 * Returns true if the column can be resized
5182 isResizable : function(colIndex){
5183 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5186 * Sets if a column is hidden.
5187 * @param {Number} colIndex The column index
5188 * @param {Boolean} hidden True if the column is hidden
5190 setHidden : function(colIndex, hidden){
5191 this.config[colIndex].hidden = hidden;
5192 this.totalWidth = null;
5193 this.fireEvent("hiddenchange", this, colIndex, hidden);
5197 * Sets the editor for a column.
5198 * @param {Number} col The column index
5199 * @param {Object} editor The editor object
5201 setEditor : function(col, editor){
5202 this.config[col].editor = editor;
5206 Roo.grid.ColumnModel.defaultRenderer = function(value){
5207 if(typeof value == "string" && value.length < 1){
5213 // Alias for backwards compatibility
5214 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5217 * Ext JS Library 1.1.1
5218 * Copyright(c) 2006-2007, Ext JS, LLC.
5220 * Originally Released Under LGPL - original licence link has changed is not relivant.
5223 * <script type="text/javascript">
5227 * @class Roo.LoadMask
5228 * A simple utility class for generically masking elements while loading data. If the element being masked has
5229 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5230 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5231 * element's UpdateManager load indicator and will be destroyed after the initial load.
5233 * Create a new LoadMask
5234 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5235 * @param {Object} config The config object
5237 Roo.LoadMask = function(el, config){
5238 this.el = Roo.get(el);
5239 Roo.apply(this, config);
5241 this.store.on('beforeload', this.onBeforeLoad, this);
5242 this.store.on('load', this.onLoad, this);
5243 this.store.on('loadexception', this.onLoadException, this);
5244 this.removeMask = false;
5246 var um = this.el.getUpdateManager();
5247 um.showLoadIndicator = false; // disable the default indicator
5248 um.on('beforeupdate', this.onBeforeLoad, this);
5249 um.on('update', this.onLoad, this);
5250 um.on('failure', this.onLoad, this);
5251 this.removeMask = true;
5255 Roo.LoadMask.prototype = {
5257 * @cfg {Boolean} removeMask
5258 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5259 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5263 * The text to display in a centered loading message box (defaults to 'Loading...')
5267 * @cfg {String} msgCls
5268 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5270 msgCls : 'x-mask-loading',
5273 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5279 * Disables the mask to prevent it from being displayed
5281 disable : function(){
5282 this.disabled = true;
5286 * Enables the mask so that it can be displayed
5288 enable : function(){
5289 this.disabled = false;
5292 onLoadException : function()
5296 if (typeof(arguments[3]) != 'undefined') {
5297 Roo.MessageBox.alert("Error loading",arguments[3]);
5301 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5302 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5311 this.el.unmask(this.removeMask);
5316 this.el.unmask(this.removeMask);
5320 onBeforeLoad : function(){
5322 this.el.mask(this.msg, this.msgCls);
5327 destroy : function(){
5329 this.store.un('beforeload', this.onBeforeLoad, this);
5330 this.store.un('load', this.onLoad, this);
5331 this.store.un('loadexception', this.onLoadException, this);
5333 var um = this.el.getUpdateManager();
5334 um.un('beforeupdate', this.onBeforeLoad, this);
5335 um.un('update', this.onLoad, this);
5336 um.un('failure', this.onLoad, this);
5347 * @class Roo.bootstrap.Table
5348 * @extends Roo.bootstrap.Component
5349 * Bootstrap Table class
5350 * @cfg {String} cls table class
5351 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5352 * @cfg {String} bgcolor Specifies the background color for a table
5353 * @cfg {Number} border Specifies whether the table cells should have borders or not
5354 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5355 * @cfg {Number} cellspacing Specifies the space between cells
5356 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5357 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5358 * @cfg {String} sortable Specifies that the table should be sortable
5359 * @cfg {String} summary Specifies a summary of the content of a table
5360 * @cfg {Number} width Specifies the width of a table
5361 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5363 * @cfg {boolean} striped Should the rows be alternative striped
5364 * @cfg {boolean} bordered Add borders to the table
5365 * @cfg {boolean} hover Add hover highlighting
5366 * @cfg {boolean} condensed Format condensed
5367 * @cfg {boolean} responsive Format condensed
5368 * @cfg {Boolean} loadMask (true|false) default false
5369 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5370 * @cfg {Boolean} thead (true|false) generate thead, default true
5371 * @cfg {Boolean} RowSelection (true|false) default false
5372 * @cfg {Boolean} CellSelection (true|false) default false
5373 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5377 * Create a new Table
5378 * @param {Object} config The config object
5381 Roo.bootstrap.Table = function(config){
5382 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5385 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5386 this.sm = this.selModel;
5387 this.sm.xmodule = this.xmodule || false;
5389 if (this.cm && typeof(this.cm.config) == 'undefined') {
5390 this.colModel = new Roo.grid.ColumnModel(this.cm);
5391 this.cm = this.colModel;
5392 this.cm.xmodule = this.xmodule || false;
5395 this.store= Roo.factory(this.store, Roo.data);
5396 this.ds = this.store;
5397 this.ds.xmodule = this.xmodule || false;
5400 if (this.footer && this.store) {
5401 this.footer.dataSource = this.ds;
5402 this.footer = Roo.factory(this.footer);
5409 * Fires when a cell is clicked
5410 * @param {Roo.bootstrap.Table} this
5411 * @param {Roo.Element} el
5412 * @param {Number} rowIndex
5413 * @param {Number} columnIndex
5414 * @param {Roo.EventObject} e
5418 * @event celldblclick
5419 * Fires when a cell is double clicked
5420 * @param {Roo.bootstrap.Table} this
5421 * @param {Roo.Element} el
5422 * @param {Number} rowIndex
5423 * @param {Number} columnIndex
5424 * @param {Roo.EventObject} e
5426 "celldblclick" : true,
5429 * Fires when a row is clicked
5430 * @param {Roo.bootstrap.Table} this
5431 * @param {Roo.Element} el
5432 * @param {Number} rowIndex
5433 * @param {Roo.EventObject} e
5437 * @event rowdblclick
5438 * Fires when a row is double clicked
5439 * @param {Roo.bootstrap.Table} this
5440 * @param {Roo.Element} el
5441 * @param {Number} rowIndex
5442 * @param {Roo.EventObject} e
5444 "rowdblclick" : true,
5447 * Fires when a mouseover occur
5448 * @param {Roo.bootstrap.Table} this
5449 * @param {Roo.Element} el
5450 * @param {Number} rowIndex
5451 * @param {Number} columnIndex
5452 * @param {Roo.EventObject} e
5457 * Fires when a mouseout occur
5458 * @param {Roo.bootstrap.Table} this
5459 * @param {Roo.Element} el
5460 * @param {Number} rowIndex
5461 * @param {Number} columnIndex
5462 * @param {Roo.EventObject} e
5467 * Fires when a row is rendered, so you can change add a style to it.
5468 * @param {Roo.bootstrap.Table} this
5469 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5473 * @event rowsrendered
5474 * Fires when all the rows have been rendered
5475 * @param {Roo.bootstrap.Table} this
5477 'rowsrendered' : true
5482 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5506 RowSelection : false,
5507 CellSelection : false,
5510 // Roo.Element - the tbody
5513 getAutoCreate : function(){
5514 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5523 cfg.cls += ' table-striped';
5527 cfg.cls += ' table-hover';
5529 if (this.bordered) {
5530 cfg.cls += ' table-bordered';
5532 if (this.condensed) {
5533 cfg.cls += ' table-condensed';
5535 if (this.responsive) {
5536 cfg.cls += ' table-responsive';
5540 cfg.cls+= ' ' +this.cls;
5543 // this lot should be simplifed...
5546 cfg.align=this.align;
5549 cfg.bgcolor=this.bgcolor;
5552 cfg.border=this.border;
5554 if (this.cellpadding) {
5555 cfg.cellpadding=this.cellpadding;
5557 if (this.cellspacing) {
5558 cfg.cellspacing=this.cellspacing;
5561 cfg.frame=this.frame;
5564 cfg.rules=this.rules;
5566 if (this.sortable) {
5567 cfg.sortable=this.sortable;
5570 cfg.summary=this.summary;
5573 cfg.width=this.width;
5576 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5579 if(this.store || this.cm){
5581 cfg.cn.push(this.renderHeader());
5584 cfg.cn.push(this.renderBody());
5587 cfg.cn.push(this.renderFooter());
5590 cfg.cls+= ' TableGrid';
5593 return { cn : [ cfg ] };
5596 initEvents : function()
5598 if(!this.store || !this.cm){
5602 //Roo.log('initEvents with ds!!!!');
5604 this.mainBody = this.el.select('tbody', true).first();
5609 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5610 e.on('click', _this.sort, _this);
5613 this.el.on("click", this.onClick, this);
5614 this.el.on("dblclick", this.onDblClick, this);
5616 // why is this done????? = it breaks dialogs??
5617 //this.parent().el.setStyle('position', 'relative');
5621 this.footer.parentId = this.id;
5622 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5625 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5627 this.store.on('load', this.onLoad, this);
5628 this.store.on('beforeload', this.onBeforeLoad, this);
5629 this.store.on('update', this.onUpdate, this);
5630 this.store.on('add', this.onAdd, this);
5634 onMouseover : function(e, el)
5636 var cell = Roo.get(el);
5642 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5643 cell = cell.findParent('td', false, true);
5646 var row = cell.findParent('tr', false, true);
5647 var cellIndex = cell.dom.cellIndex;
5648 var rowIndex = row.dom.rowIndex - 1; // start from 0
5650 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5654 onMouseout : function(e, el)
5656 var cell = Roo.get(el);
5662 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5663 cell = cell.findParent('td', false, true);
5666 var row = cell.findParent('tr', false, true);
5667 var cellIndex = cell.dom.cellIndex;
5668 var rowIndex = row.dom.rowIndex - 1; // start from 0
5670 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5674 onClick : function(e, el)
5676 var cell = Roo.get(el);
5678 if(!cell || (!this.CellSelection && !this.RowSelection)){
5682 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5683 cell = cell.findParent('td', false, true);
5686 if(!cell || typeof(cell) == 'undefined'){
5690 var row = cell.findParent('tr', false, true);
5692 if(!row || typeof(row) == 'undefined'){
5696 var cellIndex = cell.dom.cellIndex;
5697 var rowIndex = this.getRowIndex(row);
5699 if(this.CellSelection){
5700 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5703 if(this.RowSelection){
5704 this.fireEvent('rowclick', this, row, rowIndex, e);
5710 onDblClick : function(e,el)
5712 var cell = Roo.get(el);
5714 if(!cell || (!this.CellSelection && !this.RowSelection)){
5718 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5719 cell = cell.findParent('td', false, true);
5722 if(!cell || typeof(cell) == 'undefined'){
5726 var row = cell.findParent('tr', false, true);
5728 if(!row || typeof(row) == 'undefined'){
5732 var cellIndex = cell.dom.cellIndex;
5733 var rowIndex = this.getRowIndex(row);
5735 if(this.CellSelection){
5736 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5739 if(this.RowSelection){
5740 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5744 sort : function(e,el)
5746 var col = Roo.get(el);
5748 if(!col.hasClass('sortable')){
5752 var sort = col.attr('sort');
5755 if(col.hasClass('glyphicon-arrow-up')){
5759 this.store.sortInfo = {field : sort, direction : dir};
5762 Roo.log("calling footer first");
5763 this.footer.onClick('first');
5766 this.store.load({ params : { start : 0 } });
5770 renderHeader : function()
5779 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5781 var config = cm.config[i];
5786 html: cm.getColumnHeader(i)
5789 if(typeof(config.tooltip) != 'undefined'){
5790 c.tooltip = config.tooltip;
5793 if(typeof(config.colspan) != 'undefined'){
5794 c.colspan = config.colspan;
5797 if(typeof(config.hidden) != 'undefined' && config.hidden){
5798 c.style += ' display:none;';
5801 if(typeof(config.dataIndex) != 'undefined'){
5802 c.sort = config.dataIndex;
5805 if(typeof(config.sortable) != 'undefined' && config.sortable){
5809 if(typeof(config.align) != 'undefined' && config.align.length){
5810 c.style += ' text-align:' + config.align + ';';
5813 if(typeof(config.width) != 'undefined'){
5814 c.style += ' width:' + config.width + 'px;';
5817 if(typeof(config.cls) != 'undefined'){
5818 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5827 renderBody : function()
5837 colspan : this.cm.getColumnCount()
5847 renderFooter : function()
5857 colspan : this.cm.getColumnCount()
5871 Roo.log('ds onload');
5876 var ds = this.store;
5878 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5879 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5881 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5882 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5885 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5886 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5890 var tbody = this.mainBody;
5892 if(ds.getCount() > 0){
5893 ds.data.each(function(d,rowIndex){
5894 var row = this.renderRow(cm, ds, rowIndex);
5896 tbody.createChild(row);
5900 if(row.cellObjects.length){
5901 Roo.each(row.cellObjects, function(r){
5902 _this.renderCellObject(r);
5909 Roo.each(this.el.select('tbody td', true).elements, function(e){
5910 e.on('mouseover', _this.onMouseover, _this);
5913 Roo.each(this.el.select('tbody td', true).elements, function(e){
5914 e.on('mouseout', _this.onMouseout, _this);
5916 this.fireEvent('rowsrendered', this);
5917 //if(this.loadMask){
5918 // this.maskEl.hide();
5923 onUpdate : function(ds,record)
5925 this.refreshRow(record);
5928 onRemove : function(ds, record, index, isUpdate){
5929 if(isUpdate !== true){
5930 this.fireEvent("beforerowremoved", this, index, record);
5932 var bt = this.mainBody.dom;
5934 var rows = this.el.select('tbody > tr', true).elements;
5936 if(typeof(rows[index]) != 'undefined'){
5937 bt.removeChild(rows[index].dom);
5940 // if(bt.rows[index]){
5941 // bt.removeChild(bt.rows[index]);
5944 if(isUpdate !== true){
5945 //this.stripeRows(index);
5946 //this.syncRowHeights(index, index);
5948 this.fireEvent("rowremoved", this, index, record);
5952 onAdd : function(ds, records, rowIndex)
5954 //Roo.log('on Add called');
5955 // - note this does not handle multiple adding very well..
5956 var bt = this.mainBody.dom;
5957 for (var i =0 ; i < records.length;i++) {
5958 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5959 //Roo.log(records[i]);
5960 //Roo.log(this.store.getAt(rowIndex+i));
5961 this.insertRow(this.store, rowIndex + i, false);
5968 refreshRow : function(record){
5969 var ds = this.store, index;
5970 if(typeof record == 'number'){
5972 record = ds.getAt(index);
5974 index = ds.indexOf(record);
5976 this.insertRow(ds, index, true);
5977 this.onRemove(ds, record, index+1, true);
5978 //this.syncRowHeights(index, index);
5980 this.fireEvent("rowupdated", this, index, record);
5983 insertRow : function(dm, rowIndex, isUpdate){
5986 this.fireEvent("beforerowsinserted", this, rowIndex);
5988 //var s = this.getScrollState();
5989 var row = this.renderRow(this.cm, this.store, rowIndex);
5990 // insert before rowIndex..
5991 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5995 if(row.cellObjects.length){
5996 Roo.each(row.cellObjects, function(r){
5997 _this.renderCellObject(r);
6002 this.fireEvent("rowsinserted", this, rowIndex);
6003 //this.syncRowHeights(firstRow, lastRow);
6004 //this.stripeRows(firstRow);
6011 getRowDom : function(rowIndex)
6013 var rows = this.el.select('tbody > tr', true).elements;
6015 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6018 // returns the object tree for a tr..
6021 renderRow : function(cm, ds, rowIndex)
6024 var d = ds.getAt(rowIndex);
6031 var cellObjects = [];
6033 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6034 var config = cm.config[i];
6036 var renderer = cm.getRenderer(i);
6040 if(typeof(renderer) !== 'undefined'){
6041 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6043 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6044 // and are rendered into the cells after the row is rendered - using the id for the element.
6046 if(typeof(value) === 'object'){
6056 rowIndex : rowIndex,
6061 this.fireEvent('rowclass', this, rowcfg);
6065 cls : rowcfg.rowClass,
6067 html: (typeof(value) === 'object') ? '' : value
6074 if(typeof(config.colspan) != 'undefined'){
6075 td.colspan = config.colspan;
6078 if(typeof(config.hidden) != 'undefined' && config.hidden){
6079 td.style += ' display:none;';
6082 if(typeof(config.align) != 'undefined' && config.align.length){
6083 td.style += ' text-align:' + config.align + ';';
6086 if(typeof(config.width) != 'undefined'){
6087 td.style += ' width:' + config.width + 'px;';
6090 if(typeof(config.cursor) != 'undefined'){
6091 td.style += ' cursor:' + config.cursor + ';';
6094 if(typeof(config.cls) != 'undefined'){
6095 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6102 row.cellObjects = cellObjects;
6110 onBeforeLoad : function()
6112 //Roo.log('ds onBeforeLoad');
6116 //if(this.loadMask){
6117 // this.maskEl.show();
6125 this.el.select('tbody', true).first().dom.innerHTML = '';
6128 * Show or hide a row.
6129 * @param {Number} rowIndex to show or hide
6130 * @param {Boolean} state hide
6132 setRowVisibility : function(rowIndex, state)
6134 var bt = this.mainBody.dom;
6136 var rows = this.el.select('tbody > tr', true).elements;
6138 if(typeof(rows[rowIndex]) == 'undefined'){
6141 rows[rowIndex].dom.style.display = state ? '' : 'none';
6145 getSelectionModel : function(){
6147 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6149 return this.selModel;
6152 * Render the Roo.bootstrap object from renderder
6154 renderCellObject : function(r)
6158 var t = r.cfg.render(r.container);
6161 Roo.each(r.cfg.cn, function(c){
6163 container: t.getChildContainer(),
6166 _this.renderCellObject(child);
6171 getRowIndex : function(row)
6175 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6198 * @class Roo.bootstrap.TableCell
6199 * @extends Roo.bootstrap.Component
6200 * Bootstrap TableCell class
6201 * @cfg {String} html cell contain text
6202 * @cfg {String} cls cell class
6203 * @cfg {String} tag cell tag (td|th) default td
6204 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6205 * @cfg {String} align Aligns the content in a cell
6206 * @cfg {String} axis Categorizes cells
6207 * @cfg {String} bgcolor Specifies the background color of a cell
6208 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6209 * @cfg {Number} colspan Specifies the number of columns a cell should span
6210 * @cfg {String} headers Specifies one or more header cells a cell is related to
6211 * @cfg {Number} height Sets the height of a cell
6212 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6213 * @cfg {Number} rowspan Sets the number of rows a cell should span
6214 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6215 * @cfg {String} valign Vertical aligns the content in a cell
6216 * @cfg {Number} width Specifies the width of a cell
6219 * Create a new TableCell
6220 * @param {Object} config The config object
6223 Roo.bootstrap.TableCell = function(config){
6224 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6227 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6247 getAutoCreate : function(){
6248 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6268 cfg.align=this.align
6274 cfg.bgcolor=this.bgcolor
6277 cfg.charoff=this.charoff
6280 cfg.colspan=this.colspan
6283 cfg.headers=this.headers
6286 cfg.height=this.height
6289 cfg.nowrap=this.nowrap
6292 cfg.rowspan=this.rowspan
6295 cfg.scope=this.scope
6298 cfg.valign=this.valign
6301 cfg.width=this.width
6320 * @class Roo.bootstrap.TableRow
6321 * @extends Roo.bootstrap.Component
6322 * Bootstrap TableRow class
6323 * @cfg {String} cls row class
6324 * @cfg {String} align Aligns the content in a table row
6325 * @cfg {String} bgcolor Specifies a background color for a table row
6326 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6327 * @cfg {String} valign Vertical aligns the content in a table row
6330 * Create a new TableRow
6331 * @param {Object} config The config object
6334 Roo.bootstrap.TableRow = function(config){
6335 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6338 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6346 getAutoCreate : function(){
6347 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6357 cfg.align = this.align;
6360 cfg.bgcolor = this.bgcolor;
6363 cfg.charoff = this.charoff;
6366 cfg.valign = this.valign;
6384 * @class Roo.bootstrap.TableBody
6385 * @extends Roo.bootstrap.Component
6386 * Bootstrap TableBody class
6387 * @cfg {String} cls element class
6388 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6389 * @cfg {String} align Aligns the content inside the element
6390 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6391 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6394 * Create a new TableBody
6395 * @param {Object} config The config object
6398 Roo.bootstrap.TableBody = function(config){
6399 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6402 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6410 getAutoCreate : function(){
6411 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6425 cfg.align = this.align;
6428 cfg.charoff = this.charoff;
6431 cfg.valign = this.valign;
6438 // initEvents : function()
6445 // this.store = Roo.factory(this.store, Roo.data);
6446 // this.store.on('load', this.onLoad, this);
6448 // this.store.load();
6452 // onLoad: function ()
6454 // this.fireEvent('load', this);
6464 * Ext JS Library 1.1.1
6465 * Copyright(c) 2006-2007, Ext JS, LLC.
6467 * Originally Released Under LGPL - original licence link has changed is not relivant.
6470 * <script type="text/javascript">
6473 // as we use this in bootstrap.
6474 Roo.namespace('Roo.form');
6476 * @class Roo.form.Action
6477 * Internal Class used to handle form actions
6479 * @param {Roo.form.BasicForm} el The form element or its id
6480 * @param {Object} config Configuration options
6485 // define the action interface
6486 Roo.form.Action = function(form, options){
6488 this.options = options || {};
6491 * Client Validation Failed
6494 Roo.form.Action.CLIENT_INVALID = 'client';
6496 * Server Validation Failed
6499 Roo.form.Action.SERVER_INVALID = 'server';
6501 * Connect to Server Failed
6504 Roo.form.Action.CONNECT_FAILURE = 'connect';
6506 * Reading Data from Server Failed
6509 Roo.form.Action.LOAD_FAILURE = 'load';
6511 Roo.form.Action.prototype = {
6513 failureType : undefined,
6514 response : undefined,
6518 run : function(options){
6523 success : function(response){
6528 handleResponse : function(response){
6532 // default connection failure
6533 failure : function(response){
6535 this.response = response;
6536 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6537 this.form.afterAction(this, false);
6540 processResponse : function(response){
6541 this.response = response;
6542 if(!response.responseText){
6545 this.result = this.handleResponse(response);
6549 // utility functions used internally
6550 getUrl : function(appendParams){
6551 var url = this.options.url || this.form.url || this.form.el.dom.action;
6553 var p = this.getParams();
6555 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6561 getMethod : function(){
6562 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6565 getParams : function(){
6566 var bp = this.form.baseParams;
6567 var p = this.options.params;
6569 if(typeof p == "object"){
6570 p = Roo.urlEncode(Roo.applyIf(p, bp));
6571 }else if(typeof p == 'string' && bp){
6572 p += '&' + Roo.urlEncode(bp);
6575 p = Roo.urlEncode(bp);
6580 createCallback : function(){
6582 success: this.success,
6583 failure: this.failure,
6585 timeout: (this.form.timeout*1000),
6586 upload: this.form.fileUpload ? this.success : undefined
6591 Roo.form.Action.Submit = function(form, options){
6592 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6595 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6598 haveProgress : false,
6599 uploadComplete : false,
6601 // uploadProgress indicator.
6602 uploadProgress : function()
6604 if (!this.form.progressUrl) {
6608 if (!this.haveProgress) {
6609 Roo.MessageBox.progress("Uploading", "Uploading");
6611 if (this.uploadComplete) {
6612 Roo.MessageBox.hide();
6616 this.haveProgress = true;
6618 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6620 var c = new Roo.data.Connection();
6622 url : this.form.progressUrl,
6627 success : function(req){
6628 //console.log(data);
6632 rdata = Roo.decode(req.responseText)
6634 Roo.log("Invalid data from server..");
6638 if (!rdata || !rdata.success) {
6640 Roo.MessageBox.alert(Roo.encode(rdata));
6643 var data = rdata.data;
6645 if (this.uploadComplete) {
6646 Roo.MessageBox.hide();
6651 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6652 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6655 this.uploadProgress.defer(2000,this);
6658 failure: function(data) {
6659 Roo.log('progress url failed ');
6670 // run get Values on the form, so it syncs any secondary forms.
6671 this.form.getValues();
6673 var o = this.options;
6674 var method = this.getMethod();
6675 var isPost = method == 'POST';
6676 if(o.clientValidation === false || this.form.isValid()){
6678 if (this.form.progressUrl) {
6679 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6680 (new Date() * 1) + '' + Math.random());
6685 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6686 form:this.form.el.dom,
6687 url:this.getUrl(!isPost),
6689 params:isPost ? this.getParams() : null,
6690 isUpload: this.form.fileUpload
6693 this.uploadProgress();
6695 }else if (o.clientValidation !== false){ // client validation failed
6696 this.failureType = Roo.form.Action.CLIENT_INVALID;
6697 this.form.afterAction(this, false);
6701 success : function(response)
6703 this.uploadComplete= true;
6704 if (this.haveProgress) {
6705 Roo.MessageBox.hide();
6709 var result = this.processResponse(response);
6710 if(result === true || result.success){
6711 this.form.afterAction(this, true);
6715 this.form.markInvalid(result.errors);
6716 this.failureType = Roo.form.Action.SERVER_INVALID;
6718 this.form.afterAction(this, false);
6720 failure : function(response)
6722 this.uploadComplete= true;
6723 if (this.haveProgress) {
6724 Roo.MessageBox.hide();
6727 this.response = response;
6728 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6729 this.form.afterAction(this, false);
6732 handleResponse : function(response){
6733 if(this.form.errorReader){
6734 var rs = this.form.errorReader.read(response);
6737 for(var i = 0, len = rs.records.length; i < len; i++) {
6738 var r = rs.records[i];
6742 if(errors.length < 1){
6746 success : rs.success,
6752 ret = Roo.decode(response.responseText);
6756 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6766 Roo.form.Action.Load = function(form, options){
6767 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6768 this.reader = this.form.reader;
6771 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6776 Roo.Ajax.request(Roo.apply(
6777 this.createCallback(), {
6778 method:this.getMethod(),
6779 url:this.getUrl(false),
6780 params:this.getParams()
6784 success : function(response){
6786 var result = this.processResponse(response);
6787 if(result === true || !result.success || !result.data){
6788 this.failureType = Roo.form.Action.LOAD_FAILURE;
6789 this.form.afterAction(this, false);
6792 this.form.clearInvalid();
6793 this.form.setValues(result.data);
6794 this.form.afterAction(this, true);
6797 handleResponse : function(response){
6798 if(this.form.reader){
6799 var rs = this.form.reader.read(response);
6800 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6802 success : rs.success,
6806 return Roo.decode(response.responseText);
6810 Roo.form.Action.ACTION_TYPES = {
6811 'load' : Roo.form.Action.Load,
6812 'submit' : Roo.form.Action.Submit
6821 * @class Roo.bootstrap.Form
6822 * @extends Roo.bootstrap.Component
6823 * Bootstrap Form class
6824 * @cfg {String} method GET | POST (default POST)
6825 * @cfg {String} labelAlign top | left (default top)
6826 * @cfg {String} align left | right - for navbars
6827 * @cfg {Boolean} loadMask load mask when submit (default true)
6832 * @param {Object} config The config object
6836 Roo.bootstrap.Form = function(config){
6837 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6840 * @event clientvalidation
6841 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6842 * @param {Form} this
6843 * @param {Boolean} valid true if the form has passed client-side validation
6845 clientvalidation: true,
6847 * @event beforeaction
6848 * Fires before any action is performed. Return false to cancel the action.
6849 * @param {Form} this
6850 * @param {Action} action The action to be performed
6854 * @event actionfailed
6855 * Fires when an action fails.
6856 * @param {Form} this
6857 * @param {Action} action The action that failed
6859 actionfailed : true,
6861 * @event actioncomplete
6862 * Fires when an action is completed.
6863 * @param {Form} this
6864 * @param {Action} action The action that completed
6866 actioncomplete : true
6871 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6874 * @cfg {String} method
6875 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6880 * The URL to use for form actions if one isn't supplied in the action options.
6883 * @cfg {Boolean} fileUpload
6884 * Set to true if this form is a file upload.
6888 * @cfg {Object} baseParams
6889 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6893 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6897 * @cfg {Sting} align (left|right) for navbar forms
6902 activeAction : null,
6905 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6906 * element by passing it or its id or mask the form itself by passing in true.
6909 waitMsgTarget : false,
6913 getAutoCreate : function(){
6917 method : this.method || 'POST',
6918 id : this.id || Roo.id(),
6921 if (this.parent().xtype.match(/^Nav/)) {
6922 cfg.cls = 'navbar-form navbar-' + this.align;
6926 if (this.labelAlign == 'left' ) {
6927 cfg.cls += ' form-horizontal';
6933 initEvents : function()
6935 this.el.on('submit', this.onSubmit, this);
6936 // this was added as random key presses on the form where triggering form submit.
6937 this.el.on('keypress', function(e) {
6938 if (e.getCharCode() != 13) {
6941 // we might need to allow it for textareas.. and some other items.
6942 // check e.getTarget().
6944 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6948 Roo.log("keypress blocked");
6956 onSubmit : function(e){
6961 * Returns true if client-side validation on the form is successful.
6964 isValid : function(){
6965 var items = this.getItems();
6967 items.each(function(f){
6976 * Returns true if any fields in this form have changed since their original load.
6979 isDirty : function(){
6981 var items = this.getItems();
6982 items.each(function(f){
6992 * Performs a predefined action (submit or load) or custom actions you define on this form.
6993 * @param {String} actionName The name of the action type
6994 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6995 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6996 * accept other config options):
6998 Property Type Description
6999 ---------------- --------------- ----------------------------------------------------------------------------------
7000 url String The url for the action (defaults to the form's url)
7001 method String The form method to use (defaults to the form's method, or POST if not defined)
7002 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7003 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7004 validate the form on the client (defaults to false)
7006 * @return {BasicForm} this
7008 doAction : function(action, options){
7009 if(typeof action == 'string'){
7010 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7012 if(this.fireEvent('beforeaction', this, action) !== false){
7013 this.beforeAction(action);
7014 action.run.defer(100, action);
7020 beforeAction : function(action){
7021 var o = action.options;
7024 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7026 // not really supported yet.. ??
7028 //if(this.waitMsgTarget === true){
7029 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7030 //}else if(this.waitMsgTarget){
7031 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7032 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7034 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7040 afterAction : function(action, success){
7041 this.activeAction = null;
7042 var o = action.options;
7044 //if(this.waitMsgTarget === true){
7046 //}else if(this.waitMsgTarget){
7047 // this.waitMsgTarget.unmask();
7049 // Roo.MessageBox.updateProgress(1);
7050 // Roo.MessageBox.hide();
7057 Roo.callback(o.success, o.scope, [this, action]);
7058 this.fireEvent('actioncomplete', this, action);
7062 // failure condition..
7063 // we have a scenario where updates need confirming.
7064 // eg. if a locking scenario exists..
7065 // we look for { errors : { needs_confirm : true }} in the response.
7067 (typeof(action.result) != 'undefined') &&
7068 (typeof(action.result.errors) != 'undefined') &&
7069 (typeof(action.result.errors.needs_confirm) != 'undefined')
7072 Roo.log("not supported yet");
7075 Roo.MessageBox.confirm(
7076 "Change requires confirmation",
7077 action.result.errorMsg,
7082 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7092 Roo.callback(o.failure, o.scope, [this, action]);
7093 // show an error message if no failed handler is set..
7094 if (!this.hasListener('actionfailed')) {
7095 Roo.log("need to add dialog support");
7097 Roo.MessageBox.alert("Error",
7098 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7099 action.result.errorMsg :
7100 "Saving Failed, please check your entries or try again"
7105 this.fireEvent('actionfailed', this, action);
7110 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7111 * @param {String} id The value to search for
7114 findField : function(id){
7115 var items = this.getItems();
7116 var field = items.get(id);
7118 items.each(function(f){
7119 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7126 return field || null;
7129 * Mark fields in this form invalid in bulk.
7130 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7131 * @return {BasicForm} this
7133 markInvalid : function(errors){
7134 if(errors instanceof Array){
7135 for(var i = 0, len = errors.length; i < len; i++){
7136 var fieldError = errors[i];
7137 var f = this.findField(fieldError.id);
7139 f.markInvalid(fieldError.msg);
7145 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7146 field.markInvalid(errors[id]);
7150 //Roo.each(this.childForms || [], function (f) {
7151 // f.markInvalid(errors);
7158 * Set values for fields in this form in bulk.
7159 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7160 * @return {BasicForm} this
7162 setValues : function(values){
7163 if(values instanceof Array){ // array of objects
7164 for(var i = 0, len = values.length; i < len; i++){
7166 var f = this.findField(v.id);
7168 f.setValue(v.value);
7169 if(this.trackResetOnLoad){
7170 f.originalValue = f.getValue();
7174 }else{ // object hash
7177 if(typeof values[id] != 'function' && (field = this.findField(id))){
7179 if (field.setFromData &&
7181 field.displayField &&
7182 // combos' with local stores can
7183 // be queried via setValue()
7184 // to set their value..
7185 (field.store && !field.store.isLocal)
7189 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7190 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7191 field.setFromData(sd);
7194 field.setValue(values[id]);
7198 if(this.trackResetOnLoad){
7199 field.originalValue = field.getValue();
7205 //Roo.each(this.childForms || [], function (f) {
7206 // f.setValues(values);
7213 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7214 * they are returned as an array.
7215 * @param {Boolean} asString
7218 getValues : function(asString){
7219 //if (this.childForms) {
7220 // copy values from the child forms
7221 // Roo.each(this.childForms, function (f) {
7222 // this.setValues(f.getValues());
7228 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7229 if(asString === true){
7232 return Roo.urlDecode(fs);
7236 * Returns the fields in this form as an object with key/value pairs.
7237 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7240 getFieldValues : function(with_hidden)
7242 var items = this.getItems();
7244 items.each(function(f){
7248 var v = f.getValue();
7249 if (f.inputType =='radio') {
7250 if (typeof(ret[f.getName()]) == 'undefined') {
7251 ret[f.getName()] = ''; // empty..
7254 if (!f.el.dom.checked) {
7262 // not sure if this supported any more..
7263 if ((typeof(v) == 'object') && f.getRawValue) {
7264 v = f.getRawValue() ; // dates..
7266 // combo boxes where name != hiddenName...
7267 if (f.name != f.getName()) {
7268 ret[f.name] = f.getRawValue();
7270 ret[f.getName()] = v;
7277 * Clears all invalid messages in this form.
7278 * @return {BasicForm} this
7280 clearInvalid : function(){
7281 var items = this.getItems();
7283 items.each(function(f){
7294 * @return {BasicForm} this
7297 var items = this.getItems();
7298 items.each(function(f){
7302 Roo.each(this.childForms || [], function (f) {
7309 getItems : function()
7311 var r=new Roo.util.MixedCollection(false, function(o){
7312 return o.id || (o.id = Roo.id());
7314 var iter = function(el) {
7321 Roo.each(el.items,function(e) {
7341 * Ext JS Library 1.1.1
7342 * Copyright(c) 2006-2007, Ext JS, LLC.
7344 * Originally Released Under LGPL - original licence link has changed is not relivant.
7347 * <script type="text/javascript">
7350 * @class Roo.form.VTypes
7351 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7354 Roo.form.VTypes = function(){
7355 // closure these in so they are only created once.
7356 var alpha = /^[a-zA-Z_]+$/;
7357 var alphanum = /^[a-zA-Z0-9_]+$/;
7358 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7359 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7361 // All these messages and functions are configurable
7364 * The function used to validate email addresses
7365 * @param {String} value The email address
7367 'email' : function(v){
7368 return email.test(v);
7371 * The error text to display when the email validation function returns false
7374 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7376 * The keystroke filter mask to be applied on email input
7379 'emailMask' : /[a-z0-9_\.\-@]/i,
7382 * The function used to validate URLs
7383 * @param {String} value The URL
7385 'url' : function(v){
7389 * The error text to display when the url validation function returns false
7392 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7395 * The function used to validate alpha values
7396 * @param {String} value The value
7398 'alpha' : function(v){
7399 return alpha.test(v);
7402 * The error text to display when the alpha validation function returns false
7405 'alphaText' : 'This field should only contain letters and _',
7407 * The keystroke filter mask to be applied on alpha input
7410 'alphaMask' : /[a-z_]/i,
7413 * The function used to validate alphanumeric values
7414 * @param {String} value The value
7416 'alphanum' : function(v){
7417 return alphanum.test(v);
7420 * The error text to display when the alphanumeric validation function returns false
7423 'alphanumText' : 'This field should only contain letters, numbers and _',
7425 * The keystroke filter mask to be applied on alphanumeric input
7428 'alphanumMask' : /[a-z0-9_]/i
7438 * @class Roo.bootstrap.Input
7439 * @extends Roo.bootstrap.Component
7440 * Bootstrap Input class
7441 * @cfg {Boolean} disabled is it disabled
7442 * @cfg {String} fieldLabel - the label associated
7443 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7444 * @cfg {String} name name of the input
7445 * @cfg {string} fieldLabel - the label associated
7446 * @cfg {string} inputType - input / file submit ...
7447 * @cfg {string} placeholder - placeholder to put in text.
7448 * @cfg {string} before - input group add on before
7449 * @cfg {string} after - input group add on after
7450 * @cfg {string} size - (lg|sm) or leave empty..
7451 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7452 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7453 * @cfg {Number} md colspan out of 12 for computer-sized screens
7454 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7455 * @cfg {string} value default value of the input
7456 * @cfg {Number} labelWidth set the width of label (0-12)
7457 * @cfg {String} labelAlign (top|left)
7458 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7459 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7461 * @cfg {String} align (left|center|right) Default left
7466 * Create a new Input
7467 * @param {Object} config The config object
7470 Roo.bootstrap.Input = function(config){
7471 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7476 * Fires when this field receives input focus.
7477 * @param {Roo.form.Field} this
7482 * Fires when this field loses input focus.
7483 * @param {Roo.form.Field} this
7488 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7489 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7490 * @param {Roo.form.Field} this
7491 * @param {Roo.EventObject} e The event object
7496 * Fires just before the field blurs if the field value has changed.
7497 * @param {Roo.form.Field} this
7498 * @param {Mixed} newValue The new value
7499 * @param {Mixed} oldValue The original value
7504 * Fires after the field has been marked as invalid.
7505 * @param {Roo.form.Field} this
7506 * @param {String} msg The validation message
7511 * Fires after the field has been validated with no errors.
7512 * @param {Roo.form.Field} this
7517 * Fires after the key up
7518 * @param {Roo.form.Field} this
7519 * @param {Roo.EventObject} e The event Object
7525 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7527 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7528 automatic validation (defaults to "keyup").
7530 validationEvent : "keyup",
7532 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7534 validateOnBlur : true,
7536 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7538 validationDelay : 250,
7540 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7542 focusClass : "x-form-focus", // not needed???
7546 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7548 invalidClass : "has-warning",
7551 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7553 validClass : "has-success",
7556 * @cfg {Boolean} hasFeedback (true|false) default true
7561 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7563 invalidFeedbackClass : "glyphicon-warning-sign",
7566 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7568 validFeedbackClass : "glyphicon-ok",
7571 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7573 selectOnFocus : false,
7576 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7580 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7585 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7587 disableKeyFilter : false,
7590 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7594 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7598 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7600 blankText : "This field is required",
7603 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7607 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7609 maxLength : Number.MAX_VALUE,
7611 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7613 minLengthText : "The minimum length for this field is {0}",
7615 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7617 maxLengthText : "The maximum length for this field is {0}",
7621 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7622 * If available, this function will be called only after the basic validators all return true, and will be passed the
7623 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7627 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7628 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7629 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7633 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7637 autocomplete: false,
7656 formatedValue : false,
7658 parentLabelAlign : function()
7661 while (parent.parent()) {
7662 parent = parent.parent();
7663 if (typeof(parent.labelAlign) !='undefined') {
7664 return parent.labelAlign;
7671 getAutoCreate : function(){
7673 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7679 if(this.inputType != 'hidden'){
7680 cfg.cls = 'form-group' //input-group
7686 type : this.inputType,
7688 cls : 'form-control',
7689 placeholder : this.placeholder || '',
7690 autocomplete : this.autocomplete || 'new-password'
7695 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7698 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7699 input.maxLength = this.maxLength;
7702 if (this.disabled) {
7703 input.disabled=true;
7706 if (this.readOnly) {
7707 input.readonly=true;
7711 input.name = this.name;
7714 input.cls += ' input-' + this.size;
7717 ['xs','sm','md','lg'].map(function(size){
7718 if (settings[size]) {
7719 cfg.cls += ' col-' + size + '-' + settings[size];
7723 var inputblock = input;
7727 cls: 'glyphicon form-control-feedback'
7730 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7733 cls : 'has-feedback',
7741 if (this.before || this.after) {
7744 cls : 'input-group',
7748 if (this.before && typeof(this.before) == 'string') {
7750 inputblock.cn.push({
7752 cls : 'roo-input-before input-group-addon',
7756 if (this.before && typeof(this.before) == 'object') {
7757 this.before = Roo.factory(this.before);
7758 Roo.log(this.before);
7759 inputblock.cn.push({
7761 cls : 'roo-input-before input-group-' +
7762 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7766 inputblock.cn.push(input);
7768 if (this.after && typeof(this.after) == 'string') {
7769 inputblock.cn.push({
7771 cls : 'roo-input-after input-group-addon',
7775 if (this.after && typeof(this.after) == 'object') {
7776 this.after = Roo.factory(this.after);
7777 Roo.log(this.after);
7778 inputblock.cn.push({
7780 cls : 'roo-input-after input-group-' +
7781 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7785 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7786 inputblock.cls += ' has-feedback';
7787 inputblock.cn.push(feedback);
7791 if (align ==='left' && this.fieldLabel.length) {
7792 Roo.log("left and has label");
7798 cls : 'control-label col-sm-' + this.labelWidth,
7799 html : this.fieldLabel
7803 cls : "col-sm-" + (12 - this.labelWidth),
7810 } else if ( this.fieldLabel.length) {
7816 //cls : 'input-group-addon',
7817 html : this.fieldLabel
7827 Roo.log(" no label && no align");
7836 Roo.log('input-parentType: ' + this.parentType);
7838 if (this.parentType === 'Navbar' && this.parent().bar) {
7839 cfg.cls += ' navbar-form';
7847 * return the real input element.
7849 inputEl: function ()
7851 return this.el.select('input.form-control',true).first();
7854 tooltipEl : function()
7856 return this.inputEl();
7859 setDisabled : function(v)
7861 var i = this.inputEl().dom;
7863 i.removeAttribute('disabled');
7867 i.setAttribute('disabled','true');
7869 initEvents : function()
7872 this.inputEl().on("keydown" , this.fireKey, this);
7873 this.inputEl().on("focus", this.onFocus, this);
7874 this.inputEl().on("blur", this.onBlur, this);
7876 this.inputEl().relayEvent('keyup', this);
7878 // reference to original value for reset
7879 this.originalValue = this.getValue();
7880 //Roo.form.TextField.superclass.initEvents.call(this);
7881 if(this.validationEvent == 'keyup'){
7882 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7883 this.inputEl().on('keyup', this.filterValidation, this);
7885 else if(this.validationEvent !== false){
7886 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7889 if(this.selectOnFocus){
7890 this.on("focus", this.preFocus, this);
7893 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7894 this.inputEl().on("keypress", this.filterKeys, this);
7897 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7898 this.el.on("click", this.autoSize, this);
7901 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7902 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7905 if (typeof(this.before) == 'object') {
7906 this.before.render(this.el.select('.roo-input-before',true).first());
7908 if (typeof(this.after) == 'object') {
7909 this.after.render(this.el.select('.roo-input-after',true).first());
7914 filterValidation : function(e){
7915 if(!e.isNavKeyPress()){
7916 this.validationTask.delay(this.validationDelay);
7920 * Validates the field value
7921 * @return {Boolean} True if the value is valid, else false
7923 validate : function(){
7924 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7925 if(this.disabled || this.validateValue(this.getRawValue())){
7936 * Validates a value according to the field's validation rules and marks the field as invalid
7937 * if the validation fails
7938 * @param {Mixed} value The value to validate
7939 * @return {Boolean} True if the value is valid, else false
7941 validateValue : function(value){
7942 if(value.length < 1) { // if it's blank
7943 if(this.allowBlank){
7949 if(value.length < this.minLength){
7952 if(value.length > this.maxLength){
7956 var vt = Roo.form.VTypes;
7957 if(!vt[this.vtype](value, this)){
7961 if(typeof this.validator == "function"){
7962 var msg = this.validator(value);
7968 if(this.regex && !this.regex.test(value)){
7978 fireKey : function(e){
7979 //Roo.log('field ' + e.getKey());
7980 if(e.isNavKeyPress()){
7981 this.fireEvent("specialkey", this, e);
7984 focus : function (selectText){
7986 this.inputEl().focus();
7987 if(selectText === true){
7988 this.inputEl().dom.select();
7994 onFocus : function(){
7995 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7996 // this.el.addClass(this.focusClass);
7999 this.hasFocus = true;
8000 this.startValue = this.getValue();
8001 this.fireEvent("focus", this);
8005 beforeBlur : Roo.emptyFn,
8009 onBlur : function(){
8011 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8012 //this.el.removeClass(this.focusClass);
8014 this.hasFocus = false;
8015 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8018 var v = this.getValue();
8019 if(String(v) !== String(this.startValue)){
8020 this.fireEvent('change', this, v, this.startValue);
8022 this.fireEvent("blur", this);
8026 * Resets the current field value to the originally loaded value and clears any validation messages
8029 this.setValue(this.originalValue);
8033 * Returns the name of the field
8034 * @return {Mixed} name The name field
8036 getName: function(){
8040 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8041 * @return {Mixed} value The field value
8043 getValue : function(){
8045 var v = this.inputEl().getValue();
8050 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8051 * @return {Mixed} value The field value
8053 getRawValue : function(){
8054 var v = this.inputEl().getValue();
8060 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8061 * @param {Mixed} value The value to set
8063 setRawValue : function(v){
8064 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8067 selectText : function(start, end){
8068 var v = this.getRawValue();
8070 start = start === undefined ? 0 : start;
8071 end = end === undefined ? v.length : end;
8072 var d = this.inputEl().dom;
8073 if(d.setSelectionRange){
8074 d.setSelectionRange(start, end);
8075 }else if(d.createTextRange){
8076 var range = d.createTextRange();
8077 range.moveStart("character", start);
8078 range.moveEnd("character", v.length-end);
8085 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8086 * @param {Mixed} value The value to set
8088 setValue : function(v){
8091 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8097 processValue : function(value){
8098 if(this.stripCharsRe){
8099 var newValue = value.replace(this.stripCharsRe, '');
8100 if(newValue !== value){
8101 this.setRawValue(newValue);
8108 preFocus : function(){
8110 if(this.selectOnFocus){
8111 this.inputEl().dom.select();
8114 filterKeys : function(e){
8116 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8119 var c = e.getCharCode(), cc = String.fromCharCode(c);
8120 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8123 if(!this.maskRe.test(cc)){
8128 * Clear any invalid styles/messages for this field
8130 clearInvalid : function(){
8132 if(!this.el || this.preventMark){ // not rendered
8135 this.el.removeClass(this.invalidClass);
8137 this.fireEvent('valid', this);
8141 * Mark this field as valid
8143 markValid : function(){
8144 if(!this.el || this.preventMark){ // not rendered
8148 this.el.removeClass([this.invalidClass, this.validClass]);
8150 if(this.disabled || this.allowBlank){
8154 this.el.addClass(this.validClass);
8156 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8158 var feedback = this.el.select('.form-control-feedback', true).first();
8161 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8162 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8167 this.fireEvent('valid', this);
8171 * Mark this field as invalid
8172 * @param {String} msg The validation message
8174 markInvalid : function(msg){
8175 if(!this.el || this.preventMark){ // not rendered
8179 this.el.removeClass([this.invalidClass, this.validClass]);
8181 if(this.disabled || this.allowBlank){
8185 this.el.addClass(this.invalidClass);
8187 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8189 var feedback = this.el.select('.form-control-feedback', true).first();
8192 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8194 if(this.getValue().length){
8195 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8202 this.fireEvent('invalid', this, msg);
8205 SafariOnKeyDown : function(event)
8207 // this is a workaround for a password hang bug on chrome/ webkit.
8209 var isSelectAll = false;
8211 if(this.inputEl().dom.selectionEnd > 0){
8212 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8214 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8215 event.preventDefault();
8220 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8222 event.preventDefault();
8223 // this is very hacky as keydown always get's upper case.
8225 var cc = String.fromCharCode(event.getCharCode());
8226 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8230 adjustWidth : function(tag, w){
8231 tag = tag.toLowerCase();
8232 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8233 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8237 if(tag == 'textarea'){
8240 }else if(Roo.isOpera){
8244 if(tag == 'textarea'){
8263 * @class Roo.bootstrap.TextArea
8264 * @extends Roo.bootstrap.Input
8265 * Bootstrap TextArea class
8266 * @cfg {Number} cols Specifies the visible width of a text area
8267 * @cfg {Number} rows Specifies the visible number of lines in a text area
8268 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8269 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8270 * @cfg {string} html text
8273 * Create a new TextArea
8274 * @param {Object} config The config object
8277 Roo.bootstrap.TextArea = function(config){
8278 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8282 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8292 getAutoCreate : function(){
8294 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8305 value : this.value || '',
8306 html: this.html || '',
8307 cls : 'form-control',
8308 placeholder : this.placeholder || ''
8312 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8313 input.maxLength = this.maxLength;
8317 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8321 input.cols = this.cols;
8324 if (this.readOnly) {
8325 input.readonly = true;
8329 input.name = this.name;
8333 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8337 ['xs','sm','md','lg'].map(function(size){
8338 if (settings[size]) {
8339 cfg.cls += ' col-' + size + '-' + settings[size];
8343 var inputblock = input;
8345 if(this.hasFeedback && !this.allowBlank){
8349 cls: 'glyphicon form-control-feedback'
8353 cls : 'has-feedback',
8362 if (this.before || this.after) {
8365 cls : 'input-group',
8369 inputblock.cn.push({
8371 cls : 'input-group-addon',
8376 inputblock.cn.push(input);
8378 if(this.hasFeedback && !this.allowBlank){
8379 inputblock.cls += ' has-feedback';
8380 inputblock.cn.push(feedback);
8384 inputblock.cn.push({
8386 cls : 'input-group-addon',
8393 if (align ==='left' && this.fieldLabel.length) {
8394 Roo.log("left and has label");
8400 cls : 'control-label col-sm-' + this.labelWidth,
8401 html : this.fieldLabel
8405 cls : "col-sm-" + (12 - this.labelWidth),
8412 } else if ( this.fieldLabel.length) {
8418 //cls : 'input-group-addon',
8419 html : this.fieldLabel
8429 Roo.log(" no label && no align");
8439 if (this.disabled) {
8440 input.disabled=true;
8447 * return the real textarea element.
8449 inputEl: function ()
8451 return this.el.select('textarea.form-control',true).first();
8459 * trigger field - base class for combo..
8464 * @class Roo.bootstrap.TriggerField
8465 * @extends Roo.bootstrap.Input
8466 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8467 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8468 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8469 * for which you can provide a custom implementation. For example:
8471 var trigger = new Roo.bootstrap.TriggerField();
8472 trigger.onTriggerClick = myTriggerFn;
8473 trigger.applyTo('my-field');
8476 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8477 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8478 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8479 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8480 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8483 * Create a new TriggerField.
8484 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8485 * to the base TextField)
8487 Roo.bootstrap.TriggerField = function(config){
8488 this.mimicing = false;
8489 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8492 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8494 * @cfg {String} triggerClass A CSS class to apply to the trigger
8497 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8502 * @cfg {Boolean} removable (true|false) special filter default false
8506 /** @cfg {Boolean} grow @hide */
8507 /** @cfg {Number} growMin @hide */
8508 /** @cfg {Number} growMax @hide */
8514 autoSize: Roo.emptyFn,
8521 actionMode : 'wrap',
8526 getAutoCreate : function(){
8528 var align = this.labelAlign || this.parentLabelAlign();
8533 cls: 'form-group' //input-group
8540 type : this.inputType,
8541 cls : 'form-control',
8542 autocomplete: 'new-password',
8543 placeholder : this.placeholder || ''
8547 input.name = this.name;
8550 input.cls += ' input-' + this.size;
8553 if (this.disabled) {
8554 input.disabled=true;
8557 var inputblock = input;
8559 if(this.hasFeedback && !this.allowBlank){
8563 cls: 'glyphicon form-control-feedback'
8566 if(this.removable && !this.editable && !this.tickable){
8568 cls : 'has-feedback',
8574 cls : 'roo-combo-removable-btn close'
8581 cls : 'has-feedback',
8590 if(this.removable && !this.editable && !this.tickable){
8592 cls : 'roo-removable',
8598 cls : 'roo-combo-removable-btn close'
8605 if (this.before || this.after) {
8608 cls : 'input-group',
8612 inputblock.cn.push({
8614 cls : 'input-group-addon',
8619 inputblock.cn.push(input);
8621 if(this.hasFeedback && !this.allowBlank){
8622 inputblock.cls += ' has-feedback';
8623 inputblock.cn.push(feedback);
8627 inputblock.cn.push({
8629 cls : 'input-group-addon',
8642 cls: 'form-hidden-field'
8650 Roo.log('multiple');
8658 cls: 'form-hidden-field'
8662 cls: 'select2-choices',
8666 cls: 'select2-search-field',
8679 cls: 'select2-container input-group',
8684 // cls: 'typeahead typeahead-long dropdown-menu',
8685 // style: 'display:none'
8690 if(!this.multiple && this.showToggleBtn){
8696 if (this.caret != false) {
8699 cls: 'fa fa-' + this.caret
8706 cls : 'input-group-addon btn dropdown-toggle',
8711 cls: 'combobox-clear',
8725 combobox.cls += ' select2-container-multi';
8728 if (align ==='left' && this.fieldLabel.length) {
8730 Roo.log("left and has label");
8736 cls : 'control-label col-sm-' + this.labelWidth,
8737 html : this.fieldLabel
8741 cls : "col-sm-" + (12 - this.labelWidth),
8748 } else if ( this.fieldLabel.length) {
8754 //cls : 'input-group-addon',
8755 html : this.fieldLabel
8765 Roo.log(" no label && no align");
8772 ['xs','sm','md','lg'].map(function(size){
8773 if (settings[size]) {
8774 cfg.cls += ' col-' + size + '-' + settings[size];
8785 onResize : function(w, h){
8786 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8787 // if(typeof w == 'number'){
8788 // var x = w - this.trigger.getWidth();
8789 // this.inputEl().setWidth(this.adjustWidth('input', x));
8790 // this.trigger.setStyle('left', x+'px');
8795 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8798 getResizeEl : function(){
8799 return this.inputEl();
8803 getPositionEl : function(){
8804 return this.inputEl();
8808 alignErrorIcon : function(){
8809 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8813 initEvents : function(){
8817 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8818 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8819 if(!this.multiple && this.showToggleBtn){
8820 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8821 if(this.hideTrigger){
8822 this.trigger.setDisplayed(false);
8824 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8828 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8831 if(this.removable && !this.editable && !this.tickable){
8832 var close = this.closeTriggerEl();
8835 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8836 close.on('click', this.removeBtnClick, this, close);
8840 //this.trigger.addClassOnOver('x-form-trigger-over');
8841 //this.trigger.addClassOnClick('x-form-trigger-click');
8844 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8848 closeTriggerEl : function()
8850 var close = this.el.select('.roo-combo-removable-btn', true).first();
8851 return close ? close : false;
8854 removeBtnClick : function(e, h, el)
8858 this.fireEvent("remove", this);
8861 createList : function()
8863 this.list = Roo.get(document.body).createChild({
8865 cls: 'typeahead typeahead-long dropdown-menu',
8866 style: 'display:none'
8869 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8874 initTrigger : function(){
8879 onDestroy : function(){
8881 this.trigger.removeAllListeners();
8882 // this.trigger.remove();
8885 // this.wrap.remove();
8887 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8891 onFocus : function(){
8892 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8895 this.wrap.addClass('x-trigger-wrap-focus');
8896 this.mimicing = true;
8897 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8898 if(this.monitorTab){
8899 this.el.on("keydown", this.checkTab, this);
8906 checkTab : function(e){
8907 if(e.getKey() == e.TAB){
8913 onBlur : function(){
8918 mimicBlur : function(e, t){
8920 if(!this.wrap.contains(t) && this.validateBlur()){
8927 triggerBlur : function(){
8928 this.mimicing = false;
8929 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8930 if(this.monitorTab){
8931 this.el.un("keydown", this.checkTab, this);
8933 //this.wrap.removeClass('x-trigger-wrap-focus');
8934 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8938 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8939 validateBlur : function(e, t){
8944 onDisable : function(){
8945 this.inputEl().dom.disabled = true;
8946 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8948 // this.wrap.addClass('x-item-disabled');
8953 onEnable : function(){
8954 this.inputEl().dom.disabled = false;
8955 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8957 // this.el.removeClass('x-item-disabled');
8962 onShow : function(){
8963 var ae = this.getActionEl();
8966 ae.dom.style.display = '';
8967 ae.dom.style.visibility = 'visible';
8973 onHide : function(){
8974 var ae = this.getActionEl();
8975 ae.dom.style.display = 'none';
8979 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8980 * by an implementing function.
8982 * @param {EventObject} e
8984 onTriggerClick : Roo.emptyFn
8988 * Ext JS Library 1.1.1
8989 * Copyright(c) 2006-2007, Ext JS, LLC.
8991 * Originally Released Under LGPL - original licence link has changed is not relivant.
8994 * <script type="text/javascript">
8999 * @class Roo.data.SortTypes
9001 * Defines the default sorting (casting?) comparison functions used when sorting data.
9003 Roo.data.SortTypes = {
9005 * Default sort that does nothing
9006 * @param {Mixed} s The value being converted
9007 * @return {Mixed} The comparison value
9014 * The regular expression used to strip tags
9018 stripTagsRE : /<\/?[^>]+>/gi,
9021 * Strips all HTML tags to sort on text only
9022 * @param {Mixed} s The value being converted
9023 * @return {String} The comparison value
9025 asText : function(s){
9026 return String(s).replace(this.stripTagsRE, "");
9030 * Strips all HTML tags to sort on text only - Case insensitive
9031 * @param {Mixed} s The value being converted
9032 * @return {String} The comparison value
9034 asUCText : function(s){
9035 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9039 * Case insensitive string
9040 * @param {Mixed} s The value being converted
9041 * @return {String} The comparison value
9043 asUCString : function(s) {
9044 return String(s).toUpperCase();
9049 * @param {Mixed} s The value being converted
9050 * @return {Number} The comparison value
9052 asDate : function(s) {
9056 if(s instanceof Date){
9059 return Date.parse(String(s));
9064 * @param {Mixed} s The value being converted
9065 * @return {Float} The comparison value
9067 asFloat : function(s) {
9068 var val = parseFloat(String(s).replace(/,/g, ""));
9069 if(isNaN(val)) val = 0;
9075 * @param {Mixed} s The value being converted
9076 * @return {Number} The comparison value
9078 asInt : function(s) {
9079 var val = parseInt(String(s).replace(/,/g, ""));
9080 if(isNaN(val)) val = 0;
9085 * Ext JS Library 1.1.1
9086 * Copyright(c) 2006-2007, Ext JS, LLC.
9088 * Originally Released Under LGPL - original licence link has changed is not relivant.
9091 * <script type="text/javascript">
9095 * @class Roo.data.Record
9096 * Instances of this class encapsulate both record <em>definition</em> information, and record
9097 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9098 * to access Records cached in an {@link Roo.data.Store} object.<br>
9100 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9101 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9104 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9106 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9107 * {@link #create}. The parameters are the same.
9108 * @param {Array} data An associative Array of data values keyed by the field name.
9109 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9110 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9111 * not specified an integer id is generated.
9113 Roo.data.Record = function(data, id){
9114 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9119 * Generate a constructor for a specific record layout.
9120 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9121 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9122 * Each field definition object may contain the following properties: <ul>
9123 * <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,
9124 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9125 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9126 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9127 * is being used, then this is a string containing the javascript expression to reference the data relative to
9128 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9129 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9130 * this may be omitted.</p></li>
9131 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9132 * <ul><li>auto (Default, implies no conversion)</li>
9137 * <li>date</li></ul></p></li>
9138 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9139 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9140 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9141 * by the Reader into an object that will be stored in the Record. It is passed the
9142 * following parameters:<ul>
9143 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9145 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9147 * <br>usage:<br><pre><code>
9148 var TopicRecord = Roo.data.Record.create(
9149 {name: 'title', mapping: 'topic_title'},
9150 {name: 'author', mapping: 'username'},
9151 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9152 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9153 {name: 'lastPoster', mapping: 'user2'},
9154 {name: 'excerpt', mapping: 'post_text'}
9157 var myNewRecord = new TopicRecord({
9158 title: 'Do my job please',
9161 lastPost: new Date(),
9162 lastPoster: 'Animal',
9163 excerpt: 'No way dude!'
9165 myStore.add(myNewRecord);
9170 Roo.data.Record.create = function(o){
9172 f.superclass.constructor.apply(this, arguments);
9174 Roo.extend(f, Roo.data.Record);
9175 var p = f.prototype;
9176 p.fields = new Roo.util.MixedCollection(false, function(field){
9179 for(var i = 0, len = o.length; i < len; i++){
9180 p.fields.add(new Roo.data.Field(o[i]));
9182 f.getField = function(name){
9183 return p.fields.get(name);
9188 Roo.data.Record.AUTO_ID = 1000;
9189 Roo.data.Record.EDIT = 'edit';
9190 Roo.data.Record.REJECT = 'reject';
9191 Roo.data.Record.COMMIT = 'commit';
9193 Roo.data.Record.prototype = {
9195 * Readonly flag - true if this record has been modified.
9204 join : function(store){
9209 * Set the named field to the specified value.
9210 * @param {String} name The name of the field to set.
9211 * @param {Object} value The value to set the field to.
9213 set : function(name, value){
9214 if(this.data[name] == value){
9221 if(typeof this.modified[name] == 'undefined'){
9222 this.modified[name] = this.data[name];
9224 this.data[name] = value;
9225 if(!this.editing && this.store){
9226 this.store.afterEdit(this);
9231 * Get the value of the named field.
9232 * @param {String} name The name of the field to get the value of.
9233 * @return {Object} The value of the field.
9235 get : function(name){
9236 return this.data[name];
9240 beginEdit : function(){
9241 this.editing = true;
9246 cancelEdit : function(){
9247 this.editing = false;
9248 delete this.modified;
9252 endEdit : function(){
9253 this.editing = false;
9254 if(this.dirty && this.store){
9255 this.store.afterEdit(this);
9260 * Usually called by the {@link Roo.data.Store} which owns the Record.
9261 * Rejects all changes made to the Record since either creation, or the last commit operation.
9262 * Modified fields are reverted to their original values.
9264 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9265 * of reject operations.
9267 reject : function(){
9268 var m = this.modified;
9270 if(typeof m[n] != "function"){
9271 this.data[n] = m[n];
9275 delete this.modified;
9276 this.editing = false;
9278 this.store.afterReject(this);
9283 * Usually called by the {@link Roo.data.Store} which owns the Record.
9284 * Commits all changes made to the Record since either creation, or the last commit operation.
9286 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9287 * of commit operations.
9289 commit : function(){
9291 delete this.modified;
9292 this.editing = false;
9294 this.store.afterCommit(this);
9299 hasError : function(){
9300 return this.error != null;
9304 clearError : function(){
9309 * Creates a copy of this record.
9310 * @param {String} id (optional) A new record id if you don't want to use this record's id
9313 copy : function(newId) {
9314 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9318 * Ext JS Library 1.1.1
9319 * Copyright(c) 2006-2007, Ext JS, LLC.
9321 * Originally Released Under LGPL - original licence link has changed is not relivant.
9324 * <script type="text/javascript">
9330 * @class Roo.data.Store
9331 * @extends Roo.util.Observable
9332 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9333 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9335 * 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
9336 * has no knowledge of the format of the data returned by the Proxy.<br>
9338 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9339 * instances from the data object. These records are cached and made available through accessor functions.
9341 * Creates a new Store.
9342 * @param {Object} config A config object containing the objects needed for the Store to access data,
9343 * and read the data into Records.
9345 Roo.data.Store = function(config){
9346 this.data = new Roo.util.MixedCollection(false);
9347 this.data.getKey = function(o){
9350 this.baseParams = {};
9357 "multisort" : "_multisort"
9360 if(config && config.data){
9361 this.inlineData = config.data;
9365 Roo.apply(this, config);
9367 if(this.reader){ // reader passed
9368 this.reader = Roo.factory(this.reader, Roo.data);
9369 this.reader.xmodule = this.xmodule || false;
9370 if(!this.recordType){
9371 this.recordType = this.reader.recordType;
9373 if(this.reader.onMetaChange){
9374 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9378 if(this.recordType){
9379 this.fields = this.recordType.prototype.fields;
9385 * @event datachanged
9386 * Fires when the data cache has changed, and a widget which is using this Store
9387 * as a Record cache should refresh its view.
9388 * @param {Store} this
9393 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9394 * @param {Store} this
9395 * @param {Object} meta The JSON metadata
9400 * Fires when Records have been added to the Store
9401 * @param {Store} this
9402 * @param {Roo.data.Record[]} records The array of Records added
9403 * @param {Number} index The index at which the record(s) were added
9408 * Fires when a Record has been removed from the Store
9409 * @param {Store} this
9410 * @param {Roo.data.Record} record The Record that was removed
9411 * @param {Number} index The index at which the record was removed
9416 * Fires when a Record has been updated
9417 * @param {Store} this
9418 * @param {Roo.data.Record} record The Record that was updated
9419 * @param {String} operation The update operation being performed. Value may be one of:
9421 Roo.data.Record.EDIT
9422 Roo.data.Record.REJECT
9423 Roo.data.Record.COMMIT
9429 * Fires when the data cache has been cleared.
9430 * @param {Store} this
9435 * Fires before a request is made for a new data object. If the beforeload handler returns false
9436 * the load action will be canceled.
9437 * @param {Store} this
9438 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9442 * @event beforeloadadd
9443 * Fires after a new set of Records has been loaded.
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)
9448 beforeloadadd : true,
9451 * Fires after a new set of Records has been loaded, before they are added to the store.
9452 * @param {Store} this
9453 * @param {Roo.data.Record[]} records The Records that were loaded
9454 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9455 * @params {Object} return from reader
9459 * @event loadexception
9460 * Fires if an exception occurs in the Proxy during loading.
9461 * Called with the signature of the Proxy's "loadexception" event.
9462 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9465 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9466 * @param {Object} load options
9467 * @param {Object} jsonData from your request (normally this contains the Exception)
9469 loadexception : true
9473 this.proxy = Roo.factory(this.proxy, Roo.data);
9474 this.proxy.xmodule = this.xmodule || false;
9475 this.relayEvents(this.proxy, ["loadexception"]);
9477 this.sortToggle = {};
9478 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9480 Roo.data.Store.superclass.constructor.call(this);
9482 if(this.inlineData){
9483 this.loadData(this.inlineData);
9484 delete this.inlineData;
9488 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9490 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9491 * without a remote query - used by combo/forms at present.
9495 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9498 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9501 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9502 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9505 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9506 * on any HTTP request
9509 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9512 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9516 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9517 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9522 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9523 * loaded or when a record is removed. (defaults to false).
9525 pruneModifiedRecords : false,
9531 * Add Records to the Store and fires the add event.
9532 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9534 add : function(records){
9535 records = [].concat(records);
9536 for(var i = 0, len = records.length; i < len; i++){
9537 records[i].join(this);
9539 var index = this.data.length;
9540 this.data.addAll(records);
9541 this.fireEvent("add", this, records, index);
9545 * Remove a Record from the Store and fires the remove event.
9546 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9548 remove : function(record){
9549 var index = this.data.indexOf(record);
9550 this.data.removeAt(index);
9551 if(this.pruneModifiedRecords){
9552 this.modified.remove(record);
9554 this.fireEvent("remove", this, record, index);
9558 * Remove all Records from the Store and fires the clear event.
9560 removeAll : function(){
9562 if(this.pruneModifiedRecords){
9565 this.fireEvent("clear", this);
9569 * Inserts Records to the Store at the given index and fires the add event.
9570 * @param {Number} index The start index at which to insert the passed Records.
9571 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9573 insert : function(index, records){
9574 records = [].concat(records);
9575 for(var i = 0, len = records.length; i < len; i++){
9576 this.data.insert(index, records[i]);
9577 records[i].join(this);
9579 this.fireEvent("add", this, records, index);
9583 * Get the index within the cache of the passed Record.
9584 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9585 * @return {Number} The index of the passed Record. Returns -1 if not found.
9587 indexOf : function(record){
9588 return this.data.indexOf(record);
9592 * Get the index within the cache of the Record with the passed id.
9593 * @param {String} id The id of the Record to find.
9594 * @return {Number} The index of the Record. Returns -1 if not found.
9596 indexOfId : function(id){
9597 return this.data.indexOfKey(id);
9601 * Get the Record with the specified id.
9602 * @param {String} id The id of the Record to find.
9603 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9605 getById : function(id){
9606 return this.data.key(id);
9610 * Get the Record at the specified index.
9611 * @param {Number} index The index of the Record to find.
9612 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9614 getAt : function(index){
9615 return this.data.itemAt(index);
9619 * Returns a range of Records between specified indices.
9620 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9621 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9622 * @return {Roo.data.Record[]} An array of Records
9624 getRange : function(start, end){
9625 return this.data.getRange(start, end);
9629 storeOptions : function(o){
9630 o = Roo.apply({}, o);
9633 this.lastOptions = o;
9637 * Loads the Record cache from the configured Proxy using the configured Reader.
9639 * If using remote paging, then the first load call must specify the <em>start</em>
9640 * and <em>limit</em> properties in the options.params property to establish the initial
9641 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9643 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9644 * and this call will return before the new data has been loaded. Perform any post-processing
9645 * in a callback function, or in a "load" event handler.</strong>
9647 * @param {Object} options An object containing properties which control loading options:<ul>
9648 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9649 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9650 * passed the following arguments:<ul>
9651 * <li>r : Roo.data.Record[]</li>
9652 * <li>options: Options object from the load call</li>
9653 * <li>success: Boolean success indicator</li></ul></li>
9654 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9655 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9658 load : function(options){
9659 options = options || {};
9660 if(this.fireEvent("beforeload", this, options) !== false){
9661 this.storeOptions(options);
9662 var p = Roo.apply(options.params || {}, this.baseParams);
9663 // if meta was not loaded from remote source.. try requesting it.
9664 if (!this.reader.metaFromRemote) {
9667 if(this.sortInfo && this.remoteSort){
9668 var pn = this.paramNames;
9669 p[pn["sort"]] = this.sortInfo.field;
9670 p[pn["dir"]] = this.sortInfo.direction;
9672 if (this.multiSort) {
9673 var pn = this.paramNames;
9674 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9677 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9682 * Reloads the Record cache from the configured Proxy using the configured Reader and
9683 * the options from the last load operation performed.
9684 * @param {Object} options (optional) An object containing properties which may override the options
9685 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9686 * the most recently used options are reused).
9688 reload : function(options){
9689 this.load(Roo.applyIf(options||{}, this.lastOptions));
9693 // Called as a callback by the Reader during a load operation.
9694 loadRecords : function(o, options, success){
9695 if(!o || success === false){
9696 if(success !== false){
9697 this.fireEvent("load", this, [], options, o);
9699 if(options.callback){
9700 options.callback.call(options.scope || this, [], options, false);
9704 // if data returned failure - throw an exception.
9705 if (o.success === false) {
9706 // show a message if no listener is registered.
9707 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9708 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9710 // loadmask wil be hooked into this..
9711 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9714 var r = o.records, t = o.totalRecords || r.length;
9716 this.fireEvent("beforeloadadd", this, r, options, o);
9718 if(!options || options.add !== true){
9719 if(this.pruneModifiedRecords){
9722 for(var i = 0, len = r.length; i < len; i++){
9726 this.data = this.snapshot;
9727 delete this.snapshot;
9730 this.data.addAll(r);
9731 this.totalLength = t;
9733 this.fireEvent("datachanged", this);
9735 this.totalLength = Math.max(t, this.data.length+r.length);
9738 this.fireEvent("load", this, r, options, o);
9739 if(options.callback){
9740 options.callback.call(options.scope || this, r, options, true);
9746 * Loads data from a passed data block. A Reader which understands the format of the data
9747 * must have been configured in the constructor.
9748 * @param {Object} data The data block from which to read the Records. The format of the data expected
9749 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9750 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9752 loadData : function(o, append){
9753 var r = this.reader.readRecords(o);
9754 this.loadRecords(r, {add: append}, true);
9758 * Gets the number of cached records.
9760 * <em>If using paging, this may not be the total size of the dataset. If the data object
9761 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9762 * the data set size</em>
9764 getCount : function(){
9765 return this.data.length || 0;
9769 * Gets the total number of records in the dataset as returned by the server.
9771 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9772 * the dataset size</em>
9774 getTotalCount : function(){
9775 return this.totalLength || 0;
9779 * Returns the sort state of the Store as an object with two properties:
9781 field {String} The name of the field by which the Records are sorted
9782 direction {String} The sort order, "ASC" or "DESC"
9785 getSortState : function(){
9786 return this.sortInfo;
9790 applySort : function(){
9791 if(this.sortInfo && !this.remoteSort){
9792 var s = this.sortInfo, f = s.field;
9793 var st = this.fields.get(f).sortType;
9794 var fn = function(r1, r2){
9795 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9796 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9798 this.data.sort(s.direction, fn);
9799 if(this.snapshot && this.snapshot != this.data){
9800 this.snapshot.sort(s.direction, fn);
9806 * Sets the default sort column and order to be used by the next load operation.
9807 * @param {String} fieldName The name of the field to sort by.
9808 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9810 setDefaultSort : function(field, dir){
9811 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9816 * If remote sorting is used, the sort is performed on the server, and the cache is
9817 * reloaded. If local sorting is used, the cache is sorted internally.
9818 * @param {String} fieldName The name of the field to sort by.
9819 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9821 sort : function(fieldName, dir){
9822 var f = this.fields.get(fieldName);
9824 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9826 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9827 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9832 this.sortToggle[f.name] = dir;
9833 this.sortInfo = {field: f.name, direction: dir};
9834 if(!this.remoteSort){
9836 this.fireEvent("datachanged", this);
9838 this.load(this.lastOptions);
9843 * Calls the specified function for each of the Records in the cache.
9844 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9845 * Returning <em>false</em> aborts and exits the iteration.
9846 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9848 each : function(fn, scope){
9849 this.data.each(fn, scope);
9853 * Gets all records modified since the last commit. Modified records are persisted across load operations
9854 * (e.g., during paging).
9855 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9857 getModifiedRecords : function(){
9858 return this.modified;
9862 createFilterFn : function(property, value, anyMatch){
9863 if(!value.exec){ // not a regex
9864 value = String(value);
9865 if(value.length == 0){
9868 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9871 return value.test(r.data[property]);
9876 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9877 * @param {String} property A field on your records
9878 * @param {Number} start The record index to start at (defaults to 0)
9879 * @param {Number} end The last record index to include (defaults to length - 1)
9880 * @return {Number} The sum
9882 sum : function(property, start, end){
9883 var rs = this.data.items, v = 0;
9885 end = (end || end === 0) ? end : rs.length-1;
9887 for(var i = start; i <= end; i++){
9888 v += (rs[i].data[property] || 0);
9894 * Filter the records by a specified property.
9895 * @param {String} field A field on your records
9896 * @param {String/RegExp} value Either a string that the field
9897 * should start with or a RegExp to test against the field
9898 * @param {Boolean} anyMatch True to match any part not just the beginning
9900 filter : function(property, value, anyMatch){
9901 var fn = this.createFilterFn(property, value, anyMatch);
9902 return fn ? this.filterBy(fn) : this.clearFilter();
9906 * Filter by a function. The specified function will be called with each
9907 * record in this data source. If the function returns true the record is included,
9908 * otherwise it is filtered.
9909 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9910 * @param {Object} scope (optional) The scope of the function (defaults to this)
9912 filterBy : function(fn, scope){
9913 this.snapshot = this.snapshot || this.data;
9914 this.data = this.queryBy(fn, scope||this);
9915 this.fireEvent("datachanged", this);
9919 * Query the records by a specified property.
9920 * @param {String} field A field on your records
9921 * @param {String/RegExp} value Either a string that the field
9922 * should start with or a RegExp to test against the field
9923 * @param {Boolean} anyMatch True to match any part not just the beginning
9924 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9926 query : function(property, value, anyMatch){
9927 var fn = this.createFilterFn(property, value, anyMatch);
9928 return fn ? this.queryBy(fn) : this.data.clone();
9932 * Query by a function. The specified function will be called with each
9933 * record in this data source. If the function returns true the record is included
9935 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9936 * @param {Object} scope (optional) The scope of the function (defaults to this)
9937 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9939 queryBy : function(fn, scope){
9940 var data = this.snapshot || this.data;
9941 return data.filterBy(fn, scope||this);
9945 * Collects unique values for a particular dataIndex from this store.
9946 * @param {String} dataIndex The property to collect
9947 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9948 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9949 * @return {Array} An array of the unique values
9951 collect : function(dataIndex, allowNull, bypassFilter){
9952 var d = (bypassFilter === true && this.snapshot) ?
9953 this.snapshot.items : this.data.items;
9954 var v, sv, r = [], l = {};
9955 for(var i = 0, len = d.length; i < len; i++){
9956 v = d[i].data[dataIndex];
9958 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9967 * Revert to a view of the Record cache with no filtering applied.
9968 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9970 clearFilter : function(suppressEvent){
9971 if(this.snapshot && this.snapshot != this.data){
9972 this.data = this.snapshot;
9973 delete this.snapshot;
9974 if(suppressEvent !== true){
9975 this.fireEvent("datachanged", this);
9981 afterEdit : function(record){
9982 if(this.modified.indexOf(record) == -1){
9983 this.modified.push(record);
9985 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9989 afterReject : function(record){
9990 this.modified.remove(record);
9991 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9995 afterCommit : function(record){
9996 this.modified.remove(record);
9997 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10001 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10002 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10004 commitChanges : function(){
10005 var m = this.modified.slice(0);
10006 this.modified = [];
10007 for(var i = 0, len = m.length; i < len; i++){
10013 * Cancel outstanding changes on all changed records.
10015 rejectChanges : function(){
10016 var m = this.modified.slice(0);
10017 this.modified = [];
10018 for(var i = 0, len = m.length; i < len; i++){
10023 onMetaChange : function(meta, rtype, o){
10024 this.recordType = rtype;
10025 this.fields = rtype.prototype.fields;
10026 delete this.snapshot;
10027 this.sortInfo = meta.sortInfo || this.sortInfo;
10028 this.modified = [];
10029 this.fireEvent('metachange', this, this.reader.meta);
10032 moveIndex : function(data, type)
10034 var index = this.indexOf(data);
10036 var newIndex = index + type;
10040 this.insert(newIndex, data);
10045 * Ext JS Library 1.1.1
10046 * Copyright(c) 2006-2007, Ext JS, LLC.
10048 * Originally Released Under LGPL - original licence link has changed is not relivant.
10051 * <script type="text/javascript">
10055 * @class Roo.data.SimpleStore
10056 * @extends Roo.data.Store
10057 * Small helper class to make creating Stores from Array data easier.
10058 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10059 * @cfg {Array} fields An array of field definition objects, or field name strings.
10060 * @cfg {Array} data The multi-dimensional array of data
10062 * @param {Object} config
10064 Roo.data.SimpleStore = function(config){
10065 Roo.data.SimpleStore.superclass.constructor.call(this, {
10067 reader: new Roo.data.ArrayReader({
10070 Roo.data.Record.create(config.fields)
10072 proxy : new Roo.data.MemoryProxy(config.data)
10076 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10078 * Ext JS Library 1.1.1
10079 * Copyright(c) 2006-2007, Ext JS, LLC.
10081 * Originally Released Under LGPL - original licence link has changed is not relivant.
10084 * <script type="text/javascript">
10089 * @extends Roo.data.Store
10090 * @class Roo.data.JsonStore
10091 * Small helper class to make creating Stores for JSON data easier. <br/>
10093 var store = new Roo.data.JsonStore({
10094 url: 'get-images.php',
10096 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10099 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10100 * JsonReader and HttpProxy (unless inline data is provided).</b>
10101 * @cfg {Array} fields An array of field definition objects, or field name strings.
10103 * @param {Object} config
10105 Roo.data.JsonStore = function(c){
10106 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10107 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10108 reader: new Roo.data.JsonReader(c, c.fields)
10111 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10113 * Ext JS Library 1.1.1
10114 * Copyright(c) 2006-2007, Ext JS, LLC.
10116 * Originally Released Under LGPL - original licence link has changed is not relivant.
10119 * <script type="text/javascript">
10123 Roo.data.Field = function(config){
10124 if(typeof config == "string"){
10125 config = {name: config};
10127 Roo.apply(this, config);
10130 this.type = "auto";
10133 var st = Roo.data.SortTypes;
10134 // named sortTypes are supported, here we look them up
10135 if(typeof this.sortType == "string"){
10136 this.sortType = st[this.sortType];
10139 // set default sortType for strings and dates
10140 if(!this.sortType){
10143 this.sortType = st.asUCString;
10146 this.sortType = st.asDate;
10149 this.sortType = st.none;
10154 var stripRe = /[\$,%]/g;
10156 // prebuilt conversion function for this field, instead of
10157 // switching every time we're reading a value
10159 var cv, dateFormat = this.dateFormat;
10164 cv = function(v){ return v; };
10167 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10171 return v !== undefined && v !== null && v !== '' ?
10172 parseInt(String(v).replace(stripRe, ""), 10) : '';
10177 return v !== undefined && v !== null && v !== '' ?
10178 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10183 cv = function(v){ return v === true || v === "true" || v == 1; };
10190 if(v instanceof Date){
10194 if(dateFormat == "timestamp"){
10195 return new Date(v*1000);
10197 return Date.parseDate(v, dateFormat);
10199 var parsed = Date.parse(v);
10200 return parsed ? new Date(parsed) : null;
10209 Roo.data.Field.prototype = {
10217 * Ext JS Library 1.1.1
10218 * Copyright(c) 2006-2007, Ext JS, LLC.
10220 * Originally Released Under LGPL - original licence link has changed is not relivant.
10223 * <script type="text/javascript">
10226 // Base class for reading structured data from a data source. This class is intended to be
10227 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10230 * @class Roo.data.DataReader
10231 * Base class for reading structured data from a data source. This class is intended to be
10232 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10235 Roo.data.DataReader = function(meta, recordType){
10239 this.recordType = recordType instanceof Array ?
10240 Roo.data.Record.create(recordType) : recordType;
10243 Roo.data.DataReader.prototype = {
10245 * Create an empty record
10246 * @param {Object} data (optional) - overlay some values
10247 * @return {Roo.data.Record} record created.
10249 newRow : function(d) {
10251 this.recordType.prototype.fields.each(function(c) {
10253 case 'int' : da[c.name] = 0; break;
10254 case 'date' : da[c.name] = new Date(); break;
10255 case 'float' : da[c.name] = 0.0; break;
10256 case 'boolean' : da[c.name] = false; break;
10257 default : da[c.name] = ""; break;
10261 return new this.recordType(Roo.apply(da, d));
10266 * Ext JS Library 1.1.1
10267 * Copyright(c) 2006-2007, Ext JS, LLC.
10269 * Originally Released Under LGPL - original licence link has changed is not relivant.
10272 * <script type="text/javascript">
10276 * @class Roo.data.DataProxy
10277 * @extends Roo.data.Observable
10278 * This class is an abstract base class for implementations which provide retrieval of
10279 * unformatted data objects.<br>
10281 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10282 * (of the appropriate type which knows how to parse the data object) to provide a block of
10283 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10285 * Custom implementations must implement the load method as described in
10286 * {@link Roo.data.HttpProxy#load}.
10288 Roo.data.DataProxy = function(){
10291 * @event beforeload
10292 * Fires before a network request is made to retrieve a data object.
10293 * @param {Object} This DataProxy object.
10294 * @param {Object} params The params parameter to the load function.
10299 * Fires before the load method's callback is called.
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.
10306 * @event loadexception
10307 * Fires if an Exception occurs during data retrieval.
10308 * @param {Object} This DataProxy object.
10309 * @param {Object} o The data object.
10310 * @param {Object} arg The callback argument object passed to the load function.
10311 * @param {Object} e The Exception.
10313 loadexception : true
10315 Roo.data.DataProxy.superclass.constructor.call(this);
10318 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10321 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10325 * Ext JS Library 1.1.1
10326 * Copyright(c) 2006-2007, Ext JS, LLC.
10328 * Originally Released Under LGPL - original licence link has changed is not relivant.
10331 * <script type="text/javascript">
10334 * @class Roo.data.MemoryProxy
10335 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10336 * to the Reader when its load method is called.
10338 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10340 Roo.data.MemoryProxy = function(data){
10344 Roo.data.MemoryProxy.superclass.constructor.call(this);
10348 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10350 * Load data from the requested source (in this case an in-memory
10351 * data object passed to the constructor), read the data object into
10352 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10353 * process that block using the passed callback.
10354 * @param {Object} params This parameter is not used by the MemoryProxy class.
10355 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10356 * object into a block of Roo.data.Records.
10357 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10358 * The function must be passed <ul>
10359 * <li>The Record block object</li>
10360 * <li>The "arg" argument from the load function</li>
10361 * <li>A boolean success indicator</li>
10363 * @param {Object} scope The scope in which to call the callback
10364 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10366 load : function(params, reader, callback, scope, arg){
10367 params = params || {};
10370 result = reader.readRecords(this.data);
10372 this.fireEvent("loadexception", this, arg, null, e);
10373 callback.call(scope, null, arg, false);
10376 callback.call(scope, result, arg, true);
10380 update : function(params, records){
10385 * Ext JS Library 1.1.1
10386 * Copyright(c) 2006-2007, Ext JS, LLC.
10388 * Originally Released Under LGPL - original licence link has changed is not relivant.
10391 * <script type="text/javascript">
10394 * @class Roo.data.HttpProxy
10395 * @extends Roo.data.DataProxy
10396 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10397 * configured to reference a certain URL.<br><br>
10399 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10400 * from which the running page was served.<br><br>
10402 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10404 * Be aware that to enable the browser to parse an XML document, the server must set
10405 * the Content-Type header in the HTTP response to "text/xml".
10407 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10408 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10409 * will be used to make the request.
10411 Roo.data.HttpProxy = function(conn){
10412 Roo.data.HttpProxy.superclass.constructor.call(this);
10413 // is conn a conn config or a real conn?
10415 this.useAjax = !conn || !conn.events;
10419 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10420 // thse are take from connection...
10423 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10426 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10427 * extra parameters to each request made by this object. (defaults to undefined)
10430 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10431 * to each request made by this object. (defaults to undefined)
10434 * @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)
10437 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10440 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10446 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10450 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10451 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10452 * a finer-grained basis than the DataProxy events.
10454 getConnection : function(){
10455 return this.useAjax ? Roo.Ajax : this.conn;
10459 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10460 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10461 * process that block using the passed callback.
10462 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10463 * for the request to the remote server.
10464 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10465 * object into a block of Roo.data.Records.
10466 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10467 * The function must be passed <ul>
10468 * <li>The Record block object</li>
10469 * <li>The "arg" argument from the load function</li>
10470 * <li>A boolean success indicator</li>
10472 * @param {Object} scope The scope in which to call the callback
10473 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10475 load : function(params, reader, callback, scope, arg){
10476 if(this.fireEvent("beforeload", this, params) !== false){
10478 params : params || {},
10480 callback : callback,
10485 callback : this.loadResponse,
10489 Roo.applyIf(o, this.conn);
10490 if(this.activeRequest){
10491 Roo.Ajax.abort(this.activeRequest);
10493 this.activeRequest = Roo.Ajax.request(o);
10495 this.conn.request(o);
10498 callback.call(scope||this, null, arg, false);
10503 loadResponse : function(o, success, response){
10504 delete this.activeRequest;
10506 this.fireEvent("loadexception", this, o, response);
10507 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10512 result = o.reader.read(response);
10514 this.fireEvent("loadexception", this, o, response, e);
10515 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10519 this.fireEvent("load", this, o, o.request.arg);
10520 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10524 update : function(dataSet){
10529 updateResponse : function(dataSet){
10534 * Ext JS Library 1.1.1
10535 * Copyright(c) 2006-2007, Ext JS, LLC.
10537 * Originally Released Under LGPL - original licence link has changed is not relivant.
10540 * <script type="text/javascript">
10544 * @class Roo.data.ScriptTagProxy
10545 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10546 * other than the originating domain of the running page.<br><br>
10548 * <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
10549 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10551 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10552 * source code that is used as the source inside a <script> tag.<br><br>
10554 * In order for the browser to process the returned data, the server must wrap the data object
10555 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10556 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10557 * depending on whether the callback name was passed:
10560 boolean scriptTag = false;
10561 String cb = request.getParameter("callback");
10564 response.setContentType("text/javascript");
10566 response.setContentType("application/x-json");
10568 Writer out = response.getWriter();
10570 out.write(cb + "(");
10572 out.print(dataBlock.toJsonString());
10579 * @param {Object} config A configuration object.
10581 Roo.data.ScriptTagProxy = function(config){
10582 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10583 Roo.apply(this, config);
10584 this.head = document.getElementsByTagName("head")[0];
10587 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10589 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10591 * @cfg {String} url The URL from which to request the data object.
10594 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10598 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10599 * the server the name of the callback function set up by the load call to process the returned data object.
10600 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10601 * javascript output which calls this named function passing the data object as its only parameter.
10603 callbackParam : "callback",
10605 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10606 * name to the request.
10611 * Load data from the configured URL, read the data object into
10612 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10613 * process that block using the passed callback.
10614 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10615 * for the request to the remote server.
10616 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10617 * object into a block of Roo.data.Records.
10618 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10619 * The function must be passed <ul>
10620 * <li>The Record block object</li>
10621 * <li>The "arg" argument from the load function</li>
10622 * <li>A boolean success indicator</li>
10624 * @param {Object} scope The scope in which to call the callback
10625 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10627 load : function(params, reader, callback, scope, arg){
10628 if(this.fireEvent("beforeload", this, params) !== false){
10630 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10632 var url = this.url;
10633 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10635 url += "&_dc=" + (new Date().getTime());
10637 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10640 cb : "stcCallback"+transId,
10641 scriptId : "stcScript"+transId,
10645 callback : callback,
10651 window[trans.cb] = function(o){
10652 conn.handleResponse(o, trans);
10655 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10657 if(this.autoAbort !== false){
10661 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10663 var script = document.createElement("script");
10664 script.setAttribute("src", url);
10665 script.setAttribute("type", "text/javascript");
10666 script.setAttribute("id", trans.scriptId);
10667 this.head.appendChild(script);
10669 this.trans = trans;
10671 callback.call(scope||this, null, arg, false);
10676 isLoading : function(){
10677 return this.trans ? true : false;
10681 * Abort the current server request.
10683 abort : function(){
10684 if(this.isLoading()){
10685 this.destroyTrans(this.trans);
10690 destroyTrans : function(trans, isLoaded){
10691 this.head.removeChild(document.getElementById(trans.scriptId));
10692 clearTimeout(trans.timeoutId);
10694 window[trans.cb] = undefined;
10696 delete window[trans.cb];
10699 // if hasn't been loaded, wait for load to remove it to prevent script error
10700 window[trans.cb] = function(){
10701 window[trans.cb] = undefined;
10703 delete window[trans.cb];
10710 handleResponse : function(o, trans){
10711 this.trans = false;
10712 this.destroyTrans(trans, true);
10715 result = trans.reader.readRecords(o);
10717 this.fireEvent("loadexception", this, o, trans.arg, e);
10718 trans.callback.call(trans.scope||window, null, trans.arg, false);
10721 this.fireEvent("load", this, o, trans.arg);
10722 trans.callback.call(trans.scope||window, result, trans.arg, true);
10726 handleFailure : function(trans){
10727 this.trans = false;
10728 this.destroyTrans(trans, false);
10729 this.fireEvent("loadexception", this, null, trans.arg);
10730 trans.callback.call(trans.scope||window, null, trans.arg, false);
10734 * Ext JS Library 1.1.1
10735 * Copyright(c) 2006-2007, Ext JS, LLC.
10737 * Originally Released Under LGPL - original licence link has changed is not relivant.
10740 * <script type="text/javascript">
10744 * @class Roo.data.JsonReader
10745 * @extends Roo.data.DataReader
10746 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10747 * based on mappings in a provided Roo.data.Record constructor.
10749 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10750 * in the reply previously.
10755 var RecordDef = Roo.data.Record.create([
10756 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10757 {name: 'occupation'} // This field will use "occupation" as the mapping.
10759 var myReader = new Roo.data.JsonReader({
10760 totalProperty: "results", // The property which contains the total dataset size (optional)
10761 root: "rows", // The property which contains an Array of row objects
10762 id: "id" // The property within each row object that provides an ID for the record (optional)
10766 * This would consume a JSON file like this:
10768 { 'results': 2, 'rows': [
10769 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10770 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10773 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10774 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10775 * paged from the remote server.
10776 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10777 * @cfg {String} root name of the property which contains the Array of row objects.
10778 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10779 * @cfg {Array} fields Array of field definition objects
10781 * Create a new JsonReader
10782 * @param {Object} meta Metadata configuration options
10783 * @param {Object} recordType Either an Array of field definition objects,
10784 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10786 Roo.data.JsonReader = function(meta, recordType){
10789 // set some defaults:
10790 Roo.applyIf(meta, {
10791 totalProperty: 'total',
10792 successProperty : 'success',
10797 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10799 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10802 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10803 * Used by Store query builder to append _requestMeta to params.
10806 metaFromRemote : false,
10808 * This method is only used by a DataProxy which has retrieved data from a remote server.
10809 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10810 * @return {Object} data A data block which is used by an Roo.data.Store object as
10811 * a cache of Roo.data.Records.
10813 read : function(response){
10814 var json = response.responseText;
10816 var o = /* eval:var:o */ eval("("+json+")");
10818 throw {message: "JsonReader.read: Json object not found"};
10824 this.metaFromRemote = true;
10825 this.meta = o.metaData;
10826 this.recordType = Roo.data.Record.create(o.metaData.fields);
10827 this.onMetaChange(this.meta, this.recordType, o);
10829 return this.readRecords(o);
10832 // private function a store will implement
10833 onMetaChange : function(meta, recordType, o){
10840 simpleAccess: function(obj, subsc) {
10847 getJsonAccessor: function(){
10849 return function(expr) {
10851 return(re.test(expr))
10852 ? new Function("obj", "return obj." + expr)
10857 return Roo.emptyFn;
10862 * Create a data block containing Roo.data.Records from an XML document.
10863 * @param {Object} o An object which contains an Array of row objects in the property specified
10864 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10865 * which contains the total size of the dataset.
10866 * @return {Object} data A data block which is used by an Roo.data.Store object as
10867 * a cache of Roo.data.Records.
10869 readRecords : function(o){
10871 * After any data loads, the raw JSON data is available for further custom processing.
10875 var s = this.meta, Record = this.recordType,
10876 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10878 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10880 if(s.totalProperty) {
10881 this.getTotal = this.getJsonAccessor(s.totalProperty);
10883 if(s.successProperty) {
10884 this.getSuccess = this.getJsonAccessor(s.successProperty);
10886 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10888 var g = this.getJsonAccessor(s.id);
10889 this.getId = function(rec) {
10891 return (r === undefined || r === "") ? null : r;
10894 this.getId = function(){return null;};
10897 for(var jj = 0; jj < fl; jj++){
10899 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10900 this.ef[jj] = this.getJsonAccessor(map);
10904 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10905 if(s.totalProperty){
10906 var vt = parseInt(this.getTotal(o), 10);
10911 if(s.successProperty){
10912 var vs = this.getSuccess(o);
10913 if(vs === false || vs === 'false'){
10918 for(var i = 0; i < c; i++){
10921 var id = this.getId(n);
10922 for(var j = 0; j < fl; j++){
10924 var v = this.ef[j](n);
10926 Roo.log('missing convert for ' + f.name);
10930 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10932 var record = new Record(values, id);
10934 records[i] = record;
10940 totalRecords : totalRecords
10945 * Ext JS Library 1.1.1
10946 * Copyright(c) 2006-2007, Ext JS, LLC.
10948 * Originally Released Under LGPL - original licence link has changed is not relivant.
10951 * <script type="text/javascript">
10955 * @class Roo.data.ArrayReader
10956 * @extends Roo.data.DataReader
10957 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10958 * Each element of that Array represents a row of data fields. The
10959 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10960 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10964 var RecordDef = Roo.data.Record.create([
10965 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10966 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10968 var myReader = new Roo.data.ArrayReader({
10969 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10973 * This would consume an Array like this:
10975 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10977 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10979 * Create a new JsonReader
10980 * @param {Object} meta Metadata configuration options.
10981 * @param {Object} recordType Either an Array of field definition objects
10982 * as specified to {@link Roo.data.Record#create},
10983 * or an {@link Roo.data.Record} object
10984 * created using {@link Roo.data.Record#create}.
10986 Roo.data.ArrayReader = function(meta, recordType){
10987 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10990 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10992 * Create a data block containing Roo.data.Records from an XML document.
10993 * @param {Object} o An Array of row objects which represents the dataset.
10994 * @return {Object} data A data block which is used by an Roo.data.Store object as
10995 * a cache of Roo.data.Records.
10997 readRecords : function(o){
10998 var sid = this.meta ? this.meta.id : null;
10999 var recordType = this.recordType, fields = recordType.prototype.fields;
11002 for(var i = 0; i < root.length; i++){
11005 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11006 for(var j = 0, jlen = fields.length; j < jlen; j++){
11007 var f = fields.items[j];
11008 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11009 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11011 values[f.name] = v;
11013 var record = new recordType(values, id);
11015 records[records.length] = record;
11019 totalRecords : records.length
11028 * @class Roo.bootstrap.ComboBox
11029 * @extends Roo.bootstrap.TriggerField
11030 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11031 * @cfg {Boolean} append (true|false) default false
11032 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11033 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11034 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11035 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11036 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11038 * Create a new ComboBox.
11039 * @param {Object} config Configuration options
11041 Roo.bootstrap.ComboBox = function(config){
11042 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11046 * Fires when the dropdown list is expanded
11047 * @param {Roo.bootstrap.ComboBox} combo This combo box
11052 * Fires when the dropdown list is collapsed
11053 * @param {Roo.bootstrap.ComboBox} combo This combo box
11057 * @event beforeselect
11058 * Fires before a list item is selected. Return false to cancel the selection.
11059 * @param {Roo.bootstrap.ComboBox} combo This combo box
11060 * @param {Roo.data.Record} record The data record returned from the underlying store
11061 * @param {Number} index The index of the selected item in the dropdown list
11063 'beforeselect' : true,
11066 * Fires when a list item is selected
11067 * @param {Roo.bootstrap.ComboBox} combo This combo box
11068 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11069 * @param {Number} index The index of the selected item in the dropdown list
11073 * @event beforequery
11074 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11075 * The event object passed has these properties:
11076 * @param {Roo.bootstrap.ComboBox} combo This combo box
11077 * @param {String} query The query
11078 * @param {Boolean} forceAll true to force "all" query
11079 * @param {Boolean} cancel true to cancel the query
11080 * @param {Object} e The query event object
11082 'beforequery': true,
11085 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11086 * @param {Roo.bootstrap.ComboBox} combo This combo box
11091 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11092 * @param {Roo.bootstrap.ComboBox} combo This combo box
11093 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11098 * Fires when the remove value from the combobox array
11099 * @param {Roo.bootstrap.ComboBox} combo This combo box
11103 * @event specialfilter
11104 * Fires when specialfilter
11105 * @param {Roo.bootstrap.ComboBox} combo This combo box
11107 'specialfilter' : true
11112 this.tickItems = [];
11114 this.selectedIndex = -1;
11115 if(this.mode == 'local'){
11116 if(config.queryDelay === undefined){
11117 this.queryDelay = 10;
11119 if(config.minChars === undefined){
11125 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11128 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11129 * rendering into an Roo.Editor, defaults to false)
11132 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11133 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11136 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11139 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11140 * the dropdown list (defaults to undefined, with no header element)
11144 * @cfg {String/Roo.Template} tpl The template to use to render the output
11148 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11150 listWidth: undefined,
11152 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11153 * mode = 'remote' or 'text' if mode = 'local')
11155 displayField: undefined,
11158 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11159 * mode = 'remote' or 'value' if mode = 'local').
11160 * Note: use of a valueField requires the user make a selection
11161 * in order for a value to be mapped.
11163 valueField: undefined,
11167 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11168 * field's data value (defaults to the underlying DOM element's name)
11170 hiddenName: undefined,
11172 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11176 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11178 selectedClass: 'active',
11181 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11185 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11186 * anchor positions (defaults to 'tl-bl')
11188 listAlign: 'tl-bl?',
11190 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11194 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11195 * query specified by the allQuery config option (defaults to 'query')
11197 triggerAction: 'query',
11199 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11200 * (defaults to 4, does not apply if editable = false)
11204 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11205 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11209 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11210 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11214 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11215 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11219 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11220 * when editable = true (defaults to false)
11222 selectOnFocus:false,
11224 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11226 queryParam: 'query',
11228 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11229 * when mode = 'remote' (defaults to 'Loading...')
11231 loadingText: 'Loading...',
11233 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11237 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11241 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11242 * traditional select (defaults to true)
11246 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11250 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11254 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11255 * listWidth has a higher value)
11259 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11260 * allow the user to set arbitrary text into the field (defaults to false)
11262 forceSelection:false,
11264 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11265 * if typeAhead = true (defaults to 250)
11267 typeAheadDelay : 250,
11269 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11270 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11272 valueNotFoundText : undefined,
11274 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11276 blockFocus : false,
11279 * @cfg {Boolean} disableClear Disable showing of clear button.
11281 disableClear : false,
11283 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11285 alwaysQuery : false,
11288 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11293 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11295 invalidClass : "has-warning",
11298 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11300 validClass : "has-success",
11303 * @cfg {Boolean} specialFilter (true|false) special filter default false
11305 specialFilter : false,
11317 btnPosition : 'right',
11318 triggerList : true,
11319 showToggleBtn : true,
11320 // element that contains real text value.. (when hidden is used..)
11322 getAutoCreate : function()
11329 if(!this.tickable){
11330 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11335 * ComboBox with tickable selections
11338 var align = this.labelAlign || this.parentLabelAlign();
11341 cls : 'form-group roo-combobox-tickable' //input-group
11346 cls : 'tickable-buttons',
11351 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11358 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11365 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11372 buttons.cn.unshift({
11374 cls: 'select2-search-field-input'
11380 Roo.each(buttons.cn, function(c){
11382 c.cls += ' btn-' + _this.size;
11385 if (_this.disabled) {
11396 cls: 'form-hidden-field'
11400 cls: 'select2-choices',
11404 cls: 'select2-search-field',
11416 cls: 'select2-container input-group select2-container-multi',
11421 // cls: 'typeahead typeahead-long dropdown-menu',
11422 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11427 if(this.hasFeedback && !this.allowBlank){
11431 cls: 'glyphicon form-control-feedback'
11434 combobox.cn.push(feedback);
11437 if (align ==='left' && this.fieldLabel.length) {
11439 Roo.log("left and has label");
11445 cls : 'control-label col-sm-' + this.labelWidth,
11446 html : this.fieldLabel
11450 cls : "col-sm-" + (12 - this.labelWidth),
11457 } else if ( this.fieldLabel.length) {
11463 //cls : 'input-group-addon',
11464 html : this.fieldLabel
11474 Roo.log(" no label && no align");
11481 ['xs','sm','md','lg'].map(function(size){
11482 if (settings[size]) {
11483 cfg.cls += ' col-' + size + '-' + settings[size];
11492 initEvents: function()
11496 throw "can not find store for combo";
11498 this.store = Roo.factory(this.store, Roo.data);
11501 this.initTickableEvents();
11505 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11507 if(this.hiddenName){
11509 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11511 this.hiddenField.dom.value =
11512 this.hiddenValue !== undefined ? this.hiddenValue :
11513 this.value !== undefined ? this.value : '';
11515 // prevent input submission
11516 this.el.dom.removeAttribute('name');
11517 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11522 // this.el.dom.setAttribute('autocomplete', 'off');
11525 var cls = 'x-combo-list';
11527 //this.list = new Roo.Layer({
11528 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11534 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11535 _this.list.setWidth(lw);
11538 this.list.on('mouseover', this.onViewOver, this);
11539 this.list.on('mousemove', this.onViewMove, this);
11541 this.list.on('scroll', this.onViewScroll, this);
11544 this.list.swallowEvent('mousewheel');
11545 this.assetHeight = 0;
11548 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11549 this.assetHeight += this.header.getHeight();
11552 this.innerList = this.list.createChild({cls:cls+'-inner'});
11553 this.innerList.on('mouseover', this.onViewOver, this);
11554 this.innerList.on('mousemove', this.onViewMove, this);
11555 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11557 if(this.allowBlank && !this.pageSize && !this.disableClear){
11558 this.footer = this.list.createChild({cls:cls+'-ft'});
11559 this.pageTb = new Roo.Toolbar(this.footer);
11563 this.footer = this.list.createChild({cls:cls+'-ft'});
11564 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11565 {pageSize: this.pageSize});
11569 if (this.pageTb && this.allowBlank && !this.disableClear) {
11571 this.pageTb.add(new Roo.Toolbar.Fill(), {
11572 cls: 'x-btn-icon x-btn-clear',
11574 handler: function()
11577 _this.clearValue();
11578 _this.onSelect(false, -1);
11583 this.assetHeight += this.footer.getHeight();
11588 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11591 this.view = new Roo.View(this.list, this.tpl, {
11592 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11594 //this.view.wrapEl.setDisplayed(false);
11595 this.view.on('click', this.onViewClick, this);
11599 this.store.on('beforeload', this.onBeforeLoad, this);
11600 this.store.on('load', this.onLoad, this);
11601 this.store.on('loadexception', this.onLoadException, this);
11603 if(this.resizable){
11604 this.resizer = new Roo.Resizable(this.list, {
11605 pinned:true, handles:'se'
11607 this.resizer.on('resize', function(r, w, h){
11608 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11609 this.listWidth = w;
11610 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11611 this.restrictHeight();
11613 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11616 if(!this.editable){
11617 this.editable = true;
11618 this.setEditable(false);
11623 if (typeof(this.events.add.listeners) != 'undefined') {
11625 this.addicon = this.wrap.createChild(
11626 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11628 this.addicon.on('click', function(e) {
11629 this.fireEvent('add', this);
11632 if (typeof(this.events.edit.listeners) != 'undefined') {
11634 this.editicon = this.wrap.createChild(
11635 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11636 if (this.addicon) {
11637 this.editicon.setStyle('margin-left', '40px');
11639 this.editicon.on('click', function(e) {
11641 // we fire even if inothing is selected..
11642 this.fireEvent('edit', this, this.lastData );
11648 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11649 "up" : function(e){
11650 this.inKeyMode = true;
11654 "down" : function(e){
11655 if(!this.isExpanded()){
11656 this.onTriggerClick();
11658 this.inKeyMode = true;
11663 "enter" : function(e){
11664 // this.onViewClick();
11668 if(this.fireEvent("specialkey", this, e)){
11669 this.onViewClick(false);
11675 "esc" : function(e){
11679 "tab" : function(e){
11682 if(this.fireEvent("specialkey", this, e)){
11683 this.onViewClick(false);
11691 doRelay : function(foo, bar, hname){
11692 if(hname == 'down' || this.scope.isExpanded()){
11693 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11702 this.queryDelay = Math.max(this.queryDelay || 10,
11703 this.mode == 'local' ? 10 : 250);
11706 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11708 if(this.typeAhead){
11709 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11711 if(this.editable !== false){
11712 this.inputEl().on("keyup", this.onKeyUp, this);
11714 if(this.forceSelection){
11715 this.inputEl().on('blur', this.doForce, this);
11719 this.choices = this.el.select('ul.select2-choices', true).first();
11720 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11724 initTickableEvents: function()
11728 if(this.hiddenName){
11730 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11732 this.hiddenField.dom.value =
11733 this.hiddenValue !== undefined ? this.hiddenValue :
11734 this.value !== undefined ? this.value : '';
11736 // prevent input submission
11737 this.el.dom.removeAttribute('name');
11738 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11743 // this.list = this.el.select('ul.dropdown-menu',true).first();
11745 this.choices = this.el.select('ul.select2-choices', true).first();
11746 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11747 if(this.triggerList){
11748 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11751 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11752 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11754 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11755 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11757 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11758 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11760 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11761 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11762 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11765 this.cancelBtn.hide();
11770 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11771 _this.list.setWidth(lw);
11774 this.list.on('mouseover', this.onViewOver, this);
11775 this.list.on('mousemove', this.onViewMove, this);
11777 this.list.on('scroll', this.onViewScroll, this);
11780 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>';
11783 this.view = new Roo.View(this.list, this.tpl, {
11784 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11787 //this.view.wrapEl.setDisplayed(false);
11788 this.view.on('click', this.onViewClick, this);
11792 this.store.on('beforeload', this.onBeforeLoad, this);
11793 this.store.on('load', this.onLoad, this);
11794 this.store.on('loadexception', this.onLoadException, this);
11797 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11798 "up" : function(e){
11799 this.inKeyMode = true;
11803 "down" : function(e){
11804 this.inKeyMode = true;
11808 "enter" : function(e){
11809 if(this.fireEvent("specialkey", this, e)){
11810 this.onViewClick(false);
11816 "esc" : function(e){
11817 this.onTickableFooterButtonClick(e, false, false);
11820 "tab" : function(e){
11821 this.fireEvent("specialkey", this, e);
11823 this.onTickableFooterButtonClick(e, false, false);
11830 doRelay : function(e, fn, key){
11831 if(this.scope.isExpanded()){
11832 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11841 this.queryDelay = Math.max(this.queryDelay || 10,
11842 this.mode == 'local' ? 10 : 250);
11845 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11847 if(this.typeAhead){
11848 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11851 if(this.editable !== false){
11852 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11857 onDestroy : function(){
11859 this.view.setStore(null);
11860 this.view.el.removeAllListeners();
11861 this.view.el.remove();
11862 this.view.purgeListeners();
11865 this.list.dom.innerHTML = '';
11869 this.store.un('beforeload', this.onBeforeLoad, this);
11870 this.store.un('load', this.onLoad, this);
11871 this.store.un('loadexception', this.onLoadException, this);
11873 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11877 fireKey : function(e){
11878 if(e.isNavKeyPress() && !this.list.isVisible()){
11879 this.fireEvent("specialkey", this, e);
11884 onResize: function(w, h){
11885 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11887 // if(typeof w != 'number'){
11888 // // we do not handle it!?!?
11891 // var tw = this.trigger.getWidth();
11892 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11893 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11895 // this.inputEl().setWidth( this.adjustWidth('input', x));
11897 // //this.trigger.setStyle('left', x+'px');
11899 // if(this.list && this.listWidth === undefined){
11900 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11901 // this.list.setWidth(lw);
11902 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11910 * Allow or prevent the user from directly editing the field text. If false is passed,
11911 * the user will only be able to select from the items defined in the dropdown list. This method
11912 * is the runtime equivalent of setting the 'editable' config option at config time.
11913 * @param {Boolean} value True to allow the user to directly edit the field text
11915 setEditable : function(value){
11916 if(value == this.editable){
11919 this.editable = value;
11921 this.inputEl().dom.setAttribute('readOnly', true);
11922 this.inputEl().on('mousedown', this.onTriggerClick, this);
11923 this.inputEl().addClass('x-combo-noedit');
11925 this.inputEl().dom.setAttribute('readOnly', false);
11926 this.inputEl().un('mousedown', this.onTriggerClick, this);
11927 this.inputEl().removeClass('x-combo-noedit');
11933 onBeforeLoad : function(combo,opts){
11934 if(!this.hasFocus){
11938 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11940 this.restrictHeight();
11941 this.selectedIndex = -1;
11945 onLoad : function(){
11947 this.hasQuery = false;
11949 if(!this.hasFocus){
11953 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11954 this.loading.hide();
11957 if(this.store.getCount() > 0){
11959 this.restrictHeight();
11960 if(this.lastQuery == this.allQuery){
11961 if(this.editable && !this.tickable){
11962 this.inputEl().dom.select();
11966 !this.selectByValue(this.value, true) &&
11969 !this.store.lastOptions ||
11970 typeof(this.store.lastOptions.add) == 'undefined' ||
11971 this.store.lastOptions.add != true
11974 this.select(0, true);
11977 if(this.autoFocus){
11980 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11981 this.taTask.delay(this.typeAheadDelay);
11985 this.onEmptyResults();
11991 onLoadException : function()
11993 this.hasQuery = false;
11995 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11996 this.loading.hide();
11999 if(this.tickable && this.editable){
12005 Roo.log(this.store.reader.jsonData);
12006 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12008 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12014 onTypeAhead : function(){
12015 if(this.store.getCount() > 0){
12016 var r = this.store.getAt(0);
12017 var newValue = r.data[this.displayField];
12018 var len = newValue.length;
12019 var selStart = this.getRawValue().length;
12021 if(selStart != len){
12022 this.setRawValue(newValue);
12023 this.selectText(selStart, newValue.length);
12029 onSelect : function(record, index){
12031 if(this.fireEvent('beforeselect', this, record, index) !== false){
12033 this.setFromData(index > -1 ? record.data : false);
12036 this.fireEvent('select', this, record, index);
12041 * Returns the currently selected field value or empty string if no value is set.
12042 * @return {String} value The selected value
12044 getValue : function(){
12047 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12050 if(this.valueField){
12051 return typeof this.value != 'undefined' ? this.value : '';
12053 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12058 * Clears any text/value currently set in the field
12060 clearValue : function(){
12061 if(this.hiddenField){
12062 this.hiddenField.dom.value = '';
12065 this.setRawValue('');
12066 this.lastSelectionText = '';
12067 this.lastData = false;
12069 var close = this.closeTriggerEl();
12078 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12079 * will be displayed in the field. If the value does not match the data value of an existing item,
12080 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12081 * Otherwise the field will be blank (although the value will still be set).
12082 * @param {String} value The value to match
12084 setValue : function(v){
12091 if(this.valueField){
12092 var r = this.findRecord(this.valueField, v);
12094 text = r.data[this.displayField];
12095 }else if(this.valueNotFoundText !== undefined){
12096 text = this.valueNotFoundText;
12099 this.lastSelectionText = text;
12100 if(this.hiddenField){
12101 this.hiddenField.dom.value = v;
12103 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12106 var close = this.closeTriggerEl();
12109 (v.length || v * 1 > 0) ? close.show() : close.hide();
12113 * @property {Object} the last set data for the element
12118 * Sets the value of the field based on a object which is related to the record format for the store.
12119 * @param {Object} value the value to set as. or false on reset?
12121 setFromData : function(o){
12128 var dv = ''; // display value
12129 var vv = ''; // value value..
12131 if (this.displayField) {
12132 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12134 // this is an error condition!!!
12135 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12138 if(this.valueField){
12139 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12142 var close = this.closeTriggerEl();
12145 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12148 if(this.hiddenField){
12149 this.hiddenField.dom.value = vv;
12151 this.lastSelectionText = dv;
12152 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12156 // no hidden field.. - we store the value in 'value', but still display
12157 // display field!!!!
12158 this.lastSelectionText = dv;
12159 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12166 reset : function(){
12167 // overridden so that last data is reset..
12174 this.setValue(this.originalValue);
12175 this.clearInvalid();
12176 this.lastData = false;
12178 this.view.clearSelections();
12182 findRecord : function(prop, value){
12184 if(this.store.getCount() > 0){
12185 this.store.each(function(r){
12186 if(r.data[prop] == value){
12196 getName: function()
12198 // returns hidden if it's set..
12199 if (!this.rendered) {return ''};
12200 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12204 onViewMove : function(e, t){
12205 this.inKeyMode = false;
12209 onViewOver : function(e, t){
12210 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12213 var item = this.view.findItemFromChild(t);
12216 var index = this.view.indexOf(item);
12217 this.select(index, false);
12222 onViewClick : function(view, doFocus, el, e)
12224 var index = this.view.getSelectedIndexes()[0];
12226 var r = this.store.getAt(index);
12230 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12237 Roo.each(this.tickItems, function(v,k){
12239 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12240 _this.tickItems.splice(k, 1);
12242 if(typeof(e) == 'undefined' && view == false){
12243 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12255 this.tickItems.push(r.data);
12257 if(typeof(e) == 'undefined' && view == false){
12258 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12265 this.onSelect(r, index);
12267 if(doFocus !== false && !this.blockFocus){
12268 this.inputEl().focus();
12273 restrictHeight : function(){
12274 //this.innerList.dom.style.height = '';
12275 //var inner = this.innerList.dom;
12276 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12277 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12278 //this.list.beginUpdate();
12279 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12280 this.list.alignTo(this.inputEl(), this.listAlign);
12281 this.list.alignTo(this.inputEl(), this.listAlign);
12282 //this.list.endUpdate();
12286 onEmptyResults : function(){
12288 if(this.tickable && this.editable){
12289 this.restrictHeight();
12297 * Returns true if the dropdown list is expanded, else false.
12299 isExpanded : function(){
12300 return this.list.isVisible();
12304 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12305 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12306 * @param {String} value The data value of the item to select
12307 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12308 * selected item if it is not currently in view (defaults to true)
12309 * @return {Boolean} True if the value matched an item in the list, else false
12311 selectByValue : function(v, scrollIntoView){
12312 if(v !== undefined && v !== null){
12313 var r = this.findRecord(this.valueField || this.displayField, v);
12315 this.select(this.store.indexOf(r), scrollIntoView);
12323 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12324 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12325 * @param {Number} index The zero-based index of the list item to select
12326 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12327 * selected item if it is not currently in view (defaults to true)
12329 select : function(index, scrollIntoView){
12330 this.selectedIndex = index;
12331 this.view.select(index);
12332 if(scrollIntoView !== false){
12333 var el = this.view.getNode(index);
12335 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12338 this.list.scrollChildIntoView(el, false);
12344 selectNext : function(){
12345 var ct = this.store.getCount();
12347 if(this.selectedIndex == -1){
12349 }else if(this.selectedIndex < ct-1){
12350 this.select(this.selectedIndex+1);
12356 selectPrev : function(){
12357 var ct = this.store.getCount();
12359 if(this.selectedIndex == -1){
12361 }else if(this.selectedIndex != 0){
12362 this.select(this.selectedIndex-1);
12368 onKeyUp : function(e){
12369 if(this.editable !== false && !e.isSpecialKey()){
12370 this.lastKey = e.getKey();
12371 this.dqTask.delay(this.queryDelay);
12376 validateBlur : function(){
12377 return !this.list || !this.list.isVisible();
12381 initQuery : function(){
12383 var v = this.getRawValue();
12385 if(this.tickable && this.editable){
12386 v = this.tickableInputEl().getValue();
12393 doForce : function(){
12394 if(this.inputEl().dom.value.length > 0){
12395 this.inputEl().dom.value =
12396 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12402 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12403 * query allowing the query action to be canceled if needed.
12404 * @param {String} query The SQL query to execute
12405 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12406 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12407 * saved in the current store (defaults to false)
12409 doQuery : function(q, forceAll){
12411 if(q === undefined || q === null){
12416 forceAll: forceAll,
12420 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12425 forceAll = qe.forceAll;
12426 if(forceAll === true || (q.length >= this.minChars)){
12428 this.hasQuery = true;
12430 if(this.lastQuery != q || this.alwaysQuery){
12431 this.lastQuery = q;
12432 if(this.mode == 'local'){
12433 this.selectedIndex = -1;
12435 this.store.clearFilter();
12438 if(this.specialFilter){
12439 this.fireEvent('specialfilter', this);
12444 this.store.filter(this.displayField, q);
12447 this.store.fireEvent("datachanged", this.store);
12454 this.store.baseParams[this.queryParam] = q;
12456 var options = {params : this.getParams(q)};
12459 options.add = true;
12460 options.params.start = this.page * this.pageSize;
12463 this.store.load(options);
12466 * this code will make the page width larger, at the beginning, the list not align correctly,
12467 * we should expand the list on onLoad
12468 * so command out it
12473 this.selectedIndex = -1;
12478 this.loadNext = false;
12482 getParams : function(q){
12484 //p[this.queryParam] = q;
12488 p.limit = this.pageSize;
12494 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12496 collapse : function(){
12497 if(!this.isExpanded()){
12504 this.hasFocus = false;
12506 this.cancelBtn.hide();
12507 this.trigger.show();
12510 this.tickableInputEl().dom.value = '';
12511 this.tickableInputEl().blur();
12516 Roo.get(document).un('mousedown', this.collapseIf, this);
12517 Roo.get(document).un('mousewheel', this.collapseIf, this);
12518 if (!this.editable) {
12519 Roo.get(document).un('keydown', this.listKeyPress, this);
12521 this.fireEvent('collapse', this);
12525 collapseIf : function(e){
12526 var in_combo = e.within(this.el);
12527 var in_list = e.within(this.list);
12528 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12530 if (in_combo || in_list || is_list) {
12531 //e.stopPropagation();
12536 this.onTickableFooterButtonClick(e, false, false);
12544 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12546 expand : function(){
12548 if(this.isExpanded() || !this.hasFocus){
12552 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12553 this.list.setWidth(lw);
12560 this.restrictHeight();
12564 this.tickItems = Roo.apply([], this.item);
12567 this.cancelBtn.show();
12568 this.trigger.hide();
12571 this.tickableInputEl().focus();
12576 Roo.get(document).on('mousedown', this.collapseIf, this);
12577 Roo.get(document).on('mousewheel', this.collapseIf, this);
12578 if (!this.editable) {
12579 Roo.get(document).on('keydown', this.listKeyPress, this);
12582 this.fireEvent('expand', this);
12586 // Implements the default empty TriggerField.onTriggerClick function
12587 onTriggerClick : function(e)
12589 Roo.log('trigger click');
12591 if(this.disabled || !this.triggerList){
12596 this.loadNext = false;
12598 if(this.isExpanded()){
12600 if (!this.blockFocus) {
12601 this.inputEl().focus();
12605 this.hasFocus = true;
12606 if(this.triggerAction == 'all') {
12607 this.doQuery(this.allQuery, true);
12609 this.doQuery(this.getRawValue());
12611 if (!this.blockFocus) {
12612 this.inputEl().focus();
12617 onTickableTriggerClick : function(e)
12624 this.loadNext = false;
12625 this.hasFocus = true;
12627 if(this.triggerAction == 'all') {
12628 this.doQuery(this.allQuery, true);
12630 this.doQuery(this.getRawValue());
12634 onSearchFieldClick : function(e)
12636 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12637 this.onTickableFooterButtonClick(e, false, false);
12641 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12646 this.loadNext = false;
12647 this.hasFocus = true;
12649 if(this.triggerAction == 'all') {
12650 this.doQuery(this.allQuery, true);
12652 this.doQuery(this.getRawValue());
12656 listKeyPress : function(e)
12658 //Roo.log('listkeypress');
12659 // scroll to first matching element based on key pres..
12660 if (e.isSpecialKey()) {
12663 var k = String.fromCharCode(e.getKey()).toUpperCase();
12666 var csel = this.view.getSelectedNodes();
12667 var cselitem = false;
12669 var ix = this.view.indexOf(csel[0]);
12670 cselitem = this.store.getAt(ix);
12671 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12677 this.store.each(function(v) {
12679 // start at existing selection.
12680 if (cselitem.id == v.id) {
12686 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12687 match = this.store.indexOf(v);
12693 if (match === false) {
12694 return true; // no more action?
12697 this.view.select(match);
12698 var sn = Roo.get(this.view.getSelectedNodes()[0])
12699 sn.scrollIntoView(sn.dom.parentNode, false);
12702 onViewScroll : function(e, t){
12704 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){
12708 this.hasQuery = true;
12710 this.loading = this.list.select('.loading', true).first();
12712 if(this.loading === null){
12713 this.list.createChild({
12715 cls: 'loading select2-more-results select2-active',
12716 html: 'Loading more results...'
12719 this.loading = this.list.select('.loading', true).first();
12721 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12723 this.loading.hide();
12726 this.loading.show();
12731 this.loadNext = true;
12733 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12738 addItem : function(o)
12740 var dv = ''; // display value
12742 if (this.displayField) {
12743 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12745 // this is an error condition!!!
12746 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12753 var choice = this.choices.createChild({
12755 cls: 'select2-search-choice',
12764 cls: 'select2-search-choice-close',
12769 }, this.searchField);
12771 var close = choice.select('a.select2-search-choice-close', true).first()
12773 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12781 this.inputEl().dom.value = '';
12786 onRemoveItem : function(e, _self, o)
12788 e.preventDefault();
12790 this.lastItem = Roo.apply([], this.item);
12792 var index = this.item.indexOf(o.data) * 1;
12795 Roo.log('not this item?!');
12799 this.item.splice(index, 1);
12804 this.fireEvent('remove', this, e);
12810 syncValue : function()
12812 if(!this.item.length){
12819 Roo.each(this.item, function(i){
12820 if(_this.valueField){
12821 value.push(i[_this.valueField]);
12828 this.value = value.join(',');
12830 if(this.hiddenField){
12831 this.hiddenField.dom.value = this.value;
12834 this.store.fireEvent("datachanged", this.store);
12837 clearItem : function()
12839 if(!this.multiple){
12845 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12854 inputEl: function ()
12857 return this.searchField;
12859 return this.el.select('input.form-control',true).first();
12863 onTickableFooterButtonClick : function(e, btn, el)
12865 e.preventDefault();
12867 this.lastItem = Roo.apply([], this.item);
12869 if(btn && btn.name == 'cancel'){
12870 this.tickItems = Roo.apply([], this.item);
12879 Roo.each(this.tickItems, function(o){
12887 validate : function()
12889 var v = this.getRawValue();
12892 v = this.getValue();
12895 if(this.disabled || this.allowBlank || v.length){
12900 this.markInvalid();
12904 tickableInputEl : function()
12906 if(!this.tickable || !this.editable){
12907 return this.inputEl();
12910 return this.inputEl().select('.select2-search-field-input', true).first();
12916 * @cfg {Boolean} grow
12920 * @cfg {Number} growMin
12924 * @cfg {Number} growMax
12934 * Ext JS Library 1.1.1
12935 * Copyright(c) 2006-2007, Ext JS, LLC.
12937 * Originally Released Under LGPL - original licence link has changed is not relivant.
12940 * <script type="text/javascript">
12945 * @extends Roo.util.Observable
12946 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12947 * This class also supports single and multi selection modes. <br>
12948 * Create a data model bound view:
12950 var store = new Roo.data.Store(...);
12952 var view = new Roo.View({
12954 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12956 singleSelect: true,
12957 selectedClass: "ydataview-selected",
12961 // listen for node click?
12962 view.on("click", function(vw, index, node, e){
12963 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12967 dataModel.load("foobar.xml");
12969 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12971 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12972 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12974 * Note: old style constructor is still suported (container, template, config)
12977 * Create a new View
12978 * @param {Object} config The config object
12981 Roo.View = function(config, depreciated_tpl, depreciated_config){
12983 this.parent = false;
12985 if (typeof(depreciated_tpl) == 'undefined') {
12986 // new way.. - universal constructor.
12987 Roo.apply(this, config);
12988 this.el = Roo.get(this.el);
12991 this.el = Roo.get(config);
12992 this.tpl = depreciated_tpl;
12993 Roo.apply(this, depreciated_config);
12995 this.wrapEl = this.el.wrap().wrap();
12996 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12999 if(typeof(this.tpl) == "string"){
13000 this.tpl = new Roo.Template(this.tpl);
13002 // support xtype ctors..
13003 this.tpl = new Roo.factory(this.tpl, Roo);
13007 this.tpl.compile();
13012 * @event beforeclick
13013 * Fires before a click is processed. Returns false to cancel the default action.
13014 * @param {Roo.View} this
13015 * @param {Number} index The index of the target node
13016 * @param {HTMLElement} node The target node
13017 * @param {Roo.EventObject} e The raw event object
13019 "beforeclick" : true,
13022 * Fires when a template node is clicked.
13023 * @param {Roo.View} this
13024 * @param {Number} index The index of the target node
13025 * @param {HTMLElement} node The target node
13026 * @param {Roo.EventObject} e The raw event object
13031 * Fires when a template node is double clicked.
13032 * @param {Roo.View} this
13033 * @param {Number} index The index of the target node
13034 * @param {HTMLElement} node The target node
13035 * @param {Roo.EventObject} e The raw event object
13039 * @event contextmenu
13040 * Fires when a template node is right clicked.
13041 * @param {Roo.View} this
13042 * @param {Number} index The index of the target node
13043 * @param {HTMLElement} node The target node
13044 * @param {Roo.EventObject} e The raw event object
13046 "contextmenu" : true,
13048 * @event selectionchange
13049 * Fires when the selected nodes change.
13050 * @param {Roo.View} this
13051 * @param {Array} selections Array of the selected nodes
13053 "selectionchange" : true,
13056 * @event beforeselect
13057 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13058 * @param {Roo.View} this
13059 * @param {HTMLElement} node The node to be selected
13060 * @param {Array} selections Array of currently selected nodes
13062 "beforeselect" : true,
13064 * @event preparedata
13065 * Fires on every row to render, to allow you to change the data.
13066 * @param {Roo.View} this
13067 * @param {Object} data to be rendered (change this)
13069 "preparedata" : true
13077 "click": this.onClick,
13078 "dblclick": this.onDblClick,
13079 "contextmenu": this.onContextMenu,
13083 this.selections = [];
13085 this.cmp = new Roo.CompositeElementLite([]);
13087 this.store = Roo.factory(this.store, Roo.data);
13088 this.setStore(this.store, true);
13091 if ( this.footer && this.footer.xtype) {
13093 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13095 this.footer.dataSource = this.store
13096 this.footer.container = fctr;
13097 this.footer = Roo.factory(this.footer, Roo);
13098 fctr.insertFirst(this.el);
13100 // this is a bit insane - as the paging toolbar seems to detach the el..
13101 // dom.parentNode.parentNode.parentNode
13102 // they get detached?
13106 Roo.View.superclass.constructor.call(this);
13111 Roo.extend(Roo.View, Roo.util.Observable, {
13114 * @cfg {Roo.data.Store} store Data store to load data from.
13119 * @cfg {String|Roo.Element} el The container element.
13124 * @cfg {String|Roo.Template} tpl The template used by this View
13128 * @cfg {String} dataName the named area of the template to use as the data area
13129 * Works with domtemplates roo-name="name"
13133 * @cfg {String} selectedClass The css class to add to selected nodes
13135 selectedClass : "x-view-selected",
13137 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13142 * @cfg {String} text to display on mask (default Loading)
13146 * @cfg {Boolean} multiSelect Allow multiple selection
13148 multiSelect : false,
13150 * @cfg {Boolean} singleSelect Allow single selection
13152 singleSelect: false,
13155 * @cfg {Boolean} toggleSelect - selecting
13157 toggleSelect : false,
13160 * @cfg {Boolean} tickable - selecting
13165 * Returns the element this view is bound to.
13166 * @return {Roo.Element}
13168 getEl : function(){
13169 return this.wrapEl;
13175 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13177 refresh : function(){
13178 //Roo.log('refresh');
13181 // if we are using something like 'domtemplate', then
13182 // the what gets used is:
13183 // t.applySubtemplate(NAME, data, wrapping data..)
13184 // the outer template then get' applied with
13185 // the store 'extra data'
13186 // and the body get's added to the
13187 // roo-name="data" node?
13188 // <span class='roo-tpl-{name}'></span> ?????
13192 this.clearSelections();
13193 this.el.update("");
13195 var records = this.store.getRange();
13196 if(records.length < 1) {
13198 // is this valid?? = should it render a template??
13200 this.el.update(this.emptyText);
13204 if (this.dataName) {
13205 this.el.update(t.apply(this.store.meta)); //????
13206 el = this.el.child('.roo-tpl-' + this.dataName);
13209 for(var i = 0, len = records.length; i < len; i++){
13210 var data = this.prepareData(records[i].data, i, records[i]);
13211 this.fireEvent("preparedata", this, data, i, records[i]);
13213 var d = Roo.apply({}, data);
13216 Roo.apply(d, {'roo-id' : Roo.id()});
13220 Roo.each(this.parent.item, function(item){
13221 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13224 Roo.apply(d, {'roo-data-checked' : 'checked'});
13228 html[html.length] = Roo.util.Format.trim(
13230 t.applySubtemplate(this.dataName, d, this.store.meta) :
13237 el.update(html.join(""));
13238 this.nodes = el.dom.childNodes;
13239 this.updateIndexes(0);
13244 * Function to override to reformat the data that is sent to
13245 * the template for each node.
13246 * DEPRICATED - use the preparedata event handler.
13247 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13248 * a JSON object for an UpdateManager bound view).
13250 prepareData : function(data, index, record)
13252 this.fireEvent("preparedata", this, data, index, record);
13256 onUpdate : function(ds, record){
13257 // Roo.log('on update');
13258 this.clearSelections();
13259 var index = this.store.indexOf(record);
13260 var n = this.nodes[index];
13261 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13262 n.parentNode.removeChild(n);
13263 this.updateIndexes(index, index);
13269 onAdd : function(ds, records, index)
13271 //Roo.log(['on Add', ds, records, index] );
13272 this.clearSelections();
13273 if(this.nodes.length == 0){
13277 var n = this.nodes[index];
13278 for(var i = 0, len = records.length; i < len; i++){
13279 var d = this.prepareData(records[i].data, i, records[i]);
13281 this.tpl.insertBefore(n, d);
13284 this.tpl.append(this.el, d);
13287 this.updateIndexes(index);
13290 onRemove : function(ds, record, index){
13291 // Roo.log('onRemove');
13292 this.clearSelections();
13293 var el = this.dataName ?
13294 this.el.child('.roo-tpl-' + this.dataName) :
13297 el.dom.removeChild(this.nodes[index]);
13298 this.updateIndexes(index);
13302 * Refresh an individual node.
13303 * @param {Number} index
13305 refreshNode : function(index){
13306 this.onUpdate(this.store, this.store.getAt(index));
13309 updateIndexes : function(startIndex, endIndex){
13310 var ns = this.nodes;
13311 startIndex = startIndex || 0;
13312 endIndex = endIndex || ns.length - 1;
13313 for(var i = startIndex; i <= endIndex; i++){
13314 ns[i].nodeIndex = i;
13319 * Changes the data store this view uses and refresh the view.
13320 * @param {Store} store
13322 setStore : function(store, initial){
13323 if(!initial && this.store){
13324 this.store.un("datachanged", this.refresh);
13325 this.store.un("add", this.onAdd);
13326 this.store.un("remove", this.onRemove);
13327 this.store.un("update", this.onUpdate);
13328 this.store.un("clear", this.refresh);
13329 this.store.un("beforeload", this.onBeforeLoad);
13330 this.store.un("load", this.onLoad);
13331 this.store.un("loadexception", this.onLoad);
13335 store.on("datachanged", this.refresh, this);
13336 store.on("add", this.onAdd, this);
13337 store.on("remove", this.onRemove, this);
13338 store.on("update", this.onUpdate, this);
13339 store.on("clear", this.refresh, this);
13340 store.on("beforeload", this.onBeforeLoad, this);
13341 store.on("load", this.onLoad, this);
13342 store.on("loadexception", this.onLoad, this);
13350 * onbeforeLoad - masks the loading area.
13353 onBeforeLoad : function(store,opts)
13355 //Roo.log('onBeforeLoad');
13357 this.el.update("");
13359 this.el.mask(this.mask ? this.mask : "Loading" );
13361 onLoad : function ()
13368 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13369 * @param {HTMLElement} node
13370 * @return {HTMLElement} The template node
13372 findItemFromChild : function(node){
13373 var el = this.dataName ?
13374 this.el.child('.roo-tpl-' + this.dataName,true) :
13377 if(!node || node.parentNode == el){
13380 var p = node.parentNode;
13381 while(p && p != el){
13382 if(p.parentNode == el){
13391 onClick : function(e){
13392 var item = this.findItemFromChild(e.getTarget());
13394 var index = this.indexOf(item);
13395 if(this.onItemClick(item, index, e) !== false){
13396 this.fireEvent("click", this, index, item, e);
13399 this.clearSelections();
13404 onContextMenu : function(e){
13405 var item = this.findItemFromChild(e.getTarget());
13407 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13412 onDblClick : function(e){
13413 var item = this.findItemFromChild(e.getTarget());
13415 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13419 onItemClick : function(item, index, e)
13421 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13424 if (this.toggleSelect) {
13425 var m = this.isSelected(item) ? 'unselect' : 'select';
13428 _t[m](item, true, false);
13431 if(this.multiSelect || this.singleSelect){
13432 if(this.multiSelect && e.shiftKey && this.lastSelection){
13433 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13435 this.select(item, this.multiSelect && e.ctrlKey);
13436 this.lastSelection = item;
13439 if(!this.tickable){
13440 e.preventDefault();
13448 * Get the number of selected nodes.
13451 getSelectionCount : function(){
13452 return this.selections.length;
13456 * Get the currently selected nodes.
13457 * @return {Array} An array of HTMLElements
13459 getSelectedNodes : function(){
13460 return this.selections;
13464 * Get the indexes of the selected nodes.
13467 getSelectedIndexes : function(){
13468 var indexes = [], s = this.selections;
13469 for(var i = 0, len = s.length; i < len; i++){
13470 indexes.push(s[i].nodeIndex);
13476 * Clear all selections
13477 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13479 clearSelections : function(suppressEvent){
13480 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13481 this.cmp.elements = this.selections;
13482 this.cmp.removeClass(this.selectedClass);
13483 this.selections = [];
13484 if(!suppressEvent){
13485 this.fireEvent("selectionchange", this, this.selections);
13491 * Returns true if the passed node is selected
13492 * @param {HTMLElement/Number} node The node or node index
13493 * @return {Boolean}
13495 isSelected : function(node){
13496 var s = this.selections;
13500 node = this.getNode(node);
13501 return s.indexOf(node) !== -1;
13506 * @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
13507 * @param {Boolean} keepExisting (optional) true to keep existing selections
13508 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13510 select : function(nodeInfo, keepExisting, suppressEvent){
13511 if(nodeInfo instanceof Array){
13513 this.clearSelections(true);
13515 for(var i = 0, len = nodeInfo.length; i < len; i++){
13516 this.select(nodeInfo[i], true, true);
13520 var node = this.getNode(nodeInfo);
13521 if(!node || this.isSelected(node)){
13522 return; // already selected.
13525 this.clearSelections(true);
13528 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13529 Roo.fly(node).addClass(this.selectedClass);
13530 this.selections.push(node);
13531 if(!suppressEvent){
13532 this.fireEvent("selectionchange", this, this.selections);
13540 * @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
13541 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13542 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13544 unselect : function(nodeInfo, keepExisting, suppressEvent)
13546 if(nodeInfo instanceof Array){
13547 Roo.each(this.selections, function(s) {
13548 this.unselect(s, nodeInfo);
13552 var node = this.getNode(nodeInfo);
13553 if(!node || !this.isSelected(node)){
13554 //Roo.log("not selected");
13555 return; // not selected.
13559 Roo.each(this.selections, function(s) {
13561 Roo.fly(node).removeClass(this.selectedClass);
13568 this.selections= ns;
13569 this.fireEvent("selectionchange", this, this.selections);
13573 * Gets a template node.
13574 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13575 * @return {HTMLElement} The node or null if it wasn't found
13577 getNode : function(nodeInfo){
13578 if(typeof nodeInfo == "string"){
13579 return document.getElementById(nodeInfo);
13580 }else if(typeof nodeInfo == "number"){
13581 return this.nodes[nodeInfo];
13587 * Gets a range template nodes.
13588 * @param {Number} startIndex
13589 * @param {Number} endIndex
13590 * @return {Array} An array of nodes
13592 getNodes : function(start, end){
13593 var ns = this.nodes;
13594 start = start || 0;
13595 end = typeof end == "undefined" ? ns.length - 1 : end;
13598 for(var i = start; i <= end; i++){
13602 for(var i = start; i >= end; i--){
13610 * Finds the index of the passed node
13611 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13612 * @return {Number} The index of the node or -1
13614 indexOf : function(node){
13615 node = this.getNode(node);
13616 if(typeof node.nodeIndex == "number"){
13617 return node.nodeIndex;
13619 var ns = this.nodes;
13620 for(var i = 0, len = ns.length; i < len; i++){
13631 * based on jquery fullcalendar
13635 Roo.bootstrap = Roo.bootstrap || {};
13637 * @class Roo.bootstrap.Calendar
13638 * @extends Roo.bootstrap.Component
13639 * Bootstrap Calendar class
13640 * @cfg {Boolean} loadMask (true|false) default false
13641 * @cfg {Object} header generate the user specific header of the calendar, default false
13644 * Create a new Container
13645 * @param {Object} config The config object
13650 Roo.bootstrap.Calendar = function(config){
13651 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13655 * Fires when a date is selected
13656 * @param {DatePicker} this
13657 * @param {Date} date The selected date
13661 * @event monthchange
13662 * Fires when the displayed month changes
13663 * @param {DatePicker} this
13664 * @param {Date} date The selected month
13666 'monthchange': true,
13668 * @event evententer
13669 * Fires when mouse over an event
13670 * @param {Calendar} this
13671 * @param {event} Event
13673 'evententer': true,
13675 * @event eventleave
13676 * Fires when the mouse leaves an
13677 * @param {Calendar} this
13680 'eventleave': true,
13682 * @event eventclick
13683 * Fires when the mouse click an
13684 * @param {Calendar} this
13693 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13696 * @cfg {Number} startDay
13697 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13705 getAutoCreate : function(){
13708 var fc_button = function(name, corner, style, content ) {
13709 return Roo.apply({},{
13711 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13713 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13716 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13727 style : 'width:100%',
13734 cls : 'fc-header-left',
13736 fc_button('prev', 'left', 'arrow', '‹' ),
13737 fc_button('next', 'right', 'arrow', '›' ),
13738 { tag: 'span', cls: 'fc-header-space' },
13739 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13747 cls : 'fc-header-center',
13751 cls: 'fc-header-title',
13754 html : 'month / year'
13762 cls : 'fc-header-right',
13764 /* fc_button('month', 'left', '', 'month' ),
13765 fc_button('week', '', '', 'week' ),
13766 fc_button('day', 'right', '', 'day' )
13778 header = this.header;
13781 var cal_heads = function() {
13783 // fixme - handle this.
13785 for (var i =0; i < Date.dayNames.length; i++) {
13786 var d = Date.dayNames[i];
13789 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13790 html : d.substring(0,3)
13794 ret[0].cls += ' fc-first';
13795 ret[6].cls += ' fc-last';
13798 var cal_cell = function(n) {
13801 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13806 cls: 'fc-day-number',
13810 cls: 'fc-day-content',
13814 style: 'position: relative;' // height: 17px;
13826 var cal_rows = function() {
13829 for (var r = 0; r < 6; r++) {
13836 for (var i =0; i < Date.dayNames.length; i++) {
13837 var d = Date.dayNames[i];
13838 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13841 row.cn[0].cls+=' fc-first';
13842 row.cn[0].cn[0].style = 'min-height:90px';
13843 row.cn[6].cls+=' fc-last';
13847 ret[0].cls += ' fc-first';
13848 ret[4].cls += ' fc-prev-last';
13849 ret[5].cls += ' fc-last';
13856 cls: 'fc-border-separate',
13857 style : 'width:100%',
13865 cls : 'fc-first fc-last',
13883 cls : 'fc-content',
13884 style : "position: relative;",
13887 cls : 'fc-view fc-view-month fc-grid',
13888 style : 'position: relative',
13889 unselectable : 'on',
13892 cls : 'fc-event-container',
13893 style : 'position:absolute;z-index:8;top:0;left:0;'
13911 initEvents : function()
13914 throw "can not find store for calendar";
13920 style: "text-align:center",
13924 style: "background-color:white;width:50%;margin:250 auto",
13928 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13939 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13941 var size = this.el.select('.fc-content', true).first().getSize();
13942 this.maskEl.setSize(size.width, size.height);
13943 this.maskEl.enableDisplayMode("block");
13944 if(!this.loadMask){
13945 this.maskEl.hide();
13948 this.store = Roo.factory(this.store, Roo.data);
13949 this.store.on('load', this.onLoad, this);
13950 this.store.on('beforeload', this.onBeforeLoad, this);
13954 this.cells = this.el.select('.fc-day',true);
13955 //Roo.log(this.cells);
13956 this.textNodes = this.el.query('.fc-day-number');
13957 this.cells.addClassOnOver('fc-state-hover');
13959 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13960 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13961 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13962 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13964 this.on('monthchange', this.onMonthChange, this);
13966 this.update(new Date().clearTime());
13969 resize : function() {
13970 var sz = this.el.getSize();
13972 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13973 this.el.select('.fc-day-content div',true).setHeight(34);
13978 showPrevMonth : function(e){
13979 this.update(this.activeDate.add("mo", -1));
13981 showToday : function(e){
13982 this.update(new Date().clearTime());
13985 showNextMonth : function(e){
13986 this.update(this.activeDate.add("mo", 1));
13990 showPrevYear : function(){
13991 this.update(this.activeDate.add("y", -1));
13995 showNextYear : function(){
13996 this.update(this.activeDate.add("y", 1));
14001 update : function(date)
14003 var vd = this.activeDate;
14004 this.activeDate = date;
14005 // if(vd && this.el){
14006 // var t = date.getTime();
14007 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14008 // Roo.log('using add remove');
14010 // this.fireEvent('monthchange', this, date);
14012 // this.cells.removeClass("fc-state-highlight");
14013 // this.cells.each(function(c){
14014 // if(c.dateValue == t){
14015 // c.addClass("fc-state-highlight");
14016 // setTimeout(function(){
14017 // try{c.dom.firstChild.focus();}catch(e){}
14027 var days = date.getDaysInMonth();
14029 var firstOfMonth = date.getFirstDateOfMonth();
14030 var startingPos = firstOfMonth.getDay()-this.startDay;
14032 if(startingPos < this.startDay){
14036 var pm = date.add(Date.MONTH, -1);
14037 var prevStart = pm.getDaysInMonth()-startingPos;
14039 this.cells = this.el.select('.fc-day',true);
14040 this.textNodes = this.el.query('.fc-day-number');
14041 this.cells.addClassOnOver('fc-state-hover');
14043 var cells = this.cells.elements;
14044 var textEls = this.textNodes;
14046 Roo.each(cells, function(cell){
14047 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14050 days += startingPos;
14052 // convert everything to numbers so it's fast
14053 var day = 86400000;
14054 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14057 //Roo.log(prevStart);
14059 var today = new Date().clearTime().getTime();
14060 var sel = date.clearTime().getTime();
14061 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14062 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14063 var ddMatch = this.disabledDatesRE;
14064 var ddText = this.disabledDatesText;
14065 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14066 var ddaysText = this.disabledDaysText;
14067 var format = this.format;
14069 var setCellClass = function(cal, cell){
14073 //Roo.log('set Cell Class');
14075 var t = d.getTime();
14079 cell.dateValue = t;
14081 cell.className += " fc-today";
14082 cell.className += " fc-state-highlight";
14083 cell.title = cal.todayText;
14086 // disable highlight in other month..
14087 //cell.className += " fc-state-highlight";
14092 cell.className = " fc-state-disabled";
14093 cell.title = cal.minText;
14097 cell.className = " fc-state-disabled";
14098 cell.title = cal.maxText;
14102 if(ddays.indexOf(d.getDay()) != -1){
14103 cell.title = ddaysText;
14104 cell.className = " fc-state-disabled";
14107 if(ddMatch && format){
14108 var fvalue = d.dateFormat(format);
14109 if(ddMatch.test(fvalue)){
14110 cell.title = ddText.replace("%0", fvalue);
14111 cell.className = " fc-state-disabled";
14115 if (!cell.initialClassName) {
14116 cell.initialClassName = cell.dom.className;
14119 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14124 for(; i < startingPos; i++) {
14125 textEls[i].innerHTML = (++prevStart);
14126 d.setDate(d.getDate()+1);
14128 cells[i].className = "fc-past fc-other-month";
14129 setCellClass(this, cells[i]);
14134 for(; i < days; i++){
14135 intDay = i - startingPos + 1;
14136 textEls[i].innerHTML = (intDay);
14137 d.setDate(d.getDate()+1);
14139 cells[i].className = ''; // "x-date-active";
14140 setCellClass(this, cells[i]);
14144 for(; i < 42; i++) {
14145 textEls[i].innerHTML = (++extraDays);
14146 d.setDate(d.getDate()+1);
14148 cells[i].className = "fc-future fc-other-month";
14149 setCellClass(this, cells[i]);
14152 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14154 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14156 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14157 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14159 if(totalRows != 6){
14160 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14161 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14164 this.fireEvent('monthchange', this, date);
14168 if(!this.internalRender){
14169 var main = this.el.dom.firstChild;
14170 var w = main.offsetWidth;
14171 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14172 Roo.fly(main).setWidth(w);
14173 this.internalRender = true;
14174 // opera does not respect the auto grow header center column
14175 // then, after it gets a width opera refuses to recalculate
14176 // without a second pass
14177 if(Roo.isOpera && !this.secondPass){
14178 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14179 this.secondPass = true;
14180 this.update.defer(10, this, [date]);
14187 findCell : function(dt) {
14188 dt = dt.clearTime().getTime();
14190 this.cells.each(function(c){
14191 //Roo.log("check " +c.dateValue + '?=' + dt);
14192 if(c.dateValue == dt){
14202 findCells : function(ev) {
14203 var s = ev.start.clone().clearTime().getTime();
14205 var e= ev.end.clone().clearTime().getTime();
14208 this.cells.each(function(c){
14209 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14211 if(c.dateValue > e){
14214 if(c.dateValue < s){
14223 // findBestRow: function(cells)
14227 // for (var i =0 ; i < cells.length;i++) {
14228 // ret = Math.max(cells[i].rows || 0,ret);
14235 addItem : function(ev)
14237 // look for vertical location slot in
14238 var cells = this.findCells(ev);
14240 // ev.row = this.findBestRow(cells);
14242 // work out the location.
14246 for(var i =0; i < cells.length; i++) {
14248 cells[i].row = cells[0].row;
14251 cells[i].row = cells[i].row + 1;
14261 if (crow.start.getY() == cells[i].getY()) {
14263 crow.end = cells[i];
14280 cells[0].events.push(ev);
14282 this.calevents.push(ev);
14285 clearEvents: function() {
14287 if(!this.calevents){
14291 Roo.each(this.cells.elements, function(c){
14297 Roo.each(this.calevents, function(e) {
14298 Roo.each(e.els, function(el) {
14299 el.un('mouseenter' ,this.onEventEnter, this);
14300 el.un('mouseleave' ,this.onEventLeave, this);
14305 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14311 renderEvents: function()
14315 this.cells.each(function(c) {
14324 if(c.row != c.events.length){
14325 r = 4 - (4 - (c.row - c.events.length));
14328 c.events = ev.slice(0, r);
14329 c.more = ev.slice(r);
14331 if(c.more.length && c.more.length == 1){
14332 c.events.push(c.more.pop());
14335 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14339 this.cells.each(function(c) {
14341 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14344 for (var e = 0; e < c.events.length; e++){
14345 var ev = c.events[e];
14346 var rows = ev.rows;
14348 for(var i = 0; i < rows.length; i++) {
14350 // how many rows should it span..
14353 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14354 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14356 unselectable : "on",
14359 cls: 'fc-event-inner',
14363 // cls: 'fc-event-time',
14364 // html : cells.length > 1 ? '' : ev.time
14368 cls: 'fc-event-title',
14369 html : String.format('{0}', ev.title)
14376 cls: 'ui-resizable-handle ui-resizable-e',
14377 html : '  '
14384 cfg.cls += ' fc-event-start';
14386 if ((i+1) == rows.length) {
14387 cfg.cls += ' fc-event-end';
14390 var ctr = _this.el.select('.fc-event-container',true).first();
14391 var cg = ctr.createChild(cfg);
14393 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14394 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14396 var r = (c.more.length) ? 1 : 0;
14397 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14398 cg.setWidth(ebox.right - sbox.x -2);
14400 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14401 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14402 cg.on('click', _this.onEventClick, _this, ev);
14413 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14414 style : 'position: absolute',
14415 unselectable : "on",
14418 cls: 'fc-event-inner',
14422 cls: 'fc-event-title',
14430 cls: 'ui-resizable-handle ui-resizable-e',
14431 html : '  '
14437 var ctr = _this.el.select('.fc-event-container',true).first();
14438 var cg = ctr.createChild(cfg);
14440 var sbox = c.select('.fc-day-content',true).first().getBox();
14441 var ebox = c.select('.fc-day-content',true).first().getBox();
14443 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14444 cg.setWidth(ebox.right - sbox.x -2);
14446 cg.on('click', _this.onMoreEventClick, _this, c.more);
14456 onEventEnter: function (e, el,event,d) {
14457 this.fireEvent('evententer', this, el, event);
14460 onEventLeave: function (e, el,event,d) {
14461 this.fireEvent('eventleave', this, el, event);
14464 onEventClick: function (e, el,event,d) {
14465 this.fireEvent('eventclick', this, el, event);
14468 onMonthChange: function () {
14472 onMoreEventClick: function(e, el, more)
14476 this.calpopover.placement = 'right';
14477 this.calpopover.setTitle('More');
14479 this.calpopover.setContent('');
14481 var ctr = this.calpopover.el.select('.popover-content', true).first();
14483 Roo.each(more, function(m){
14485 cls : 'fc-event-hori fc-event-draggable',
14488 var cg = ctr.createChild(cfg);
14490 cg.on('click', _this.onEventClick, _this, m);
14493 this.calpopover.show(el);
14498 onLoad: function ()
14500 this.calevents = [];
14503 if(this.store.getCount() > 0){
14504 this.store.data.each(function(d){
14507 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14508 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14509 time : d.data.start_time,
14510 title : d.data.title,
14511 description : d.data.description,
14512 venue : d.data.venue
14517 this.renderEvents();
14519 if(this.calevents.length && this.loadMask){
14520 this.maskEl.hide();
14524 onBeforeLoad: function()
14526 this.clearEvents();
14528 this.maskEl.show();
14542 * @class Roo.bootstrap.Popover
14543 * @extends Roo.bootstrap.Component
14544 * Bootstrap Popover class
14545 * @cfg {String} html contents of the popover (or false to use children..)
14546 * @cfg {String} title of popover (or false to hide)
14547 * @cfg {String} placement how it is placed
14548 * @cfg {String} trigger click || hover (or false to trigger manually)
14549 * @cfg {String} over what (parent or false to trigger manually.)
14550 * @cfg {Number} delay - delay before showing
14553 * Create a new Popover
14554 * @param {Object} config The config object
14557 Roo.bootstrap.Popover = function(config){
14558 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14561 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14563 title: 'Fill in a title',
14566 placement : 'right',
14567 trigger : 'hover', // hover
14573 can_build_overlaid : false,
14575 getChildContainer : function()
14577 return this.el.select('.popover-content',true).first();
14580 getAutoCreate : function(){
14581 Roo.log('make popover?');
14583 cls : 'popover roo-dynamic',
14584 style: 'display:block',
14590 cls : 'popover-inner',
14594 cls: 'popover-title',
14598 cls : 'popover-content',
14609 setTitle: function(str)
14611 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14613 setContent: function(str)
14615 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14617 // as it get's added to the bottom of the page.
14618 onRender : function(ct, position)
14620 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14622 var cfg = Roo.apply({}, this.getAutoCreate());
14626 cfg.cls += ' ' + this.cls;
14629 cfg.style = this.style;
14631 Roo.log("adding to ")
14632 this.el = Roo.get(document.body).createChild(cfg, position);
14638 initEvents : function()
14640 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14641 this.el.enableDisplayMode('block');
14643 if (this.over === false) {
14646 if (this.triggers === false) {
14649 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14650 var triggers = this.trigger ? this.trigger.split(' ') : [];
14651 Roo.each(triggers, function(trigger) {
14653 if (trigger == 'click') {
14654 on_el.on('click', this.toggle, this);
14655 } else if (trigger != 'manual') {
14656 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14657 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14659 on_el.on(eventIn ,this.enter, this);
14660 on_el.on(eventOut, this.leave, this);
14671 toggle : function () {
14672 this.hoverState == 'in' ? this.leave() : this.enter();
14675 enter : function () {
14678 clearTimeout(this.timeout);
14680 this.hoverState = 'in';
14682 if (!this.delay || !this.delay.show) {
14687 this.timeout = setTimeout(function () {
14688 if (_t.hoverState == 'in') {
14691 }, this.delay.show)
14693 leave : function() {
14694 clearTimeout(this.timeout);
14696 this.hoverState = 'out';
14698 if (!this.delay || !this.delay.hide) {
14703 this.timeout = setTimeout(function () {
14704 if (_t.hoverState == 'out') {
14707 }, this.delay.hide)
14710 show : function (on_el)
14713 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14716 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14717 if (this.html !== false) {
14718 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14720 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14721 if (!this.title.length) {
14722 this.el.select('.popover-title',true).hide();
14725 var placement = typeof this.placement == 'function' ?
14726 this.placement.call(this, this.el, on_el) :
14729 var autoToken = /\s?auto?\s?/i;
14730 var autoPlace = autoToken.test(placement);
14732 placement = placement.replace(autoToken, '') || 'top';
14736 //this.el.setXY([0,0]);
14738 this.el.dom.style.display='block';
14739 this.el.addClass(placement);
14741 //this.el.appendTo(on_el);
14743 var p = this.getPosition();
14744 var box = this.el.getBox();
14749 var align = Roo.bootstrap.Popover.alignment[placement];
14750 this.el.alignTo(on_el, align[0],align[1]);
14751 //var arrow = this.el.select('.arrow',true).first();
14752 //arrow.set(align[2],
14754 this.el.addClass('in');
14755 this.hoverState = null;
14757 if (this.el.hasClass('fade')) {
14764 this.el.setXY([0,0]);
14765 this.el.removeClass('in');
14772 Roo.bootstrap.Popover.alignment = {
14773 'left' : ['r-l', [-10,0], 'right'],
14774 'right' : ['l-r', [10,0], 'left'],
14775 'bottom' : ['t-b', [0,10], 'top'],
14776 'top' : [ 'b-t', [0,-10], 'bottom']
14787 * @class Roo.bootstrap.Progress
14788 * @extends Roo.bootstrap.Component
14789 * Bootstrap Progress class
14790 * @cfg {Boolean} striped striped of the progress bar
14791 * @cfg {Boolean} active animated of the progress bar
14795 * Create a new Progress
14796 * @param {Object} config The config object
14799 Roo.bootstrap.Progress = function(config){
14800 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14803 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14808 getAutoCreate : function(){
14816 cfg.cls += ' progress-striped';
14820 cfg.cls += ' active';
14839 * @class Roo.bootstrap.ProgressBar
14840 * @extends Roo.bootstrap.Component
14841 * Bootstrap ProgressBar class
14842 * @cfg {Number} aria_valuenow aria-value now
14843 * @cfg {Number} aria_valuemin aria-value min
14844 * @cfg {Number} aria_valuemax aria-value max
14845 * @cfg {String} label label for the progress bar
14846 * @cfg {String} panel (success | info | warning | danger )
14847 * @cfg {String} role role of the progress bar
14848 * @cfg {String} sr_only text
14852 * Create a new ProgressBar
14853 * @param {Object} config The config object
14856 Roo.bootstrap.ProgressBar = function(config){
14857 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14860 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14864 aria_valuemax : 100,
14870 getAutoCreate : function()
14875 cls: 'progress-bar',
14876 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14888 cfg.role = this.role;
14891 if(this.aria_valuenow){
14892 cfg['aria-valuenow'] = this.aria_valuenow;
14895 if(this.aria_valuemin){
14896 cfg['aria-valuemin'] = this.aria_valuemin;
14899 if(this.aria_valuemax){
14900 cfg['aria-valuemax'] = this.aria_valuemax;
14903 if(this.label && !this.sr_only){
14904 cfg.html = this.label;
14908 cfg.cls += ' progress-bar-' + this.panel;
14914 update : function(aria_valuenow)
14916 this.aria_valuenow = aria_valuenow;
14918 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14933 * @class Roo.bootstrap.TabGroup
14934 * @extends Roo.bootstrap.Column
14935 * Bootstrap Column class
14936 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14937 * @cfg {Boolean} carousel true to make the group behave like a carousel
14938 * @cfg {Number} bullets show the panel pointer.. default 0
14939 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14940 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14941 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14944 * Create a new TabGroup
14945 * @param {Object} config The config object
14948 Roo.bootstrap.TabGroup = function(config){
14949 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14951 this.navId = Roo.id();
14954 Roo.bootstrap.TabGroup.register(this);
14958 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14961 transition : false,
14966 slideOnTouch : false,
14968 getAutoCreate : function()
14970 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14972 cfg.cls += ' tab-content';
14974 Roo.log('get auto create...............');
14976 if (this.carousel) {
14977 cfg.cls += ' carousel slide';
14980 cls : 'carousel-inner'
14983 if(this.bullets > 0 && !Roo.isTouch){
14986 cls : 'carousel-bullets',
14990 if(this.bullets_cls){
14991 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14994 for (var i = 0; i < this.bullets; i++){
14996 cls : 'bullet bullet-' + i
15004 cfg.cn[0].cn = bullets;
15011 initEvents: function()
15013 Roo.log('-------- init events on tab group ---------');
15015 if(this.bullets > 0 && !Roo.isTouch){
15021 if(Roo.isTouch && this.slideOnTouch){
15022 this.el.on("touchstart", this.onTouchStart, this);
15025 if(this.autoslide){
15028 this.slideFn = window.setInterval(function() {
15029 _this.showPanelNext();
15035 onTouchStart : function(e, el, o)
15037 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15041 this.showPanelNext();
15044 getChildContainer : function()
15046 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15050 * register a Navigation item
15051 * @param {Roo.bootstrap.NavItem} the navitem to add
15053 register : function(item)
15055 this.tabs.push( item);
15056 item.navId = this.navId; // not really needed..
15060 getActivePanel : function()
15063 Roo.each(this.tabs, function(t) {
15073 getPanelByName : function(n)
15076 Roo.each(this.tabs, function(t) {
15077 if (t.tabId == n) {
15085 indexOfPanel : function(p)
15088 Roo.each(this.tabs, function(t,i) {
15089 if (t.tabId == p.tabId) {
15098 * show a specific panel
15099 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15100 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15102 showPanel : function (pan)
15104 if(this.transition){
15105 Roo.log("waiting for the transitionend");
15109 if (typeof(pan) == 'number') {
15110 pan = this.tabs[pan];
15112 if (typeof(pan) == 'string') {
15113 pan = this.getPanelByName(pan);
15115 if (pan.tabId == this.getActivePanel().tabId) {
15118 var cur = this.getActivePanel();
15120 if (false === cur.fireEvent('beforedeactivate')) {
15124 if(this.bullets > 0 && !Roo.isTouch){
15125 this.setActiveBullet(this.indexOfPanel(pan));
15128 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15130 this.transition = true;
15131 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15132 var lr = dir == 'next' ? 'left' : 'right';
15133 pan.el.addClass(dir); // or prev
15134 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15135 cur.el.addClass(lr); // or right
15136 pan.el.addClass(lr);
15139 cur.el.on('transitionend', function() {
15140 Roo.log("trans end?");
15142 pan.el.removeClass([lr,dir]);
15143 pan.setActive(true);
15145 cur.el.removeClass([lr]);
15146 cur.setActive(false);
15148 _this.transition = false;
15150 }, this, { single: true } );
15155 cur.setActive(false);
15156 pan.setActive(true);
15161 showPanelNext : function()
15163 var i = this.indexOfPanel(this.getActivePanel());
15165 if (i >= this.tabs.length - 1 && !this.autoslide) {
15169 if (i >= this.tabs.length - 1 && this.autoslide) {
15173 this.showPanel(this.tabs[i+1]);
15176 showPanelPrev : function()
15178 var i = this.indexOfPanel(this.getActivePanel());
15180 if (i < 1 && !this.autoslide) {
15184 if (i < 1 && this.autoslide) {
15185 i = this.tabs.length;
15188 this.showPanel(this.tabs[i-1]);
15191 initBullet : function()
15199 for (var i = 0; i < this.bullets; i++){
15200 var bullet = this.el.select('.bullet-' + i, true).first();
15206 bullet.on('click', (function(e, el, o, ii, t){
15208 e.preventDefault();
15210 _this.showPanel(ii);
15212 if(_this.autoslide && _this.slideFn){
15213 clearInterval(_this.slideFn);
15214 _this.slideFn = window.setInterval(function() {
15215 _this.showPanelNext();
15219 }).createDelegate(this, [i, bullet], true));
15223 setActiveBullet : function(i)
15229 Roo.each(this.el.select('.bullet', true).elements, function(el){
15230 el.removeClass('selected');
15233 var bullet = this.el.select('.bullet-' + i, true).first();
15239 bullet.addClass('selected');
15250 Roo.apply(Roo.bootstrap.TabGroup, {
15254 * register a Navigation Group
15255 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15257 register : function(navgrp)
15259 this.groups[navgrp.navId] = navgrp;
15263 * fetch a Navigation Group based on the navigation ID
15264 * if one does not exist , it will get created.
15265 * @param {string} the navgroup to add
15266 * @returns {Roo.bootstrap.NavGroup} the navgroup
15268 get: function(navId) {
15269 if (typeof(this.groups[navId]) == 'undefined') {
15270 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15272 return this.groups[navId] ;
15287 * @class Roo.bootstrap.TabPanel
15288 * @extends Roo.bootstrap.Component
15289 * Bootstrap TabPanel class
15290 * @cfg {Boolean} active panel active
15291 * @cfg {String} html panel content
15292 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15293 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15297 * Create a new TabPanel
15298 * @param {Object} config The config object
15301 Roo.bootstrap.TabPanel = function(config){
15302 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15306 * Fires when the active status changes
15307 * @param {Roo.bootstrap.TabPanel} this
15308 * @param {Boolean} state the new state
15313 * @event beforedeactivate
15314 * Fires before a tab is de-activated - can be used to do validation on a form.
15315 * @param {Roo.bootstrap.TabPanel} this
15316 * @return {Boolean} false if there is an error
15319 'beforedeactivate': true
15322 this.tabId = this.tabId || Roo.id();
15326 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15333 getAutoCreate : function(){
15336 // item is needed for carousel - not sure if it has any effect otherwise
15337 cls: 'tab-pane item',
15338 html: this.html || ''
15342 cfg.cls += ' active';
15346 cfg.tabId = this.tabId;
15353 initEvents: function()
15355 Roo.log('-------- init events on tab panel ---------');
15357 var p = this.parent();
15358 this.navId = this.navId || p.navId;
15360 if (typeof(this.navId) != 'undefined') {
15361 // not really needed.. but just in case.. parent should be a NavGroup.
15362 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15363 Roo.log(['register', tg, this]);
15366 var i = tg.tabs.length - 1;
15368 if(this.active && tg.bullets > 0 && i < tg.bullets){
15369 tg.setActiveBullet(i);
15376 onRender : function(ct, position)
15378 // Roo.log("Call onRender: " + this.xtype);
15380 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15388 setActive: function(state)
15390 Roo.log("panel - set active " + this.tabId + "=" + state);
15392 this.active = state;
15394 this.el.removeClass('active');
15396 } else if (!this.el.hasClass('active')) {
15397 this.el.addClass('active');
15400 this.fireEvent('changed', this, state);
15417 * @class Roo.bootstrap.DateField
15418 * @extends Roo.bootstrap.Input
15419 * Bootstrap DateField class
15420 * @cfg {Number} weekStart default 0
15421 * @cfg {String} viewMode default empty, (months|years)
15422 * @cfg {String} minViewMode default empty, (months|years)
15423 * @cfg {Number} startDate default -Infinity
15424 * @cfg {Number} endDate default Infinity
15425 * @cfg {Boolean} todayHighlight default false
15426 * @cfg {Boolean} todayBtn default false
15427 * @cfg {Boolean} calendarWeeks default false
15428 * @cfg {Object} daysOfWeekDisabled default empty
15429 * @cfg {Boolean} singleMode default false (true | false)
15431 * @cfg {Boolean} keyboardNavigation default true
15432 * @cfg {String} language default en
15435 * Create a new DateField
15436 * @param {Object} config The config object
15439 Roo.bootstrap.DateField = function(config){
15440 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15444 * Fires when this field show.
15445 * @param {Roo.bootstrap.DateField} this
15446 * @param {Mixed} date The date value
15451 * Fires when this field hide.
15452 * @param {Roo.bootstrap.DateField} this
15453 * @param {Mixed} date The date value
15458 * Fires when select a date.
15459 * @param {Roo.bootstrap.DateField} this
15460 * @param {Mixed} date The date value
15466 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15469 * @cfg {String} format
15470 * The default date format string which can be overriden for localization support. The format must be
15471 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15475 * @cfg {String} altFormats
15476 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15477 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15479 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15487 todayHighlight : false,
15493 keyboardNavigation: true,
15495 calendarWeeks: false,
15497 startDate: -Infinity,
15501 daysOfWeekDisabled: [],
15505 singleMode : false,
15507 UTCDate: function()
15509 return new Date(Date.UTC.apply(Date, arguments));
15512 UTCToday: function()
15514 var today = new Date();
15515 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15518 getDate: function() {
15519 var d = this.getUTCDate();
15520 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15523 getUTCDate: function() {
15527 setDate: function(d) {
15528 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15531 setUTCDate: function(d) {
15533 this.setValue(this.formatDate(this.date));
15536 onRender: function(ct, position)
15539 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15541 this.language = this.language || 'en';
15542 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15543 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15545 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15546 this.format = this.format || 'm/d/y';
15547 this.isInline = false;
15548 this.isInput = true;
15549 this.component = this.el.select('.add-on', true).first() || false;
15550 this.component = (this.component && this.component.length === 0) ? false : this.component;
15551 this.hasInput = this.component && this.inputEL().length;
15553 if (typeof(this.minViewMode === 'string')) {
15554 switch (this.minViewMode) {
15556 this.minViewMode = 1;
15559 this.minViewMode = 2;
15562 this.minViewMode = 0;
15567 if (typeof(this.viewMode === 'string')) {
15568 switch (this.viewMode) {
15581 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15583 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15585 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15587 this.picker().on('mousedown', this.onMousedown, this);
15588 this.picker().on('click', this.onClick, this);
15590 this.picker().addClass('datepicker-dropdown');
15592 this.startViewMode = this.viewMode;
15594 if(this.singleMode){
15595 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15596 v.setVisibilityMode(Roo.Element.DISPLAY)
15600 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15601 v.setStyle('width', '189px');
15605 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15606 if(!this.calendarWeeks){
15611 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15612 v.attr('colspan', function(i, val){
15613 return parseInt(val) + 1;
15618 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15620 this.setStartDate(this.startDate);
15621 this.setEndDate(this.endDate);
15623 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15630 if(this.isInline) {
15635 picker : function()
15637 return this.pickerEl;
15638 // return this.el.select('.datepicker', true).first();
15641 fillDow: function()
15643 var dowCnt = this.weekStart;
15652 if(this.calendarWeeks){
15660 while (dowCnt < this.weekStart + 7) {
15664 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15668 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15671 fillMonths: function()
15674 var months = this.picker().select('>.datepicker-months td', true).first();
15676 months.dom.innerHTML = '';
15682 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15685 months.createChild(month);
15692 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;
15694 if (this.date < this.startDate) {
15695 this.viewDate = new Date(this.startDate);
15696 } else if (this.date > this.endDate) {
15697 this.viewDate = new Date(this.endDate);
15699 this.viewDate = new Date(this.date);
15707 var d = new Date(this.viewDate),
15708 year = d.getUTCFullYear(),
15709 month = d.getUTCMonth(),
15710 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15711 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15712 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15713 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15714 currentDate = this.date && this.date.valueOf(),
15715 today = this.UTCToday();
15717 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15719 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15721 // this.picker.select('>tfoot th.today').
15722 // .text(dates[this.language].today)
15723 // .toggle(this.todayBtn !== false);
15725 this.updateNavArrows();
15728 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15730 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15732 prevMonth.setUTCDate(day);
15734 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15736 var nextMonth = new Date(prevMonth);
15738 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15740 nextMonth = nextMonth.valueOf();
15742 var fillMonths = false;
15744 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15746 while(prevMonth.valueOf() < nextMonth) {
15749 if (prevMonth.getUTCDay() === this.weekStart) {
15751 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15759 if(this.calendarWeeks){
15760 // ISO 8601: First week contains first thursday.
15761 // ISO also states week starts on Monday, but we can be more abstract here.
15763 // Start of current week: based on weekstart/current date
15764 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15765 // Thursday of this week
15766 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15767 // First Thursday of year, year from thursday
15768 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15769 // Calendar week: ms between thursdays, div ms per day, div 7 days
15770 calWeek = (th - yth) / 864e5 / 7 + 1;
15772 fillMonths.cn.push({
15780 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15782 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15785 if (this.todayHighlight &&
15786 prevMonth.getUTCFullYear() == today.getFullYear() &&
15787 prevMonth.getUTCMonth() == today.getMonth() &&
15788 prevMonth.getUTCDate() == today.getDate()) {
15789 clsName += ' today';
15792 if (currentDate && prevMonth.valueOf() === currentDate) {
15793 clsName += ' active';
15796 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15797 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15798 clsName += ' disabled';
15801 fillMonths.cn.push({
15803 cls: 'day ' + clsName,
15804 html: prevMonth.getDate()
15807 prevMonth.setDate(prevMonth.getDate()+1);
15810 var currentYear = this.date && this.date.getUTCFullYear();
15811 var currentMonth = this.date && this.date.getUTCMonth();
15813 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15815 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15816 v.removeClass('active');
15818 if(currentYear === year && k === currentMonth){
15819 v.addClass('active');
15822 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15823 v.addClass('disabled');
15829 year = parseInt(year/10, 10) * 10;
15831 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15833 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15836 for (var i = -1; i < 11; i++) {
15837 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15839 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15847 showMode: function(dir)
15850 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15853 Roo.each(this.picker().select('>div',true).elements, function(v){
15854 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15857 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15862 if(this.isInline) return;
15864 this.picker().removeClass(['bottom', 'top']);
15866 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15868 * place to the top of element!
15872 this.picker().addClass('top');
15873 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15878 this.picker().addClass('bottom');
15880 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15883 parseDate : function(value)
15885 if(!value || value instanceof Date){
15888 var v = Date.parseDate(value, this.format);
15889 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15890 v = Date.parseDate(value, 'Y-m-d');
15892 if(!v && this.altFormats){
15893 if(!this.altFormatsArray){
15894 this.altFormatsArray = this.altFormats.split("|");
15896 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15897 v = Date.parseDate(value, this.altFormatsArray[i]);
15903 formatDate : function(date, fmt)
15905 return (!date || !(date instanceof Date)) ?
15906 date : date.dateFormat(fmt || this.format);
15909 onFocus : function()
15911 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15915 onBlur : function()
15917 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15919 var d = this.inputEl().getValue();
15928 this.picker().show();
15932 this.fireEvent('show', this, this.date);
15937 if(this.isInline) return;
15938 this.picker().hide();
15939 this.viewMode = this.startViewMode;
15942 this.fireEvent('hide', this, this.date);
15946 onMousedown: function(e)
15948 e.stopPropagation();
15949 e.preventDefault();
15954 Roo.bootstrap.DateField.superclass.keyup.call(this);
15958 setValue: function(v)
15961 // v can be a string or a date..
15964 var d = new Date(this.parseDate(v) ).clearTime();
15966 if(isNaN(d.getTime())){
15967 this.date = this.viewDate = '';
15968 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15972 v = this.formatDate(d);
15974 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15976 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15980 this.fireEvent('select', this, this.date);
15984 getValue: function()
15986 return this.formatDate(this.date);
15989 fireKey: function(e)
15991 if (!this.picker().isVisible()){
15992 if (e.keyCode == 27) // allow escape to hide and re-show picker
15997 var dateChanged = false,
15999 newDate, newViewDate;
16004 e.preventDefault();
16008 if (!this.keyboardNavigation) break;
16009 dir = e.keyCode == 37 ? -1 : 1;
16012 newDate = this.moveYear(this.date, dir);
16013 newViewDate = this.moveYear(this.viewDate, dir);
16014 } else if (e.shiftKey){
16015 newDate = this.moveMonth(this.date, dir);
16016 newViewDate = this.moveMonth(this.viewDate, dir);
16018 newDate = new Date(this.date);
16019 newDate.setUTCDate(this.date.getUTCDate() + dir);
16020 newViewDate = new Date(this.viewDate);
16021 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16023 if (this.dateWithinRange(newDate)){
16024 this.date = newDate;
16025 this.viewDate = newViewDate;
16026 this.setValue(this.formatDate(this.date));
16028 e.preventDefault();
16029 dateChanged = true;
16034 if (!this.keyboardNavigation) break;
16035 dir = e.keyCode == 38 ? -1 : 1;
16037 newDate = this.moveYear(this.date, dir);
16038 newViewDate = this.moveYear(this.viewDate, dir);
16039 } else if (e.shiftKey){
16040 newDate = this.moveMonth(this.date, dir);
16041 newViewDate = this.moveMonth(this.viewDate, dir);
16043 newDate = new Date(this.date);
16044 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16045 newViewDate = new Date(this.viewDate);
16046 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16048 if (this.dateWithinRange(newDate)){
16049 this.date = newDate;
16050 this.viewDate = newViewDate;
16051 this.setValue(this.formatDate(this.date));
16053 e.preventDefault();
16054 dateChanged = true;
16058 this.setValue(this.formatDate(this.date));
16060 e.preventDefault();
16063 this.setValue(this.formatDate(this.date));
16077 onClick: function(e)
16079 e.stopPropagation();
16080 e.preventDefault();
16082 var target = e.getTarget();
16084 if(target.nodeName.toLowerCase() === 'i'){
16085 target = Roo.get(target).dom.parentNode;
16088 var nodeName = target.nodeName;
16089 var className = target.className;
16090 var html = target.innerHTML;
16091 //Roo.log(nodeName);
16093 switch(nodeName.toLowerCase()) {
16095 switch(className) {
16101 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16102 switch(this.viewMode){
16104 this.viewDate = this.moveMonth(this.viewDate, dir);
16108 this.viewDate = this.moveYear(this.viewDate, dir);
16114 var date = new Date();
16115 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16117 this.setValue(this.formatDate(this.date));
16124 if (className.indexOf('disabled') < 0) {
16125 this.viewDate.setUTCDate(1);
16126 if (className.indexOf('month') > -1) {
16127 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16129 var year = parseInt(html, 10) || 0;
16130 this.viewDate.setUTCFullYear(year);
16134 if(this.singleMode){
16135 this.setValue(this.formatDate(this.viewDate));
16146 //Roo.log(className);
16147 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16148 var day = parseInt(html, 10) || 1;
16149 var year = this.viewDate.getUTCFullYear(),
16150 month = this.viewDate.getUTCMonth();
16152 if (className.indexOf('old') > -1) {
16159 } else if (className.indexOf('new') > -1) {
16167 //Roo.log([year,month,day]);
16168 this.date = this.UTCDate(year, month, day,0,0,0,0);
16169 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16171 //Roo.log(this.formatDate(this.date));
16172 this.setValue(this.formatDate(this.date));
16179 setStartDate: function(startDate)
16181 this.startDate = startDate || -Infinity;
16182 if (this.startDate !== -Infinity) {
16183 this.startDate = this.parseDate(this.startDate);
16186 this.updateNavArrows();
16189 setEndDate: function(endDate)
16191 this.endDate = endDate || Infinity;
16192 if (this.endDate !== Infinity) {
16193 this.endDate = this.parseDate(this.endDate);
16196 this.updateNavArrows();
16199 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16201 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16202 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16203 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16205 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16206 return parseInt(d, 10);
16209 this.updateNavArrows();
16212 updateNavArrows: function()
16214 if(this.singleMode){
16218 var d = new Date(this.viewDate),
16219 year = d.getUTCFullYear(),
16220 month = d.getUTCMonth();
16222 Roo.each(this.picker().select('.prev', true).elements, function(v){
16224 switch (this.viewMode) {
16227 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16233 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16240 Roo.each(this.picker().select('.next', true).elements, function(v){
16242 switch (this.viewMode) {
16245 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16251 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16259 moveMonth: function(date, dir)
16261 if (!dir) return date;
16262 var new_date = new Date(date.valueOf()),
16263 day = new_date.getUTCDate(),
16264 month = new_date.getUTCMonth(),
16265 mag = Math.abs(dir),
16267 dir = dir > 0 ? 1 : -1;
16270 // If going back one month, make sure month is not current month
16271 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16273 return new_date.getUTCMonth() == month;
16275 // If going forward one month, make sure month is as expected
16276 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16278 return new_date.getUTCMonth() != new_month;
16280 new_month = month + dir;
16281 new_date.setUTCMonth(new_month);
16282 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16283 if (new_month < 0 || new_month > 11)
16284 new_month = (new_month + 12) % 12;
16286 // For magnitudes >1, move one month at a time...
16287 for (var i=0; i<mag; i++)
16288 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16289 new_date = this.moveMonth(new_date, dir);
16290 // ...then reset the day, keeping it in the new month
16291 new_month = new_date.getUTCMonth();
16292 new_date.setUTCDate(day);
16294 return new_month != new_date.getUTCMonth();
16297 // Common date-resetting loop -- if date is beyond end of month, make it
16300 new_date.setUTCDate(--day);
16301 new_date.setUTCMonth(new_month);
16306 moveYear: function(date, dir)
16308 return this.moveMonth(date, dir*12);
16311 dateWithinRange: function(date)
16313 return date >= this.startDate && date <= this.endDate;
16319 this.picker().remove();
16324 Roo.apply(Roo.bootstrap.DateField, {
16335 html: '<i class="fa fa-arrow-left"/>'
16345 html: '<i class="fa fa-arrow-right"/>'
16387 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16388 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16389 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16390 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16391 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16404 navFnc: 'FullYear',
16409 navFnc: 'FullYear',
16414 Roo.apply(Roo.bootstrap.DateField, {
16418 cls: 'datepicker dropdown-menu roo-dynamic',
16422 cls: 'datepicker-days',
16426 cls: 'table-condensed',
16428 Roo.bootstrap.DateField.head,
16432 Roo.bootstrap.DateField.footer
16439 cls: 'datepicker-months',
16443 cls: 'table-condensed',
16445 Roo.bootstrap.DateField.head,
16446 Roo.bootstrap.DateField.content,
16447 Roo.bootstrap.DateField.footer
16454 cls: 'datepicker-years',
16458 cls: 'table-condensed',
16460 Roo.bootstrap.DateField.head,
16461 Roo.bootstrap.DateField.content,
16462 Roo.bootstrap.DateField.footer
16481 * @class Roo.bootstrap.TimeField
16482 * @extends Roo.bootstrap.Input
16483 * Bootstrap DateField class
16487 * Create a new TimeField
16488 * @param {Object} config The config object
16491 Roo.bootstrap.TimeField = function(config){
16492 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16496 * Fires when this field show.
16497 * @param {Roo.bootstrap.DateField} thisthis
16498 * @param {Mixed} date The date value
16503 * Fires when this field hide.
16504 * @param {Roo.bootstrap.DateField} this
16505 * @param {Mixed} date The date value
16510 * Fires when select a date.
16511 * @param {Roo.bootstrap.DateField} this
16512 * @param {Mixed} date The date value
16518 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16521 * @cfg {String} format
16522 * The default time format string which can be overriden for localization support. The format must be
16523 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16527 onRender: function(ct, position)
16530 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16532 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16534 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16536 this.pop = this.picker().select('>.datepicker-time',true).first();
16537 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16539 this.picker().on('mousedown', this.onMousedown, this);
16540 this.picker().on('click', this.onClick, this);
16542 this.picker().addClass('datepicker-dropdown');
16547 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16548 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16549 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16550 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16551 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16552 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16556 fireKey: function(e){
16557 if (!this.picker().isVisible()){
16558 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16564 e.preventDefault();
16572 this.onTogglePeriod();
16575 this.onIncrementMinutes();
16578 this.onDecrementMinutes();
16587 onClick: function(e) {
16588 e.stopPropagation();
16589 e.preventDefault();
16592 picker : function()
16594 return this.el.select('.datepicker', true).first();
16597 fillTime: function()
16599 var time = this.pop.select('tbody', true).first();
16601 time.dom.innerHTML = '';
16616 cls: 'hours-up glyphicon glyphicon-chevron-up'
16636 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16657 cls: 'timepicker-hour',
16672 cls: 'timepicker-minute',
16687 cls: 'btn btn-primary period',
16709 cls: 'hours-down glyphicon glyphicon-chevron-down'
16729 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16747 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16754 var hours = this.time.getHours();
16755 var minutes = this.time.getMinutes();
16768 hours = hours - 12;
16772 hours = '0' + hours;
16776 minutes = '0' + minutes;
16779 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16780 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16781 this.pop.select('button', true).first().dom.innerHTML = period;
16787 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16789 var cls = ['bottom'];
16791 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16798 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16803 this.picker().addClass(cls.join('-'));
16807 Roo.each(cls, function(c){
16809 _this.picker().setTop(_this.inputEl().getHeight());
16813 _this.picker().setTop(0 - _this.picker().getHeight());
16818 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16822 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16829 onFocus : function()
16831 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16835 onBlur : function()
16837 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16843 this.picker().show();
16848 this.fireEvent('show', this, this.date);
16853 this.picker().hide();
16856 this.fireEvent('hide', this, this.date);
16859 setTime : function()
16862 this.setValue(this.time.format(this.format));
16864 this.fireEvent('select', this, this.date);
16869 onMousedown: function(e){
16870 e.stopPropagation();
16871 e.preventDefault();
16874 onIncrementHours: function()
16876 Roo.log('onIncrementHours');
16877 this.time = this.time.add(Date.HOUR, 1);
16882 onDecrementHours: function()
16884 Roo.log('onDecrementHours');
16885 this.time = this.time.add(Date.HOUR, -1);
16889 onIncrementMinutes: function()
16891 Roo.log('onIncrementMinutes');
16892 this.time = this.time.add(Date.MINUTE, 1);
16896 onDecrementMinutes: function()
16898 Roo.log('onDecrementMinutes');
16899 this.time = this.time.add(Date.MINUTE, -1);
16903 onTogglePeriod: function()
16905 Roo.log('onTogglePeriod');
16906 this.time = this.time.add(Date.HOUR, 12);
16913 Roo.apply(Roo.bootstrap.TimeField, {
16943 cls: 'btn btn-info ok',
16955 Roo.apply(Roo.bootstrap.TimeField, {
16959 cls: 'datepicker dropdown-menu',
16963 cls: 'datepicker-time',
16967 cls: 'table-condensed',
16969 Roo.bootstrap.TimeField.content,
16970 Roo.bootstrap.TimeField.footer
16989 * @class Roo.bootstrap.MonthField
16990 * @extends Roo.bootstrap.Input
16991 * Bootstrap MonthField class
16993 * @cfg {String} language default en
16996 * Create a new MonthField
16997 * @param {Object} config The config object
17000 Roo.bootstrap.MonthField = function(config){
17001 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
17006 * Fires when this field show.
17007 * @param {Roo.bootstrap.MonthField} this
17008 * @param {Mixed} date The date value
17013 * Fires when this field hide.
17014 * @param {Roo.bootstrap.MonthField} this
17015 * @param {Mixed} date The date value
17020 * Fires when select a date.
17021 * @param {Roo.bootstrap.MonthField} this
17022 * @param {String} oldvalue The old value
17023 * @param {String} newvalue The new value
17029 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17031 onRender: function(ct, position)
17034 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17036 this.language = this.language || 'en';
17037 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17038 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17040 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17041 this.isInline = false;
17042 this.isInput = true;
17043 this.component = this.el.select('.add-on', true).first() || false;
17044 this.component = (this.component && this.component.length === 0) ? false : this.component;
17045 this.hasInput = this.component && this.inputEL().length;
17047 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17049 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17051 this.picker().on('mousedown', this.onMousedown, this);
17052 this.picker().on('click', this.onClick, this);
17054 this.picker().addClass('datepicker-dropdown');
17056 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17057 v.setStyle('width', '189px');
17064 if(this.isInline) {
17070 setValue: function(v, suppressEvent)
17072 var o = this.getValue();
17074 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17078 if(suppressEvent !== true){
17079 this.fireEvent('select', this, o, v);
17084 getValue: function()
17089 onClick: function(e)
17091 e.stopPropagation();
17092 e.preventDefault();
17094 var target = e.getTarget();
17096 if(target.nodeName.toLowerCase() === 'i'){
17097 target = Roo.get(target).dom.parentNode;
17100 var nodeName = target.nodeName;
17101 var className = target.className;
17102 var html = target.innerHTML;
17104 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17108 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17110 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17116 picker : function()
17118 return this.pickerEl;
17121 fillMonths: function()
17124 var months = this.picker().select('>.datepicker-months td', true).first();
17126 months.dom.innerHTML = '';
17132 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17135 months.createChild(month);
17144 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17145 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17148 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17149 e.removeClass('active');
17151 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17152 e.addClass('active');
17159 if(this.isInline) return;
17161 this.picker().removeClass(['bottom', 'top']);
17163 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17165 * place to the top of element!
17169 this.picker().addClass('top');
17170 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17175 this.picker().addClass('bottom');
17177 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17180 onFocus : function()
17182 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17186 onBlur : function()
17188 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17190 var d = this.inputEl().getValue();
17199 this.picker().show();
17200 this.picker().select('>.datepicker-months', true).first().show();
17204 this.fireEvent('show', this, this.date);
17209 if(this.isInline) return;
17210 this.picker().hide();
17211 this.fireEvent('hide', this, this.date);
17215 onMousedown: function(e)
17217 e.stopPropagation();
17218 e.preventDefault();
17223 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17227 fireKey: function(e)
17229 if (!this.picker().isVisible()){
17230 if (e.keyCode == 27) // allow escape to hide and re-show picker
17240 e.preventDefault();
17244 dir = e.keyCode == 37 ? -1 : 1;
17246 this.vIndex = this.vIndex + dir;
17248 if(this.vIndex < 0){
17252 if(this.vIndex > 11){
17256 if(isNaN(this.vIndex)){
17260 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17266 dir = e.keyCode == 38 ? -1 : 1;
17268 this.vIndex = this.vIndex + dir * 4;
17270 if(this.vIndex < 0){
17274 if(this.vIndex > 11){
17278 if(isNaN(this.vIndex)){
17282 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17287 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17288 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17292 e.preventDefault();
17295 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17296 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17312 this.picker().remove();
17317 Roo.apply(Roo.bootstrap.MonthField, {
17336 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17337 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17342 Roo.apply(Roo.bootstrap.MonthField, {
17346 cls: 'datepicker dropdown-menu roo-dynamic',
17350 cls: 'datepicker-months',
17354 cls: 'table-condensed',
17356 Roo.bootstrap.DateField.content
17376 * @class Roo.bootstrap.CheckBox
17377 * @extends Roo.bootstrap.Input
17378 * Bootstrap CheckBox class
17380 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17381 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17382 * @cfg {String} boxLabel The text that appears beside the checkbox
17383 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17384 * @cfg {Boolean} checked initnal the element
17385 * @cfg {Boolean} inline inline the element (default false)
17386 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17389 * Create a new CheckBox
17390 * @param {Object} config The config object
17393 Roo.bootstrap.CheckBox = function(config){
17394 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17399 * Fires when the element is checked or unchecked.
17400 * @param {Roo.bootstrap.CheckBox} this This input
17401 * @param {Boolean} checked The new checked value
17408 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17410 inputType: 'checkbox',
17418 getAutoCreate : function()
17420 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17426 cfg.cls = 'form-group ' + this.inputType; //input-group
17429 cfg.cls += ' ' + this.inputType + '-inline';
17435 type : this.inputType,
17436 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17437 cls : 'roo-' + this.inputType, //'form-box',
17438 placeholder : this.placeholder || ''
17442 if (this.weight) { // Validity check?
17443 cfg.cls += " " + this.inputType + "-" + this.weight;
17446 if (this.disabled) {
17447 input.disabled=true;
17451 input.checked = this.checked;
17455 input.name = this.name;
17459 input.cls += ' input-' + this.size;
17464 ['xs','sm','md','lg'].map(function(size){
17465 if (settings[size]) {
17466 cfg.cls += ' col-' + size + '-' + settings[size];
17470 var inputblock = input;
17472 if (this.before || this.after) {
17475 cls : 'input-group',
17480 inputblock.cn.push({
17482 cls : 'input-group-addon',
17487 inputblock.cn.push(input);
17490 inputblock.cn.push({
17492 cls : 'input-group-addon',
17499 if (align ==='left' && this.fieldLabel.length) {
17500 Roo.log("left and has label");
17506 cls : 'control-label col-md-' + this.labelWidth,
17507 html : this.fieldLabel
17511 cls : "col-md-" + (12 - this.labelWidth),
17518 } else if ( this.fieldLabel.length) {
17523 tag: this.boxLabel ? 'span' : 'label',
17525 cls: 'control-label box-input-label',
17526 //cls : 'input-group-addon',
17527 html : this.fieldLabel
17537 Roo.log(" no label && no align");
17538 cfg.cn = [ inputblock ] ;
17543 var boxLabelCfg = {
17545 //'for': id, // box label is handled by onclick - so no for...
17547 html: this.boxLabel
17551 boxLabelCfg.tooltip = this.tooltip;
17554 cfg.cn.push(boxLabelCfg);
17564 * return the real input element.
17566 inputEl: function ()
17568 return this.el.select('input.roo-' + this.inputType,true).first();
17571 labelEl: function()
17573 return this.el.select('label.control-label',true).first();
17575 /* depricated... */
17579 return this.labelEl();
17582 initEvents : function()
17584 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17586 this.inputEl().on('click', this.onClick, this);
17588 if (this.boxLabel) {
17589 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17592 this.startValue = this.getValue();
17595 Roo.bootstrap.CheckBox.register(this);
17599 onClick : function()
17601 this.setChecked(!this.checked);
17604 setChecked : function(state,suppressEvent)
17606 this.startValue = this.getValue();
17608 if(this.inputType == 'radio'){
17610 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17611 e.dom.checked = false;
17614 this.inputEl().dom.checked = true;
17616 this.inputEl().dom.value = this.inputValue;
17618 if(suppressEvent !== true){
17619 this.fireEvent('check', this, true);
17627 this.checked = state;
17629 this.inputEl().dom.checked = state;
17631 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17633 if(suppressEvent !== true){
17634 this.fireEvent('check', this, state);
17640 getValue : function()
17642 if(this.inputType == 'radio'){
17643 return this.getGroupValue();
17646 return this.inputEl().getValue();
17650 getGroupValue : function()
17652 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17656 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17659 setValue : function(v,suppressEvent)
17661 if(this.inputType == 'radio'){
17662 this.setGroupValue(v, suppressEvent);
17666 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17671 setGroupValue : function(v, suppressEvent)
17673 this.startValue = this.getValue();
17675 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17676 e.dom.checked = false;
17678 if(e.dom.value == v){
17679 e.dom.checked = true;
17683 if(suppressEvent !== true){
17684 this.fireEvent('check', this, true);
17692 validate : function()
17696 (this.inputType == 'radio' && this.validateRadio()) ||
17697 (this.inputType == 'checkbox' && this.validateCheckbox())
17703 this.markInvalid();
17707 validateRadio : function()
17711 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17712 if(!e.dom.checked){
17724 validateCheckbox : function()
17727 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17730 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17738 for(var i in group){
17743 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17750 * Mark this field as valid
17752 markValid : function()
17754 if(this.allowBlank){
17760 this.fireEvent('valid', this);
17762 if(this.inputType == 'radio'){
17763 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17764 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17765 e.findParent('.form-group', false, true).addClass(_this.validClass);
17772 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17773 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17777 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17783 for(var i in group){
17784 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17785 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17790 * Mark this field as invalid
17791 * @param {String} msg The validation message
17793 markInvalid : function(msg)
17795 if(this.allowBlank){
17801 this.fireEvent('invalid', this, msg);
17803 if(this.inputType == 'radio'){
17804 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17805 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17806 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17813 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17814 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17818 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17824 for(var i in group){
17825 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17826 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17833 Roo.apply(Roo.bootstrap.CheckBox, {
17838 * register a CheckBox Group
17839 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17841 register : function(checkbox)
17843 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17844 this.groups[checkbox.groupId] = {};
17847 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17851 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17855 * fetch a CheckBox Group based on the group ID
17856 * @param {string} the group ID
17857 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17859 get: function(groupId) {
17860 if (typeof(this.groups[groupId]) == 'undefined') {
17864 return this.groups[groupId] ;
17876 *<div class="radio">
17878 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17879 Option one is this and that—be sure to include why it's great
17886 *<label class="radio-inline">fieldLabel</label>
17887 *<label class="radio-inline">
17888 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17896 * @class Roo.bootstrap.Radio
17897 * @extends Roo.bootstrap.CheckBox
17898 * Bootstrap Radio class
17901 * Create a new Radio
17902 * @param {Object} config The config object
17905 Roo.bootstrap.Radio = function(config){
17906 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17910 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17912 inputType: 'radio',
17916 getAutoCreate : function()
17918 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17919 align = align || 'left'; // default...
17926 tag : this.inline ? 'span' : 'div',
17931 var inline = this.inline ? ' radio-inline' : '';
17935 // does not need for, as we wrap the input with it..
17937 cls : 'control-label box-label' + inline,
17940 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17944 //cls : 'control-label' + inline,
17945 html : this.fieldLabel,
17946 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17955 type : this.inputType,
17956 //value : (!this.checked) ? this.valueOff : this.inputValue,
17957 value : this.inputValue,
17959 placeholder : this.placeholder || '' // ?? needed????
17962 if (this.weight) { // Validity check?
17963 input.cls += " radio-" + this.weight;
17965 if (this.disabled) {
17966 input.disabled=true;
17970 input.checked = this.checked;
17974 input.name = this.name;
17978 input.cls += ' input-' + this.size;
17981 //?? can span's inline have a width??
17984 ['xs','sm','md','lg'].map(function(size){
17985 if (settings[size]) {
17986 cfg.cls += ' col-' + size + '-' + settings[size];
17990 var inputblock = input;
17992 if (this.before || this.after) {
17995 cls : 'input-group',
18000 inputblock.cn.push({
18002 cls : 'input-group-addon',
18006 inputblock.cn.push(input);
18008 inputblock.cn.push({
18010 cls : 'input-group-addon',
18018 if (this.fieldLabel && this.fieldLabel.length) {
18019 cfg.cn.push(fieldLabel);
18022 // normal bootstrap puts the input inside the label.
18023 // however with our styled version - it has to go after the input.
18025 //lbl.cn.push(inputblock);
18029 cls: 'radio' + inline,
18036 cfg.cn.push( lblwrap);
18041 html: this.boxLabel
18050 initEvents : function()
18052 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18054 this.inputEl().on('click', this.onClick, this);
18055 if (this.boxLabel) {
18056 Roo.log('find label')
18057 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18062 inputEl: function ()
18064 return this.el.select('input.roo-radio',true).first();
18066 onClick : function()
18069 this.setChecked(true);
18072 setChecked : function(state,suppressEvent)
18075 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18076 v.dom.checked = false;
18079 Roo.log(this.inputEl().dom);
18080 this.checked = state;
18081 this.inputEl().dom.checked = state;
18083 if(suppressEvent !== true){
18084 this.fireEvent('check', this, state);
18087 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18091 getGroupValue : function()
18094 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18095 if(v.dom.checked == true){
18096 value = v.dom.value;
18104 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18105 * @return {Mixed} value The field value
18107 getValue : function(){
18108 return this.getGroupValue();
18114 //<script type="text/javascript">
18117 * Based Ext JS Library 1.1.1
18118 * Copyright(c) 2006-2007, Ext JS, LLC.
18124 * @class Roo.HtmlEditorCore
18125 * @extends Roo.Component
18126 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18128 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18131 Roo.HtmlEditorCore = function(config){
18134 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18139 * @event initialize
18140 * Fires when the editor is fully initialized (including the iframe)
18141 * @param {Roo.HtmlEditorCore} this
18146 * Fires when the editor is first receives the focus. Any insertion must wait
18147 * until after this event.
18148 * @param {Roo.HtmlEditorCore} this
18152 * @event beforesync
18153 * Fires before the textarea is updated with content from the editor iframe. Return false
18154 * to cancel the sync.
18155 * @param {Roo.HtmlEditorCore} this
18156 * @param {String} html
18160 * @event beforepush
18161 * Fires before the iframe editor is updated with content from the textarea. Return false
18162 * to cancel the push.
18163 * @param {Roo.HtmlEditorCore} this
18164 * @param {String} html
18169 * Fires when the textarea is updated with content from the editor iframe.
18170 * @param {Roo.HtmlEditorCore} this
18171 * @param {String} html
18176 * Fires when the iframe editor is updated with content from the textarea.
18177 * @param {Roo.HtmlEditorCore} this
18178 * @param {String} html
18183 * @event editorevent
18184 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18185 * @param {Roo.HtmlEditorCore} this
18191 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18193 // defaults : white / black...
18194 this.applyBlacklists();
18201 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18205 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18211 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18216 * @cfg {Number} height (in pixels)
18220 * @cfg {Number} width (in pixels)
18225 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18228 stylesheets: false,
18233 // private properties
18234 validationEvent : false,
18236 initialized : false,
18238 sourceEditMode : false,
18239 onFocus : Roo.emptyFn,
18241 hideMode:'offsets',
18245 // blacklist + whitelisted elements..
18252 * Protected method that will not generally be called directly. It
18253 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18254 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18256 getDocMarkup : function(){
18260 // inherit styels from page...??
18261 if (this.stylesheets === false) {
18263 Roo.get(document.head).select('style').each(function(node) {
18264 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18267 Roo.get(document.head).select('link').each(function(node) {
18268 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18271 } else if (!this.stylesheets.length) {
18273 st = '<style type="text/css">' +
18274 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18280 st += '<style type="text/css">' +
18281 'IMG { cursor: pointer } ' +
18285 return '<html><head>' + st +
18286 //<style type="text/css">' +
18287 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18289 ' </head><body class="roo-htmleditor-body"></body></html>';
18293 onRender : function(ct, position)
18296 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18297 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18300 this.el.dom.style.border = '0 none';
18301 this.el.dom.setAttribute('tabIndex', -1);
18302 this.el.addClass('x-hidden hide');
18306 if(Roo.isIE){ // fix IE 1px bogus margin
18307 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18311 this.frameId = Roo.id();
18315 var iframe = this.owner.wrap.createChild({
18317 cls: 'form-control', // bootstrap..
18319 name: this.frameId,
18320 frameBorder : 'no',
18321 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18326 this.iframe = iframe.dom;
18328 this.assignDocWin();
18330 this.doc.designMode = 'on';
18333 this.doc.write(this.getDocMarkup());
18337 var task = { // must defer to wait for browser to be ready
18339 //console.log("run task?" + this.doc.readyState);
18340 this.assignDocWin();
18341 if(this.doc.body || this.doc.readyState == 'complete'){
18343 this.doc.designMode="on";
18347 Roo.TaskMgr.stop(task);
18348 this.initEditor.defer(10, this);
18355 Roo.TaskMgr.start(task);
18360 onResize : function(w, h)
18362 Roo.log('resize: ' +w + ',' + h );
18363 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18367 if(typeof w == 'number'){
18369 this.iframe.style.width = w + 'px';
18371 if(typeof h == 'number'){
18373 this.iframe.style.height = h + 'px';
18375 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18382 * Toggles the editor between standard and source edit mode.
18383 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18385 toggleSourceEdit : function(sourceEditMode){
18387 this.sourceEditMode = sourceEditMode === true;
18389 if(this.sourceEditMode){
18391 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18394 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18395 //this.iframe.className = '';
18398 //this.setSize(this.owner.wrap.getSize());
18399 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18406 * Protected method that will not generally be called directly. If you need/want
18407 * custom HTML cleanup, this is the method you should override.
18408 * @param {String} html The HTML to be cleaned
18409 * return {String} The cleaned HTML
18411 cleanHtml : function(html){
18412 html = String(html);
18413 if(html.length > 5){
18414 if(Roo.isSafari){ // strip safari nonsense
18415 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18418 if(html == ' '){
18425 * HTML Editor -> Textarea
18426 * Protected method that will not generally be called directly. Syncs the contents
18427 * of the editor iframe with the textarea.
18429 syncValue : function(){
18430 if(this.initialized){
18431 var bd = (this.doc.body || this.doc.documentElement);
18432 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18433 var html = bd.innerHTML;
18435 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18436 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18438 html = '<div style="'+m[0]+'">' + html + '</div>';
18441 html = this.cleanHtml(html);
18442 // fix up the special chars.. normaly like back quotes in word...
18443 // however we do not want to do this with chinese..
18444 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18445 var cc = b.charCodeAt();
18447 (cc >= 0x4E00 && cc < 0xA000 ) ||
18448 (cc >= 0x3400 && cc < 0x4E00 ) ||
18449 (cc >= 0xf900 && cc < 0xfb00 )
18455 if(this.owner.fireEvent('beforesync', this, html) !== false){
18456 this.el.dom.value = html;
18457 this.owner.fireEvent('sync', this, html);
18463 * Protected method that will not generally be called directly. Pushes the value of the textarea
18464 * into the iframe editor.
18466 pushValue : function(){
18467 if(this.initialized){
18468 var v = this.el.dom.value.trim();
18470 // if(v.length < 1){
18474 if(this.owner.fireEvent('beforepush', this, v) !== false){
18475 var d = (this.doc.body || this.doc.documentElement);
18477 this.cleanUpPaste();
18478 this.el.dom.value = d.innerHTML;
18479 this.owner.fireEvent('push', this, v);
18485 deferFocus : function(){
18486 this.focus.defer(10, this);
18490 focus : function(){
18491 if(this.win && !this.sourceEditMode){
18498 assignDocWin: function()
18500 var iframe = this.iframe;
18503 this.doc = iframe.contentWindow.document;
18504 this.win = iframe.contentWindow;
18506 // if (!Roo.get(this.frameId)) {
18509 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18510 // this.win = Roo.get(this.frameId).dom.contentWindow;
18512 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18516 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18517 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18522 initEditor : function(){
18523 //console.log("INIT EDITOR");
18524 this.assignDocWin();
18528 this.doc.designMode="on";
18530 this.doc.write(this.getDocMarkup());
18533 var dbody = (this.doc.body || this.doc.documentElement);
18534 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18535 // this copies styles from the containing element into thsi one..
18536 // not sure why we need all of this..
18537 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18539 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18540 //ss['background-attachment'] = 'fixed'; // w3c
18541 dbody.bgProperties = 'fixed'; // ie
18542 //Roo.DomHelper.applyStyles(dbody, ss);
18543 Roo.EventManager.on(this.doc, {
18544 //'mousedown': this.onEditorEvent,
18545 'mouseup': this.onEditorEvent,
18546 'dblclick': this.onEditorEvent,
18547 'click': this.onEditorEvent,
18548 'keyup': this.onEditorEvent,
18553 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18555 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18556 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18558 this.initialized = true;
18560 this.owner.fireEvent('initialize', this);
18565 onDestroy : function(){
18571 //for (var i =0; i < this.toolbars.length;i++) {
18572 // // fixme - ask toolbars for heights?
18573 // this.toolbars[i].onDestroy();
18576 //this.wrap.dom.innerHTML = '';
18577 //this.wrap.remove();
18582 onFirstFocus : function(){
18584 this.assignDocWin();
18587 this.activated = true;
18590 if(Roo.isGecko){ // prevent silly gecko errors
18592 var s = this.win.getSelection();
18593 if(!s.focusNode || s.focusNode.nodeType != 3){
18594 var r = s.getRangeAt(0);
18595 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18600 this.execCmd('useCSS', true);
18601 this.execCmd('styleWithCSS', false);
18604 this.owner.fireEvent('activate', this);
18608 adjustFont: function(btn){
18609 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18610 //if(Roo.isSafari){ // safari
18613 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18614 if(Roo.isSafari){ // safari
18615 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18616 v = (v < 10) ? 10 : v;
18617 v = (v > 48) ? 48 : v;
18618 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18623 v = Math.max(1, v+adjust);
18625 this.execCmd('FontSize', v );
18628 onEditorEvent : function(e)
18630 this.owner.fireEvent('editorevent', this, e);
18631 // this.updateToolbar();
18632 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18635 insertTag : function(tg)
18637 // could be a bit smarter... -> wrap the current selected tRoo..
18638 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18640 range = this.createRange(this.getSelection());
18641 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18642 wrappingNode.appendChild(range.extractContents());
18643 range.insertNode(wrappingNode);
18650 this.execCmd("formatblock", tg);
18654 insertText : function(txt)
18658 var range = this.createRange();
18659 range.deleteContents();
18660 //alert(Sender.getAttribute('label'));
18662 range.insertNode(this.doc.createTextNode(txt));
18668 * Executes a Midas editor command on the editor document and performs necessary focus and
18669 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18670 * @param {String} cmd The Midas command
18671 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18673 relayCmd : function(cmd, value){
18675 this.execCmd(cmd, value);
18676 this.owner.fireEvent('editorevent', this);
18677 //this.updateToolbar();
18678 this.owner.deferFocus();
18682 * Executes a Midas editor command directly on the editor document.
18683 * For visual commands, you should use {@link #relayCmd} instead.
18684 * <b>This should only be called after the editor is initialized.</b>
18685 * @param {String} cmd The Midas command
18686 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18688 execCmd : function(cmd, value){
18689 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18696 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18698 * @param {String} text | dom node..
18700 insertAtCursor : function(text)
18705 if(!this.activated){
18711 var r = this.doc.selection.createRange();
18722 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18726 // from jquery ui (MIT licenced)
18728 var win = this.win;
18730 if (win.getSelection && win.getSelection().getRangeAt) {
18731 range = win.getSelection().getRangeAt(0);
18732 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18733 range.insertNode(node);
18734 } else if (win.document.selection && win.document.selection.createRange) {
18735 // no firefox support
18736 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18737 win.document.selection.createRange().pasteHTML(txt);
18739 // no firefox support
18740 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18741 this.execCmd('InsertHTML', txt);
18750 mozKeyPress : function(e){
18752 var c = e.getCharCode(), cmd;
18755 c = String.fromCharCode(c).toLowerCase();
18769 this.cleanUpPaste.defer(100, this);
18777 e.preventDefault();
18785 fixKeys : function(){ // load time branching for fastest keydown performance
18787 return function(e){
18788 var k = e.getKey(), r;
18791 r = this.doc.selection.createRange();
18794 r.pasteHTML('    ');
18801 r = this.doc.selection.createRange();
18803 var target = r.parentElement();
18804 if(!target || target.tagName.toLowerCase() != 'li'){
18806 r.pasteHTML('<br />');
18812 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18813 this.cleanUpPaste.defer(100, this);
18819 }else if(Roo.isOpera){
18820 return function(e){
18821 var k = e.getKey();
18825 this.execCmd('InsertHTML','    ');
18828 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18829 this.cleanUpPaste.defer(100, this);
18834 }else if(Roo.isSafari){
18835 return function(e){
18836 var k = e.getKey();
18840 this.execCmd('InsertText','\t');
18844 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18845 this.cleanUpPaste.defer(100, this);
18853 getAllAncestors: function()
18855 var p = this.getSelectedNode();
18858 a.push(p); // push blank onto stack..
18859 p = this.getParentElement();
18863 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18867 a.push(this.doc.body);
18871 lastSelNode : false,
18874 getSelection : function()
18876 this.assignDocWin();
18877 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18880 getSelectedNode: function()
18882 // this may only work on Gecko!!!
18884 // should we cache this!!!!
18889 var range = this.createRange(this.getSelection()).cloneRange();
18892 var parent = range.parentElement();
18894 var testRange = range.duplicate();
18895 testRange.moveToElementText(parent);
18896 if (testRange.inRange(range)) {
18899 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18902 parent = parent.parentElement;
18907 // is ancestor a text element.
18908 var ac = range.commonAncestorContainer;
18909 if (ac.nodeType == 3) {
18910 ac = ac.parentNode;
18913 var ar = ac.childNodes;
18916 var other_nodes = [];
18917 var has_other_nodes = false;
18918 for (var i=0;i<ar.length;i++) {
18919 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18922 // fullly contained node.
18924 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18929 // probably selected..
18930 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18931 other_nodes.push(ar[i]);
18935 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18940 has_other_nodes = true;
18942 if (!nodes.length && other_nodes.length) {
18943 nodes= other_nodes;
18945 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18951 createRange: function(sel)
18953 // this has strange effects when using with
18954 // top toolbar - not sure if it's a great idea.
18955 //this.editor.contentWindow.focus();
18956 if (typeof sel != "undefined") {
18958 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18960 return this.doc.createRange();
18963 return this.doc.createRange();
18966 getParentElement: function()
18969 this.assignDocWin();
18970 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18972 var range = this.createRange(sel);
18975 var p = range.commonAncestorContainer;
18976 while (p.nodeType == 3) { // text node
18987 * Range intersection.. the hard stuff...
18991 * [ -- selected range --- ]
18995 * if end is before start or hits it. fail.
18996 * if start is after end or hits it fail.
18998 * if either hits (but other is outside. - then it's not
19004 // @see http://www.thismuchiknow.co.uk/?p=64.
19005 rangeIntersectsNode : function(range, node)
19007 var nodeRange = node.ownerDocument.createRange();
19009 nodeRange.selectNode(node);
19011 nodeRange.selectNodeContents(node);
19014 var rangeStartRange = range.cloneRange();
19015 rangeStartRange.collapse(true);
19017 var rangeEndRange = range.cloneRange();
19018 rangeEndRange.collapse(false);
19020 var nodeStartRange = nodeRange.cloneRange();
19021 nodeStartRange.collapse(true);
19023 var nodeEndRange = nodeRange.cloneRange();
19024 nodeEndRange.collapse(false);
19026 return rangeStartRange.compareBoundaryPoints(
19027 Range.START_TO_START, nodeEndRange) == -1 &&
19028 rangeEndRange.compareBoundaryPoints(
19029 Range.START_TO_START, nodeStartRange) == 1;
19033 rangeCompareNode : function(range, node)
19035 var nodeRange = node.ownerDocument.createRange();
19037 nodeRange.selectNode(node);
19039 nodeRange.selectNodeContents(node);
19043 range.collapse(true);
19045 nodeRange.collapse(true);
19047 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19048 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19050 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19052 var nodeIsBefore = ss == 1;
19053 var nodeIsAfter = ee == -1;
19055 if (nodeIsBefore && nodeIsAfter)
19057 if (!nodeIsBefore && nodeIsAfter)
19058 return 1; //right trailed.
19060 if (nodeIsBefore && !nodeIsAfter)
19061 return 2; // left trailed.
19066 // private? - in a new class?
19067 cleanUpPaste : function()
19069 // cleans up the whole document..
19070 Roo.log('cleanuppaste');
19072 this.cleanUpChildren(this.doc.body);
19073 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19074 if (clean != this.doc.body.innerHTML) {
19075 this.doc.body.innerHTML = clean;
19080 cleanWordChars : function(input) {// change the chars to hex code
19081 var he = Roo.HtmlEditorCore;
19083 var output = input;
19084 Roo.each(he.swapCodes, function(sw) {
19085 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19087 output = output.replace(swapper, sw[1]);
19094 cleanUpChildren : function (n)
19096 if (!n.childNodes.length) {
19099 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19100 this.cleanUpChild(n.childNodes[i]);
19107 cleanUpChild : function (node)
19110 //console.log(node);
19111 if (node.nodeName == "#text") {
19112 // clean up silly Windows -- stuff?
19115 if (node.nodeName == "#comment") {
19116 node.parentNode.removeChild(node);
19117 // clean up silly Windows -- stuff?
19120 var lcname = node.tagName.toLowerCase();
19121 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19122 // whitelist of tags..
19124 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19126 node.parentNode.removeChild(node);
19131 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19133 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19134 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19136 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19137 // remove_keep_children = true;
19140 if (remove_keep_children) {
19141 this.cleanUpChildren(node);
19142 // inserts everything just before this node...
19143 while (node.childNodes.length) {
19144 var cn = node.childNodes[0];
19145 node.removeChild(cn);
19146 node.parentNode.insertBefore(cn, node);
19148 node.parentNode.removeChild(node);
19152 if (!node.attributes || !node.attributes.length) {
19153 this.cleanUpChildren(node);
19157 function cleanAttr(n,v)
19160 if (v.match(/^\./) || v.match(/^\//)) {
19163 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19166 if (v.match(/^#/)) {
19169 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19170 node.removeAttribute(n);
19174 var cwhite = this.cwhite;
19175 var cblack = this.cblack;
19177 function cleanStyle(n,v)
19179 if (v.match(/expression/)) { //XSS?? should we even bother..
19180 node.removeAttribute(n);
19184 var parts = v.split(/;/);
19187 Roo.each(parts, function(p) {
19188 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19192 var l = p.split(':').shift().replace(/\s+/g,'');
19193 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19195 if ( cwhite.length && cblack.indexOf(l) > -1) {
19196 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19197 //node.removeAttribute(n);
19201 // only allow 'c whitelisted system attributes'
19202 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19203 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19204 //node.removeAttribute(n);
19214 if (clean.length) {
19215 node.setAttribute(n, clean.join(';'));
19217 node.removeAttribute(n);
19223 for (var i = node.attributes.length-1; i > -1 ; i--) {
19224 var a = node.attributes[i];
19227 if (a.name.toLowerCase().substr(0,2)=='on') {
19228 node.removeAttribute(a.name);
19231 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19232 node.removeAttribute(a.name);
19235 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19236 cleanAttr(a.name,a.value); // fixme..
19239 if (a.name == 'style') {
19240 cleanStyle(a.name,a.value);
19243 /// clean up MS crap..
19244 // tecnically this should be a list of valid class'es..
19247 if (a.name == 'class') {
19248 if (a.value.match(/^Mso/)) {
19249 node.className = '';
19252 if (a.value.match(/body/)) {
19253 node.className = '';
19264 this.cleanUpChildren(node);
19270 * Clean up MS wordisms...
19272 cleanWord : function(node)
19277 this.cleanWord(this.doc.body);
19280 if (node.nodeName == "#text") {
19281 // clean up silly Windows -- stuff?
19284 if (node.nodeName == "#comment") {
19285 node.parentNode.removeChild(node);
19286 // clean up silly Windows -- stuff?
19290 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19291 node.parentNode.removeChild(node);
19295 // remove - but keep children..
19296 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19297 while (node.childNodes.length) {
19298 var cn = node.childNodes[0];
19299 node.removeChild(cn);
19300 node.parentNode.insertBefore(cn, node);
19302 node.parentNode.removeChild(node);
19303 this.iterateChildren(node, this.cleanWord);
19307 if (node.className.length) {
19309 var cn = node.className.split(/\W+/);
19311 Roo.each(cn, function(cls) {
19312 if (cls.match(/Mso[a-zA-Z]+/)) {
19317 node.className = cna.length ? cna.join(' ') : '';
19319 node.removeAttribute("class");
19323 if (node.hasAttribute("lang")) {
19324 node.removeAttribute("lang");
19327 if (node.hasAttribute("style")) {
19329 var styles = node.getAttribute("style").split(";");
19331 Roo.each(styles, function(s) {
19332 if (!s.match(/:/)) {
19335 var kv = s.split(":");
19336 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19339 // what ever is left... we allow.
19342 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19343 if (!nstyle.length) {
19344 node.removeAttribute('style');
19347 this.iterateChildren(node, this.cleanWord);
19353 * iterateChildren of a Node, calling fn each time, using this as the scole..
19354 * @param {DomNode} node node to iterate children of.
19355 * @param {Function} fn method of this class to call on each item.
19357 iterateChildren : function(node, fn)
19359 if (!node.childNodes.length) {
19362 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19363 fn.call(this, node.childNodes[i])
19369 * cleanTableWidths.
19371 * Quite often pasting from word etc.. results in tables with column and widths.
19372 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19375 cleanTableWidths : function(node)
19380 this.cleanTableWidths(this.doc.body);
19385 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19388 Roo.log(node.tagName);
19389 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19390 this.iterateChildren(node, this.cleanTableWidths);
19393 if (node.hasAttribute('width')) {
19394 node.removeAttribute('width');
19398 if (node.hasAttribute("style")) {
19401 var styles = node.getAttribute("style").split(";");
19403 Roo.each(styles, function(s) {
19404 if (!s.match(/:/)) {
19407 var kv = s.split(":");
19408 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
19411 // what ever is left... we allow.
19414 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19415 if (!nstyle.length) {
19416 node.removeAttribute('style');
19420 this.iterateChildren(node, this.cleanTableWidths);
19428 domToHTML : function(currentElement, depth, nopadtext) {
19430 depth = depth || 0;
19431 nopadtext = nopadtext || false;
19433 if (!currentElement) {
19434 return this.domToHTML(this.doc.body);
19437 //Roo.log(currentElement);
19439 var allText = false;
19440 var nodeName = currentElement.nodeName;
19441 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19443 if (nodeName == '#text') {
19445 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19450 if (nodeName != 'BODY') {
19453 // Prints the node tagName, such as <A>, <IMG>, etc
19456 for(i = 0; i < currentElement.attributes.length;i++) {
19458 var aname = currentElement.attributes.item(i).name;
19459 if (!currentElement.attributes.item(i).value.length) {
19462 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19465 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19474 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19477 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19482 // Traverse the tree
19484 var currentElementChild = currentElement.childNodes.item(i);
19485 var allText = true;
19486 var innerHTML = '';
19488 while (currentElementChild) {
19489 // Formatting code (indent the tree so it looks nice on the screen)
19490 var nopad = nopadtext;
19491 if (lastnode == 'SPAN') {
19495 if (currentElementChild.nodeName == '#text') {
19496 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19497 toadd = nopadtext ? toadd : toadd.trim();
19498 if (!nopad && toadd.length > 80) {
19499 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19501 innerHTML += toadd;
19504 currentElementChild = currentElement.childNodes.item(i);
19510 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19512 // Recursively traverse the tree structure of the child node
19513 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19514 lastnode = currentElementChild.nodeName;
19516 currentElementChild=currentElement.childNodes.item(i);
19522 // The remaining code is mostly for formatting the tree
19523 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19528 ret+= "</"+tagName+">";
19534 applyBlacklists : function()
19536 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19537 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19541 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19542 if (b.indexOf(tag) > -1) {
19545 this.white.push(tag);
19549 Roo.each(w, function(tag) {
19550 if (b.indexOf(tag) > -1) {
19553 if (this.white.indexOf(tag) > -1) {
19556 this.white.push(tag);
19561 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19562 if (w.indexOf(tag) > -1) {
19565 this.black.push(tag);
19569 Roo.each(b, function(tag) {
19570 if (w.indexOf(tag) > -1) {
19573 if (this.black.indexOf(tag) > -1) {
19576 this.black.push(tag);
19581 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19582 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19586 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19587 if (b.indexOf(tag) > -1) {
19590 this.cwhite.push(tag);
19594 Roo.each(w, function(tag) {
19595 if (b.indexOf(tag) > -1) {
19598 if (this.cwhite.indexOf(tag) > -1) {
19601 this.cwhite.push(tag);
19606 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19607 if (w.indexOf(tag) > -1) {
19610 this.cblack.push(tag);
19614 Roo.each(b, function(tag) {
19615 if (w.indexOf(tag) > -1) {
19618 if (this.cblack.indexOf(tag) > -1) {
19621 this.cblack.push(tag);
19626 setStylesheets : function(stylesheets)
19628 if(typeof(stylesheets) == 'string'){
19629 Roo.get(this.iframe.contentDocument.head).createChild({
19631 rel : 'stylesheet',
19640 Roo.each(stylesheets, function(s) {
19645 Roo.get(_this.iframe.contentDocument.head).createChild({
19647 rel : 'stylesheet',
19656 removeStylesheets : function()
19660 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19665 // hide stuff that is not compatible
19679 * @event specialkey
19683 * @cfg {String} fieldClass @hide
19686 * @cfg {String} focusClass @hide
19689 * @cfg {String} autoCreate @hide
19692 * @cfg {String} inputType @hide
19695 * @cfg {String} invalidClass @hide
19698 * @cfg {String} invalidText @hide
19701 * @cfg {String} msgFx @hide
19704 * @cfg {String} validateOnBlur @hide
19708 Roo.HtmlEditorCore.white = [
19709 'area', 'br', 'img', 'input', 'hr', 'wbr',
19711 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19712 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19713 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19714 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19715 'table', 'ul', 'xmp',
19717 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19720 'dir', 'menu', 'ol', 'ul', 'dl',
19726 Roo.HtmlEditorCore.black = [
19727 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19729 'base', 'basefont', 'bgsound', 'blink', 'body',
19730 'frame', 'frameset', 'head', 'html', 'ilayer',
19731 'iframe', 'layer', 'link', 'meta', 'object',
19732 'script', 'style' ,'title', 'xml' // clean later..
19734 Roo.HtmlEditorCore.clean = [
19735 'script', 'style', 'title', 'xml'
19737 Roo.HtmlEditorCore.remove = [
19742 Roo.HtmlEditorCore.ablack = [
19746 Roo.HtmlEditorCore.aclean = [
19747 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19751 Roo.HtmlEditorCore.pwhite= [
19752 'http', 'https', 'mailto'
19755 // white listed style attributes.
19756 Roo.HtmlEditorCore.cwhite= [
19757 // 'text-align', /// default is to allow most things..
19763 // black listed style attributes.
19764 Roo.HtmlEditorCore.cblack= [
19765 // 'font-size' -- this can be set by the project
19769 Roo.HtmlEditorCore.swapCodes =[
19788 * @class Roo.bootstrap.HtmlEditor
19789 * @extends Roo.bootstrap.TextArea
19790 * Bootstrap HtmlEditor class
19793 * Create a new HtmlEditor
19794 * @param {Object} config The config object
19797 Roo.bootstrap.HtmlEditor = function(config){
19798 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19799 if (!this.toolbars) {
19800 this.toolbars = [];
19802 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19805 * @event initialize
19806 * Fires when the editor is fully initialized (including the iframe)
19807 * @param {HtmlEditor} this
19812 * Fires when the editor is first receives the focus. Any insertion must wait
19813 * until after this event.
19814 * @param {HtmlEditor} this
19818 * @event beforesync
19819 * Fires before the textarea is updated with content from the editor iframe. Return false
19820 * to cancel the sync.
19821 * @param {HtmlEditor} this
19822 * @param {String} html
19826 * @event beforepush
19827 * Fires before the iframe editor is updated with content from the textarea. Return false
19828 * to cancel the push.
19829 * @param {HtmlEditor} this
19830 * @param {String} html
19835 * Fires when the textarea is updated with content from the editor iframe.
19836 * @param {HtmlEditor} this
19837 * @param {String} html
19842 * Fires when the iframe editor is updated with content from the textarea.
19843 * @param {HtmlEditor} this
19844 * @param {String} html
19848 * @event editmodechange
19849 * Fires when the editor switches edit modes
19850 * @param {HtmlEditor} this
19851 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19853 editmodechange: true,
19855 * @event editorevent
19856 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19857 * @param {HtmlEditor} this
19861 * @event firstfocus
19862 * Fires when on first focus - needed by toolbars..
19863 * @param {HtmlEditor} this
19868 * Auto save the htmlEditor value as a file into Events
19869 * @param {HtmlEditor} this
19873 * @event savedpreview
19874 * preview the saved version of htmlEditor
19875 * @param {HtmlEditor} this
19882 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19886 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19891 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19896 * @cfg {Number} height (in pixels)
19900 * @cfg {Number} width (in pixels)
19905 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19908 stylesheets: false,
19913 // private properties
19914 validationEvent : false,
19916 initialized : false,
19919 onFocus : Roo.emptyFn,
19921 hideMode:'offsets',
19924 tbContainer : false,
19926 toolbarContainer :function() {
19927 return this.wrap.select('.x-html-editor-tb',true).first();
19931 * Protected method that will not generally be called directly. It
19932 * is called when the editor creates its toolbar. Override this method if you need to
19933 * add custom toolbar buttons.
19934 * @param {HtmlEditor} editor
19936 createToolbar : function(){
19938 Roo.log("create toolbars");
19940 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19941 this.toolbars[0].render(this.toolbarContainer());
19945 // if (!editor.toolbars || !editor.toolbars.length) {
19946 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19949 // for (var i =0 ; i < editor.toolbars.length;i++) {
19950 // editor.toolbars[i] = Roo.factory(
19951 // typeof(editor.toolbars[i]) == 'string' ?
19952 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19953 // Roo.bootstrap.HtmlEditor);
19954 // editor.toolbars[i].init(editor);
19960 onRender : function(ct, position)
19962 // Roo.log("Call onRender: " + this.xtype);
19964 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19966 this.wrap = this.inputEl().wrap({
19967 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19970 this.editorcore.onRender(ct, position);
19972 if (this.resizable) {
19973 this.resizeEl = new Roo.Resizable(this.wrap, {
19977 minHeight : this.height,
19978 height: this.height,
19979 handles : this.resizable,
19982 resize : function(r, w, h) {
19983 _t.onResize(w,h); // -something
19989 this.createToolbar(this);
19992 if(!this.width && this.resizable){
19993 this.setSize(this.wrap.getSize());
19995 if (this.resizeEl) {
19996 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19997 // should trigger onReize..
20003 onResize : function(w, h)
20005 Roo.log('resize: ' +w + ',' + h );
20006 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20010 if(this.inputEl() ){
20011 if(typeof w == 'number'){
20012 var aw = w - this.wrap.getFrameWidth('lr');
20013 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20016 if(typeof h == 'number'){
20017 var tbh = -11; // fixme it needs to tool bar size!
20018 for (var i =0; i < this.toolbars.length;i++) {
20019 // fixme - ask toolbars for heights?
20020 tbh += this.toolbars[i].el.getHeight();
20021 //if (this.toolbars[i].footer) {
20022 // tbh += this.toolbars[i].footer.el.getHeight();
20030 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20031 ah -= 5; // knock a few pixes off for look..
20032 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20036 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20037 this.editorcore.onResize(ew,eh);
20042 * Toggles the editor between standard and source edit mode.
20043 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20045 toggleSourceEdit : function(sourceEditMode)
20047 this.editorcore.toggleSourceEdit(sourceEditMode);
20049 if(this.editorcore.sourceEditMode){
20050 Roo.log('editor - showing textarea');
20053 // Roo.log(this.syncValue());
20055 this.inputEl().removeClass(['hide', 'x-hidden']);
20056 this.inputEl().dom.removeAttribute('tabIndex');
20057 this.inputEl().focus();
20059 Roo.log('editor - hiding textarea');
20061 // Roo.log(this.pushValue());
20064 this.inputEl().addClass(['hide', 'x-hidden']);
20065 this.inputEl().dom.setAttribute('tabIndex', -1);
20066 //this.deferFocus();
20069 if(this.resizable){
20070 this.setSize(this.wrap.getSize());
20073 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20076 // private (for BoxComponent)
20077 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20079 // private (for BoxComponent)
20080 getResizeEl : function(){
20084 // private (for BoxComponent)
20085 getPositionEl : function(){
20090 initEvents : function(){
20091 this.originalValue = this.getValue();
20095 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20098 // markInvalid : Roo.emptyFn,
20100 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20103 // clearInvalid : Roo.emptyFn,
20105 setValue : function(v){
20106 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20107 this.editorcore.pushValue();
20112 deferFocus : function(){
20113 this.focus.defer(10, this);
20117 focus : function(){
20118 this.editorcore.focus();
20124 onDestroy : function(){
20130 for (var i =0; i < this.toolbars.length;i++) {
20131 // fixme - ask toolbars for heights?
20132 this.toolbars[i].onDestroy();
20135 this.wrap.dom.innerHTML = '';
20136 this.wrap.remove();
20141 onFirstFocus : function(){
20142 //Roo.log("onFirstFocus");
20143 this.editorcore.onFirstFocus();
20144 for (var i =0; i < this.toolbars.length;i++) {
20145 this.toolbars[i].onFirstFocus();
20151 syncValue : function()
20153 this.editorcore.syncValue();
20156 pushValue : function()
20158 this.editorcore.pushValue();
20162 // hide stuff that is not compatible
20176 * @event specialkey
20180 * @cfg {String} fieldClass @hide
20183 * @cfg {String} focusClass @hide
20186 * @cfg {String} autoCreate @hide
20189 * @cfg {String} inputType @hide
20192 * @cfg {String} invalidClass @hide
20195 * @cfg {String} invalidText @hide
20198 * @cfg {String} msgFx @hide
20201 * @cfg {String} validateOnBlur @hide
20210 Roo.namespace('Roo.bootstrap.htmleditor');
20212 * @class Roo.bootstrap.HtmlEditorToolbar1
20217 new Roo.bootstrap.HtmlEditor({
20220 new Roo.bootstrap.HtmlEditorToolbar1({
20221 disable : { fonts: 1 , format: 1, ..., ... , ...],
20227 * @cfg {Object} disable List of elements to disable..
20228 * @cfg {Array} btns List of additional buttons.
20232 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20235 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20238 Roo.apply(this, config);
20240 // default disabled, based on 'good practice'..
20241 this.disable = this.disable || {};
20242 Roo.applyIf(this.disable, {
20245 specialElements : true
20247 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20249 this.editor = config.editor;
20250 this.editorcore = config.editor.editorcore;
20252 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20254 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20255 // dont call parent... till later.
20257 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20262 editorcore : false,
20267 "h1","h2","h3","h4","h5","h6",
20269 "abbr", "acronym", "address", "cite", "samp", "var",
20273 onRender : function(ct, position)
20275 // Roo.log("Call onRender: " + this.xtype);
20277 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20279 this.el.dom.style.marginBottom = '0';
20281 var editorcore = this.editorcore;
20282 var editor= this.editor;
20285 var btn = function(id,cmd , toggle, handler){
20287 var event = toggle ? 'toggle' : 'click';
20292 xns: Roo.bootstrap,
20295 enableToggle:toggle !== false,
20297 pressed : toggle ? false : null,
20300 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20301 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20310 xns: Roo.bootstrap,
20311 glyphicon : 'font',
20315 xns: Roo.bootstrap,
20319 Roo.each(this.formats, function(f) {
20320 style.menu.items.push({
20322 xns: Roo.bootstrap,
20323 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20328 editorcore.insertTag(this.tagname);
20335 children.push(style);
20338 btn('bold',false,true);
20339 btn('italic',false,true);
20340 btn('align-left', 'justifyleft',true);
20341 btn('align-center', 'justifycenter',true);
20342 btn('align-right' , 'justifyright',true);
20343 btn('link', false, false, function(btn) {
20344 //Roo.log("create link?");
20345 var url = prompt(this.createLinkText, this.defaultLinkValue);
20346 if(url && url != 'http:/'+'/'){
20347 this.editorcore.relayCmd('createlink', url);
20350 btn('list','insertunorderedlist',true);
20351 btn('pencil', false,true, function(btn){
20354 this.toggleSourceEdit(btn.pressed);
20360 xns: Roo.bootstrap,
20365 xns: Roo.bootstrap,
20370 cog.menu.items.push({
20372 xns: Roo.bootstrap,
20373 html : Clean styles,
20378 editorcore.insertTag(this.tagname);
20387 this.xtype = 'NavSimplebar';
20389 for(var i=0;i< children.length;i++) {
20391 this.buttons.add(this.addxtypeChild(children[i]));
20395 editor.on('editorevent', this.updateToolbar, this);
20397 onBtnClick : function(id)
20399 this.editorcore.relayCmd(id);
20400 this.editorcore.focus();
20404 * Protected method that will not generally be called directly. It triggers
20405 * a toolbar update by reading the markup state of the current selection in the editor.
20407 updateToolbar: function(){
20409 if(!this.editorcore.activated){
20410 this.editor.onFirstFocus(); // is this neeed?
20414 var btns = this.buttons;
20415 var doc = this.editorcore.doc;
20416 btns.get('bold').setActive(doc.queryCommandState('bold'));
20417 btns.get('italic').setActive(doc.queryCommandState('italic'));
20418 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20420 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20421 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20422 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20424 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20425 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20428 var ans = this.editorcore.getAllAncestors();
20429 if (this.formatCombo) {
20432 var store = this.formatCombo.store;
20433 this.formatCombo.setValue("");
20434 for (var i =0; i < ans.length;i++) {
20435 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20437 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20445 // hides menus... - so this cant be on a menu...
20446 Roo.bootstrap.MenuMgr.hideAll();
20448 Roo.bootstrap.MenuMgr.hideAll();
20449 //this.editorsyncValue();
20451 onFirstFocus: function() {
20452 this.buttons.each(function(item){
20456 toggleSourceEdit : function(sourceEditMode){
20459 if(sourceEditMode){
20460 Roo.log("disabling buttons");
20461 this.buttons.each( function(item){
20462 if(item.cmd != 'pencil'){
20468 Roo.log("enabling buttons");
20469 if(this.editorcore.initialized){
20470 this.buttons.each( function(item){
20476 Roo.log("calling toggole on editor");
20477 // tell the editor that it's been pressed..
20478 this.editor.toggleSourceEdit(sourceEditMode);
20488 * @class Roo.bootstrap.Table.AbstractSelectionModel
20489 * @extends Roo.util.Observable
20490 * Abstract base class for grid SelectionModels. It provides the interface that should be
20491 * implemented by descendant classes. This class should not be directly instantiated.
20494 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20495 this.locked = false;
20496 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20500 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20501 /** @ignore Called by the grid automatically. Do not call directly. */
20502 init : function(grid){
20508 * Locks the selections.
20511 this.locked = true;
20515 * Unlocks the selections.
20517 unlock : function(){
20518 this.locked = false;
20522 * Returns true if the selections are locked.
20523 * @return {Boolean}
20525 isLocked : function(){
20526 return this.locked;
20530 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20531 * @class Roo.bootstrap.Table.RowSelectionModel
20532 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20533 * It supports multiple selections and keyboard selection/navigation.
20535 * @param {Object} config
20538 Roo.bootstrap.Table.RowSelectionModel = function(config){
20539 Roo.apply(this, config);
20540 this.selections = new Roo.util.MixedCollection(false, function(o){
20545 this.lastActive = false;
20549 * @event selectionchange
20550 * Fires when the selection changes
20551 * @param {SelectionModel} this
20553 "selectionchange" : true,
20555 * @event afterselectionchange
20556 * Fires after the selection changes (eg. by key press or clicking)
20557 * @param {SelectionModel} this
20559 "afterselectionchange" : true,
20561 * @event beforerowselect
20562 * Fires when a row is selected being selected, return false to cancel.
20563 * @param {SelectionModel} this
20564 * @param {Number} rowIndex The selected index
20565 * @param {Boolean} keepExisting False if other selections will be cleared
20567 "beforerowselect" : true,
20570 * Fires when a row is selected.
20571 * @param {SelectionModel} this
20572 * @param {Number} rowIndex The selected index
20573 * @param {Roo.data.Record} r The record
20575 "rowselect" : true,
20577 * @event rowdeselect
20578 * Fires when a row is deselected.
20579 * @param {SelectionModel} this
20580 * @param {Number} rowIndex The selected index
20582 "rowdeselect" : true
20584 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20585 this.locked = false;
20588 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20590 * @cfg {Boolean} singleSelect
20591 * True to allow selection of only one row at a time (defaults to false)
20593 singleSelect : false,
20596 initEvents : function(){
20598 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20599 this.grid.on("mousedown", this.handleMouseDown, this);
20600 }else{ // allow click to work like normal
20601 this.grid.on("rowclick", this.handleDragableRowClick, this);
20604 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20605 "up" : function(e){
20607 this.selectPrevious(e.shiftKey);
20608 }else if(this.last !== false && this.lastActive !== false){
20609 var last = this.last;
20610 this.selectRange(this.last, this.lastActive-1);
20611 this.grid.getView().focusRow(this.lastActive);
20612 if(last !== false){
20616 this.selectFirstRow();
20618 this.fireEvent("afterselectionchange", this);
20620 "down" : function(e){
20622 this.selectNext(e.shiftKey);
20623 }else if(this.last !== false && this.lastActive !== false){
20624 var last = this.last;
20625 this.selectRange(this.last, this.lastActive+1);
20626 this.grid.getView().focusRow(this.lastActive);
20627 if(last !== false){
20631 this.selectFirstRow();
20633 this.fireEvent("afterselectionchange", this);
20638 var view = this.grid.view;
20639 view.on("refresh", this.onRefresh, this);
20640 view.on("rowupdated", this.onRowUpdated, this);
20641 view.on("rowremoved", this.onRemove, this);
20645 onRefresh : function(){
20646 var ds = this.grid.dataSource, i, v = this.grid.view;
20647 var s = this.selections;
20648 s.each(function(r){
20649 if((i = ds.indexOfId(r.id)) != -1){
20658 onRemove : function(v, index, r){
20659 this.selections.remove(r);
20663 onRowUpdated : function(v, index, r){
20664 if(this.isSelected(r)){
20665 v.onRowSelect(index);
20671 * @param {Array} records The records to select
20672 * @param {Boolean} keepExisting (optional) True to keep existing selections
20674 selectRecords : function(records, keepExisting){
20676 this.clearSelections();
20678 var ds = this.grid.dataSource;
20679 for(var i = 0, len = records.length; i < len; i++){
20680 this.selectRow(ds.indexOf(records[i]), true);
20685 * Gets the number of selected rows.
20688 getCount : function(){
20689 return this.selections.length;
20693 * Selects the first row in the grid.
20695 selectFirstRow : function(){
20700 * Select the last row.
20701 * @param {Boolean} keepExisting (optional) True to keep existing selections
20703 selectLastRow : function(keepExisting){
20704 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20708 * Selects the row immediately following the last selected row.
20709 * @param {Boolean} keepExisting (optional) True to keep existing selections
20711 selectNext : function(keepExisting){
20712 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20713 this.selectRow(this.last+1, keepExisting);
20714 this.grid.getView().focusRow(this.last);
20719 * Selects the row that precedes the last selected row.
20720 * @param {Boolean} keepExisting (optional) True to keep existing selections
20722 selectPrevious : function(keepExisting){
20724 this.selectRow(this.last-1, keepExisting);
20725 this.grid.getView().focusRow(this.last);
20730 * Returns the selected records
20731 * @return {Array} Array of selected records
20733 getSelections : function(){
20734 return [].concat(this.selections.items);
20738 * Returns the first selected record.
20741 getSelected : function(){
20742 return this.selections.itemAt(0);
20747 * Clears all selections.
20749 clearSelections : function(fast){
20750 if(this.locked) return;
20752 var ds = this.grid.dataSource;
20753 var s = this.selections;
20754 s.each(function(r){
20755 this.deselectRow(ds.indexOfId(r.id));
20759 this.selections.clear();
20766 * Selects all rows.
20768 selectAll : function(){
20769 if(this.locked) return;
20770 this.selections.clear();
20771 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20772 this.selectRow(i, true);
20777 * Returns True if there is a selection.
20778 * @return {Boolean}
20780 hasSelection : function(){
20781 return this.selections.length > 0;
20785 * Returns True if the specified row is selected.
20786 * @param {Number/Record} record The record or index of the record to check
20787 * @return {Boolean}
20789 isSelected : function(index){
20790 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20791 return (r && this.selections.key(r.id) ? true : false);
20795 * Returns True if the specified record id is selected.
20796 * @param {String} id The id of record to check
20797 * @return {Boolean}
20799 isIdSelected : function(id){
20800 return (this.selections.key(id) ? true : false);
20804 handleMouseDown : function(e, t){
20805 var view = this.grid.getView(), rowIndex;
20806 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20809 if(e.shiftKey && this.last !== false){
20810 var last = this.last;
20811 this.selectRange(last, rowIndex, e.ctrlKey);
20812 this.last = last; // reset the last
20813 view.focusRow(rowIndex);
20815 var isSelected = this.isSelected(rowIndex);
20816 if(e.button !== 0 && isSelected){
20817 view.focusRow(rowIndex);
20818 }else if(e.ctrlKey && isSelected){
20819 this.deselectRow(rowIndex);
20820 }else if(!isSelected){
20821 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20822 view.focusRow(rowIndex);
20825 this.fireEvent("afterselectionchange", this);
20828 handleDragableRowClick : function(grid, rowIndex, e)
20830 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20831 this.selectRow(rowIndex, false);
20832 grid.view.focusRow(rowIndex);
20833 this.fireEvent("afterselectionchange", this);
20838 * Selects multiple rows.
20839 * @param {Array} rows Array of the indexes of the row to select
20840 * @param {Boolean} keepExisting (optional) True to keep existing selections
20842 selectRows : function(rows, keepExisting){
20844 this.clearSelections();
20846 for(var i = 0, len = rows.length; i < len; i++){
20847 this.selectRow(rows[i], true);
20852 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20853 * @param {Number} startRow The index of the first row in the range
20854 * @param {Number} endRow The index of the last row in the range
20855 * @param {Boolean} keepExisting (optional) True to retain existing selections
20857 selectRange : function(startRow, endRow, keepExisting){
20858 if(this.locked) return;
20860 this.clearSelections();
20862 if(startRow <= endRow){
20863 for(var i = startRow; i <= endRow; i++){
20864 this.selectRow(i, true);
20867 for(var i = startRow; i >= endRow; i--){
20868 this.selectRow(i, true);
20874 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20875 * @param {Number} startRow The index of the first row in the range
20876 * @param {Number} endRow The index of the last row in the range
20878 deselectRange : function(startRow, endRow, preventViewNotify){
20879 if(this.locked) return;
20880 for(var i = startRow; i <= endRow; i++){
20881 this.deselectRow(i, preventViewNotify);
20887 * @param {Number} row The index of the row to select
20888 * @param {Boolean} keepExisting (optional) True to keep existing selections
20890 selectRow : function(index, keepExisting, preventViewNotify){
20891 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20892 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20893 if(!keepExisting || this.singleSelect){
20894 this.clearSelections();
20896 var r = this.grid.dataSource.getAt(index);
20897 this.selections.add(r);
20898 this.last = this.lastActive = index;
20899 if(!preventViewNotify){
20900 this.grid.getView().onRowSelect(index);
20902 this.fireEvent("rowselect", this, index, r);
20903 this.fireEvent("selectionchange", this);
20909 * @param {Number} row The index of the row to deselect
20911 deselectRow : function(index, preventViewNotify){
20912 if(this.locked) return;
20913 if(this.last == index){
20916 if(this.lastActive == index){
20917 this.lastActive = false;
20919 var r = this.grid.dataSource.getAt(index);
20920 this.selections.remove(r);
20921 if(!preventViewNotify){
20922 this.grid.getView().onRowDeselect(index);
20924 this.fireEvent("rowdeselect", this, index);
20925 this.fireEvent("selectionchange", this);
20929 restoreLast : function(){
20931 this.last = this._last;
20936 acceptsNav : function(row, col, cm){
20937 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20941 onEditorKey : function(field, e){
20942 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20947 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20949 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20951 }else if(k == e.ENTER && !e.ctrlKey){
20955 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20957 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20959 }else if(k == e.ESC){
20963 g.startEditing(newCell[0], newCell[1]);
20968 * Ext JS Library 1.1.1
20969 * Copyright(c) 2006-2007, Ext JS, LLC.
20971 * Originally Released Under LGPL - original licence link has changed is not relivant.
20974 * <script type="text/javascript">
20978 * @class Roo.bootstrap.PagingToolbar
20980 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20982 * Create a new PagingToolbar
20983 * @param {Object} config The config object
20985 Roo.bootstrap.PagingToolbar = function(config)
20987 // old args format still supported... - xtype is prefered..
20988 // created from xtype...
20989 var ds = config.dataSource;
20990 this.toolbarItems = [];
20991 if (config.items) {
20992 this.toolbarItems = config.items;
20993 // config.items = [];
20996 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
21003 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21007 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21009 * @cfg {Roo.data.Store} dataSource
21010 * The underlying data store providing the paged data
21013 * @cfg {String/HTMLElement/Element} container
21014 * container The id or element that will contain the toolbar
21017 * @cfg {Boolean} displayInfo
21018 * True to display the displayMsg (defaults to false)
21021 * @cfg {Number} pageSize
21022 * The number of records to display per page (defaults to 20)
21026 * @cfg {String} displayMsg
21027 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21029 displayMsg : 'Displaying {0} - {1} of {2}',
21031 * @cfg {String} emptyMsg
21032 * The message to display when no records are found (defaults to "No data to display")
21034 emptyMsg : 'No data to display',
21036 * Customizable piece of the default paging text (defaults to "Page")
21039 beforePageText : "Page",
21041 * Customizable piece of the default paging text (defaults to "of %0")
21044 afterPageText : "of {0}",
21046 * Customizable piece of the default paging text (defaults to "First Page")
21049 firstText : "First Page",
21051 * Customizable piece of the default paging text (defaults to "Previous Page")
21054 prevText : "Previous Page",
21056 * Customizable piece of the default paging text (defaults to "Next Page")
21059 nextText : "Next Page",
21061 * Customizable piece of the default paging text (defaults to "Last Page")
21064 lastText : "Last Page",
21066 * Customizable piece of the default paging text (defaults to "Refresh")
21069 refreshText : "Refresh",
21073 onRender : function(ct, position)
21075 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21076 this.navgroup.parentId = this.id;
21077 this.navgroup.onRender(this.el, null);
21078 // add the buttons to the navgroup
21080 if(this.displayInfo){
21081 Roo.log(this.el.select('ul.navbar-nav',true).first());
21082 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21083 this.displayEl = this.el.select('.x-paging-info', true).first();
21084 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21085 // this.displayEl = navel.el.select('span',true).first();
21091 Roo.each(_this.buttons, function(e){
21092 Roo.factory(e).onRender(_this.el, null);
21096 Roo.each(_this.toolbarItems, function(e) {
21097 _this.navgroup.addItem(e);
21101 this.first = this.navgroup.addItem({
21102 tooltip: this.firstText,
21104 icon : 'fa fa-backward',
21106 preventDefault: true,
21107 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21110 this.prev = this.navgroup.addItem({
21111 tooltip: this.prevText,
21113 icon : 'fa fa-step-backward',
21115 preventDefault: true,
21116 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21118 //this.addSeparator();
21121 var field = this.navgroup.addItem( {
21123 cls : 'x-paging-position',
21125 html : this.beforePageText +
21126 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21127 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21130 this.field = field.el.select('input', true).first();
21131 this.field.on("keydown", this.onPagingKeydown, this);
21132 this.field.on("focus", function(){this.dom.select();});
21135 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21136 //this.field.setHeight(18);
21137 //this.addSeparator();
21138 this.next = this.navgroup.addItem({
21139 tooltip: this.nextText,
21141 html : ' <i class="fa fa-step-forward">',
21143 preventDefault: true,
21144 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21146 this.last = this.navgroup.addItem({
21147 tooltip: this.lastText,
21148 icon : 'fa fa-forward',
21151 preventDefault: true,
21152 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21154 //this.addSeparator();
21155 this.loading = this.navgroup.addItem({
21156 tooltip: this.refreshText,
21157 icon: 'fa fa-refresh',
21158 preventDefault: true,
21159 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21165 updateInfo : function(){
21166 if(this.displayEl){
21167 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21168 var msg = count == 0 ?
21172 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21174 this.displayEl.update(msg);
21179 onLoad : function(ds, r, o){
21180 this.cursor = o.params ? o.params.start : 0;
21181 var d = this.getPageData(),
21185 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21186 this.field.dom.value = ap;
21187 this.first.setDisabled(ap == 1);
21188 this.prev.setDisabled(ap == 1);
21189 this.next.setDisabled(ap == ps);
21190 this.last.setDisabled(ap == ps);
21191 this.loading.enable();
21196 getPageData : function(){
21197 var total = this.ds.getTotalCount();
21200 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21201 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21206 onLoadError : function(){
21207 this.loading.enable();
21211 onPagingKeydown : function(e){
21212 var k = e.getKey();
21213 var d = this.getPageData();
21215 var v = this.field.dom.value, pageNum;
21216 if(!v || isNaN(pageNum = parseInt(v, 10))){
21217 this.field.dom.value = d.activePage;
21220 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21221 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21224 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))
21226 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21227 this.field.dom.value = pageNum;
21228 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21231 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21233 var v = this.field.dom.value, pageNum;
21234 var increment = (e.shiftKey) ? 10 : 1;
21235 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21237 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21238 this.field.dom.value = d.activePage;
21241 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21243 this.field.dom.value = parseInt(v, 10) + increment;
21244 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21245 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21252 beforeLoad : function(){
21254 this.loading.disable();
21259 onClick : function(which){
21268 ds.load({params:{start: 0, limit: this.pageSize}});
21271 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21274 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21277 var total = ds.getTotalCount();
21278 var extra = total % this.pageSize;
21279 var lastStart = extra ? (total - extra) : total-this.pageSize;
21280 ds.load({params:{start: lastStart, limit: this.pageSize}});
21283 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21289 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21290 * @param {Roo.data.Store} store The data store to unbind
21292 unbind : function(ds){
21293 ds.un("beforeload", this.beforeLoad, this);
21294 ds.un("load", this.onLoad, this);
21295 ds.un("loadexception", this.onLoadError, this);
21296 ds.un("remove", this.updateInfo, this);
21297 ds.un("add", this.updateInfo, this);
21298 this.ds = undefined;
21302 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21303 * @param {Roo.data.Store} store The data store to bind
21305 bind : function(ds){
21306 ds.on("beforeload", this.beforeLoad, this);
21307 ds.on("load", this.onLoad, this);
21308 ds.on("loadexception", this.onLoadError, this);
21309 ds.on("remove", this.updateInfo, this);
21310 ds.on("add", this.updateInfo, this);
21321 * @class Roo.bootstrap.MessageBar
21322 * @extends Roo.bootstrap.Component
21323 * Bootstrap MessageBar class
21324 * @cfg {String} html contents of the MessageBar
21325 * @cfg {String} weight (info | success | warning | danger) default info
21326 * @cfg {String} beforeClass insert the bar before the given class
21327 * @cfg {Boolean} closable (true | false) default false
21328 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21331 * Create a new Element
21332 * @param {Object} config The config object
21335 Roo.bootstrap.MessageBar = function(config){
21336 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21339 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21345 beforeClass: 'bootstrap-sticky-wrap',
21347 getAutoCreate : function(){
21351 cls: 'alert alert-dismissable alert-' + this.weight,
21356 html: this.html || ''
21362 cfg.cls += ' alert-messages-fixed';
21376 onRender : function(ct, position)
21378 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21381 var cfg = Roo.apply({}, this.getAutoCreate());
21385 cfg.cls += ' ' + this.cls;
21388 cfg.style = this.style;
21390 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21392 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21395 this.el.select('>button.close').on('click', this.hide, this);
21401 if (!this.rendered) {
21407 this.fireEvent('show', this);
21413 if (!this.rendered) {
21419 this.fireEvent('hide', this);
21422 update : function()
21424 // var e = this.el.dom.firstChild;
21426 // if(this.closable){
21427 // e = e.nextSibling;
21430 // e.data = this.html || '';
21432 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21448 * @class Roo.bootstrap.Graph
21449 * @extends Roo.bootstrap.Component
21450 * Bootstrap Graph class
21454 @cfg {String} graphtype bar | vbar | pie
21455 @cfg {number} g_x coodinator | centre x (pie)
21456 @cfg {number} g_y coodinator | centre y (pie)
21457 @cfg {number} g_r radius (pie)
21458 @cfg {number} g_height height of the chart (respected by all elements in the set)
21459 @cfg {number} g_width width of the chart (respected by all elements in the set)
21460 @cfg {Object} title The title of the chart
21463 -opts (object) options for the chart
21465 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21466 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21468 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.
21469 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21471 o stretch (boolean)
21473 -opts (object) options for the pie
21476 o startAngle (number)
21477 o endAngle (number)
21481 * Create a new Input
21482 * @param {Object} config The config object
21485 Roo.bootstrap.Graph = function(config){
21486 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21492 * The img click event for the img.
21493 * @param {Roo.EventObject} e
21499 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21510 //g_colors: this.colors,
21517 getAutoCreate : function(){
21528 onRender : function(ct,position){
21529 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21530 this.raphael = Raphael(this.el.dom);
21532 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21533 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21534 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21535 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21537 r.text(160, 10, "Single Series Chart").attr(txtattr);
21538 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21539 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21540 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21542 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21543 r.barchart(330, 10, 300, 220, data1);
21544 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21545 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21548 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21549 // r.barchart(30, 30, 560, 250, xdata, {
21550 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21551 // axis : "0 0 1 1",
21552 // axisxlabels : xdata
21553 // //yvalues : cols,
21556 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21558 // this.load(null,xdata,{
21559 // axis : "0 0 1 1",
21560 // axisxlabels : xdata
21565 load : function(graphtype,xdata,opts){
21566 this.raphael.clear();
21568 graphtype = this.graphtype;
21573 var r = this.raphael,
21574 fin = function () {
21575 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21577 fout = function () {
21578 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21580 pfin = function() {
21581 this.sector.stop();
21582 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21585 this.label[0].stop();
21586 this.label[0].attr({ r: 7.5 });
21587 this.label[1].attr({ "font-weight": 800 });
21590 pfout = function() {
21591 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21594 this.label[0].animate({ r: 5 }, 500, "bounce");
21595 this.label[1].attr({ "font-weight": 400 });
21601 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21604 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21607 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21608 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21610 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21617 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21622 setTitle: function(o)
21627 initEvents: function() {
21630 this.el.on('click', this.onClick, this);
21634 onClick : function(e)
21636 Roo.log('img onclick');
21637 this.fireEvent('click', this, e);
21649 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21652 * @class Roo.bootstrap.dash.NumberBox
21653 * @extends Roo.bootstrap.Component
21654 * Bootstrap NumberBox class
21655 * @cfg {String} headline Box headline
21656 * @cfg {String} content Box content
21657 * @cfg {String} icon Box icon
21658 * @cfg {String} footer Footer text
21659 * @cfg {String} fhref Footer href
21662 * Create a new NumberBox
21663 * @param {Object} config The config object
21667 Roo.bootstrap.dash.NumberBox = function(config){
21668 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21672 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21681 getAutoCreate : function(){
21685 cls : 'small-box ',
21693 cls : 'roo-headline',
21694 html : this.headline
21698 cls : 'roo-content',
21699 html : this.content
21713 cls : 'ion ' + this.icon
21722 cls : 'small-box-footer',
21723 href : this.fhref || '#',
21727 cfg.cn.push(footer);
21734 onRender : function(ct,position){
21735 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21742 setHeadline: function (value)
21744 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21747 setFooter: function (value, href)
21749 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21752 this.el.select('a.small-box-footer',true).first().attr('href', href);
21757 setContent: function (value)
21759 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21762 initEvents: function()
21776 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21779 * @class Roo.bootstrap.dash.TabBox
21780 * @extends Roo.bootstrap.Component
21781 * Bootstrap TabBox class
21782 * @cfg {String} title Title of the TabBox
21783 * @cfg {String} icon Icon of the TabBox
21784 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21785 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21788 * Create a new TabBox
21789 * @param {Object} config The config object
21793 Roo.bootstrap.dash.TabBox = function(config){
21794 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21799 * When a pane is added
21800 * @param {Roo.bootstrap.dash.TabPane} pane
21804 * @event activatepane
21805 * When a pane is activated
21806 * @param {Roo.bootstrap.dash.TabPane} pane
21808 "activatepane" : true
21816 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21821 tabScrollable : false,
21823 getChildContainer : function()
21825 return this.el.select('.tab-content', true).first();
21828 getAutoCreate : function(){
21832 cls: 'pull-left header',
21840 cls: 'fa ' + this.icon
21846 cls: 'nav nav-tabs pull-right',
21852 if(this.tabScrollable){
21859 cls: 'nav nav-tabs pull-right',
21870 cls: 'nav-tabs-custom',
21875 cls: 'tab-content no-padding',
21883 initEvents : function()
21885 //Roo.log('add add pane handler');
21886 this.on('addpane', this.onAddPane, this);
21889 * Updates the box title
21890 * @param {String} html to set the title to.
21892 setTitle : function(value)
21894 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21896 onAddPane : function(pane)
21898 this.panes.push(pane);
21899 //Roo.log('addpane');
21901 // tabs are rendere left to right..
21902 if(!this.showtabs){
21906 var ctr = this.el.select('.nav-tabs', true).first();
21909 var existing = ctr.select('.nav-tab',true);
21910 var qty = existing.getCount();;
21913 var tab = ctr.createChild({
21915 cls : 'nav-tab' + (qty ? '' : ' active'),
21923 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21926 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21928 pane.el.addClass('active');
21933 onTabClick : function(ev,un,ob,pane)
21935 //Roo.log('tab - prev default');
21936 ev.preventDefault();
21939 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21940 pane.tab.addClass('active');
21941 //Roo.log(pane.title);
21942 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21943 // technically we should have a deactivate event.. but maybe add later.
21944 // and it should not de-activate the selected tab...
21945 this.fireEvent('activatepane', pane);
21946 pane.el.addClass('active');
21947 pane.fireEvent('activate');
21952 getActivePane : function()
21955 Roo.each(this.panes, function(p) {
21956 if(p.el.hasClass('active')){
21977 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21979 * @class Roo.bootstrap.TabPane
21980 * @extends Roo.bootstrap.Component
21981 * Bootstrap TabPane class
21982 * @cfg {Boolean} active (false | true) Default false
21983 * @cfg {String} title title of panel
21987 * Create a new TabPane
21988 * @param {Object} config The config object
21991 Roo.bootstrap.dash.TabPane = function(config){
21992 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21998 * When a pane is activated
21999 * @param {Roo.bootstrap.dash.TabPane} pane
22006 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22011 // the tabBox that this is attached to.
22014 getAutoCreate : function()
22022 cfg.cls += ' active';
22027 initEvents : function()
22029 //Roo.log('trigger add pane handler');
22030 this.parent().fireEvent('addpane', this)
22034 * Updates the tab title
22035 * @param {String} html to set the title to.
22037 setTitle: function(str)
22043 this.tab.select('a', true).first().dom.innerHTML = str;
22060 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22063 * @class Roo.bootstrap.menu.Menu
22064 * @extends Roo.bootstrap.Component
22065 * Bootstrap Menu class - container for Menu
22066 * @cfg {String} html Text of the menu
22067 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22068 * @cfg {String} icon Font awesome icon
22069 * @cfg {String} pos Menu align to (top | bottom) default bottom
22073 * Create a new Menu
22074 * @param {Object} config The config object
22078 Roo.bootstrap.menu.Menu = function(config){
22079 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22083 * @event beforeshow
22084 * Fires before this menu is displayed
22085 * @param {Roo.bootstrap.menu.Menu} this
22089 * @event beforehide
22090 * Fires before this menu is hidden
22091 * @param {Roo.bootstrap.menu.Menu} this
22096 * Fires after this menu is displayed
22097 * @param {Roo.bootstrap.menu.Menu} this
22102 * Fires after this menu is hidden
22103 * @param {Roo.bootstrap.menu.Menu} this
22108 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22109 * @param {Roo.bootstrap.menu.Menu} this
22110 * @param {Roo.EventObject} e
22117 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22121 weight : 'default',
22126 getChildContainer : function() {
22127 if(this.isSubMenu){
22131 return this.el.select('ul.dropdown-menu', true).first();
22134 getAutoCreate : function()
22139 cls : 'roo-menu-text',
22147 cls : 'fa ' + this.icon
22158 cls : 'dropdown-button btn btn-' + this.weight,
22163 cls : 'dropdown-toggle btn btn-' + this.weight,
22173 cls : 'dropdown-menu'
22179 if(this.pos == 'top'){
22180 cfg.cls += ' dropup';
22183 if(this.isSubMenu){
22186 cls : 'dropdown-menu'
22193 onRender : function(ct, position)
22195 this.isSubMenu = ct.hasClass('dropdown-submenu');
22197 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22200 initEvents : function()
22202 if(this.isSubMenu){
22206 this.hidden = true;
22208 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22209 this.triggerEl.on('click', this.onTriggerPress, this);
22211 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22212 this.buttonEl.on('click', this.onClick, this);
22218 if(this.isSubMenu){
22222 return this.el.select('ul.dropdown-menu', true).first();
22225 onClick : function(e)
22227 this.fireEvent("click", this, e);
22230 onTriggerPress : function(e)
22232 if (this.isVisible()) {
22239 isVisible : function(){
22240 return !this.hidden;
22245 this.fireEvent("beforeshow", this);
22247 this.hidden = false;
22248 this.el.addClass('open');
22250 Roo.get(document).on("mouseup", this.onMouseUp, this);
22252 this.fireEvent("show", this);
22259 this.fireEvent("beforehide", this);
22261 this.hidden = true;
22262 this.el.removeClass('open');
22264 Roo.get(document).un("mouseup", this.onMouseUp);
22266 this.fireEvent("hide", this);
22269 onMouseUp : function()
22283 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22286 * @class Roo.bootstrap.menu.Item
22287 * @extends Roo.bootstrap.Component
22288 * Bootstrap MenuItem class
22289 * @cfg {Boolean} submenu (true | false) default false
22290 * @cfg {String} html text of the item
22291 * @cfg {String} href the link
22292 * @cfg {Boolean} disable (true | false) default false
22293 * @cfg {Boolean} preventDefault (true | false) default true
22294 * @cfg {String} icon Font awesome icon
22295 * @cfg {String} pos Submenu align to (left | right) default right
22299 * Create a new Item
22300 * @param {Object} config The config object
22304 Roo.bootstrap.menu.Item = function(config){
22305 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22309 * Fires when the mouse is hovering over this menu
22310 * @param {Roo.bootstrap.menu.Item} this
22311 * @param {Roo.EventObject} e
22316 * Fires when the mouse exits this menu
22317 * @param {Roo.bootstrap.menu.Item} this
22318 * @param {Roo.EventObject} e
22324 * The raw click event for the entire grid.
22325 * @param {Roo.EventObject} e
22331 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22336 preventDefault: true,
22341 getAutoCreate : function()
22346 cls : 'roo-menu-item-text',
22354 cls : 'fa ' + this.icon
22363 href : this.href || '#',
22370 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22374 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22376 if(this.pos == 'left'){
22377 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22384 initEvents : function()
22386 this.el.on('mouseover', this.onMouseOver, this);
22387 this.el.on('mouseout', this.onMouseOut, this);
22389 this.el.select('a', true).first().on('click', this.onClick, this);
22393 onClick : function(e)
22395 if(this.preventDefault){
22396 e.preventDefault();
22399 this.fireEvent("click", this, e);
22402 onMouseOver : function(e)
22404 if(this.submenu && this.pos == 'left'){
22405 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22408 this.fireEvent("mouseover", this, e);
22411 onMouseOut : function(e)
22413 this.fireEvent("mouseout", this, e);
22425 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22428 * @class Roo.bootstrap.menu.Separator
22429 * @extends Roo.bootstrap.Component
22430 * Bootstrap Separator class
22433 * Create a new Separator
22434 * @param {Object} config The config object
22438 Roo.bootstrap.menu.Separator = function(config){
22439 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22442 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22444 getAutoCreate : function(){
22465 * @class Roo.bootstrap.Tooltip
22466 * Bootstrap Tooltip class
22467 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22468 * to determine which dom element triggers the tooltip.
22470 * It needs to add support for additional attributes like tooltip-position
22473 * Create a new Toolti
22474 * @param {Object} config The config object
22477 Roo.bootstrap.Tooltip = function(config){
22478 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22481 Roo.apply(Roo.bootstrap.Tooltip, {
22483 * @function init initialize tooltip monitoring.
22487 currentTip : false,
22488 currentRegion : false,
22494 Roo.get(document).on('mouseover', this.enter ,this);
22495 Roo.get(document).on('mouseout', this.leave, this);
22498 this.currentTip = new Roo.bootstrap.Tooltip();
22501 enter : function(ev)
22503 var dom = ev.getTarget();
22505 //Roo.log(['enter',dom]);
22506 var el = Roo.fly(dom);
22507 if (this.currentEl) {
22509 //Roo.log(this.currentEl);
22510 //Roo.log(this.currentEl.contains(dom));
22511 if (this.currentEl == el) {
22514 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22522 if (this.currentTip.el) {
22523 this.currentTip.el.hide(); // force hiding...
22528 // you can not look for children, as if el is the body.. then everythign is the child..
22529 if (!el.attr('tooltip')) { //
22530 if (!el.select("[tooltip]").elements.length) {
22533 // is the mouse over this child...?
22534 bindEl = el.select("[tooltip]").first();
22535 var xy = ev.getXY();
22536 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22537 //Roo.log("not in region.");
22540 //Roo.log("child element over..");
22543 this.currentEl = bindEl;
22544 this.currentTip.bind(bindEl);
22545 this.currentRegion = Roo.lib.Region.getRegion(dom);
22546 this.currentTip.enter();
22549 leave : function(ev)
22551 var dom = ev.getTarget();
22552 //Roo.log(['leave',dom]);
22553 if (!this.currentEl) {
22558 if (dom != this.currentEl.dom) {
22561 var xy = ev.getXY();
22562 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22565 // only activate leave if mouse cursor is outside... bounding box..
22570 if (this.currentTip) {
22571 this.currentTip.leave();
22573 //Roo.log('clear currentEl');
22574 this.currentEl = false;
22579 'left' : ['r-l', [-2,0], 'right'],
22580 'right' : ['l-r', [2,0], 'left'],
22581 'bottom' : ['t-b', [0,2], 'top'],
22582 'top' : [ 'b-t', [0,-2], 'bottom']
22588 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22593 delay : null, // can be { show : 300 , hide: 500}
22597 hoverState : null, //???
22599 placement : 'bottom',
22601 getAutoCreate : function(){
22608 cls : 'tooltip-arrow'
22611 cls : 'tooltip-inner'
22618 bind : function(el)
22624 enter : function () {
22626 if (this.timeout != null) {
22627 clearTimeout(this.timeout);
22630 this.hoverState = 'in';
22631 //Roo.log("enter - show");
22632 if (!this.delay || !this.delay.show) {
22637 this.timeout = setTimeout(function () {
22638 if (_t.hoverState == 'in') {
22641 }, this.delay.show);
22645 clearTimeout(this.timeout);
22647 this.hoverState = 'out';
22648 if (!this.delay || !this.delay.hide) {
22654 this.timeout = setTimeout(function () {
22655 //Roo.log("leave - timeout");
22657 if (_t.hoverState == 'out') {
22659 Roo.bootstrap.Tooltip.currentEl = false;
22667 this.render(document.body);
22670 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22672 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22674 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22676 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22678 var placement = typeof this.placement == 'function' ?
22679 this.placement.call(this, this.el, on_el) :
22682 var autoToken = /\s?auto?\s?/i;
22683 var autoPlace = autoToken.test(placement);
22685 placement = placement.replace(autoToken, '') || 'top';
22689 //this.el.setXY([0,0]);
22691 //this.el.dom.style.display='block';
22692 this.el.addClass(placement);
22694 //this.el.appendTo(on_el);
22696 var p = this.getPosition();
22697 var box = this.el.getBox();
22702 var align = Roo.bootstrap.Tooltip.alignment[placement];
22703 this.el.alignTo(this.bindEl, align[0],align[1]);
22704 //var arrow = this.el.select('.arrow',true).first();
22705 //arrow.set(align[2],
22707 this.el.addClass('in fade');
22708 this.hoverState = null;
22710 if (this.el.hasClass('fade')) {
22721 //this.el.setXY([0,0]);
22722 this.el.removeClass('in');
22738 * @class Roo.bootstrap.LocationPicker
22739 * @extends Roo.bootstrap.Component
22740 * Bootstrap LocationPicker class
22741 * @cfg {Number} latitude Position when init default 0
22742 * @cfg {Number} longitude Position when init default 0
22743 * @cfg {Number} zoom default 15
22744 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22745 * @cfg {Boolean} mapTypeControl default false
22746 * @cfg {Boolean} disableDoubleClickZoom default false
22747 * @cfg {Boolean} scrollwheel default true
22748 * @cfg {Boolean} streetViewControl default false
22749 * @cfg {Number} radius default 0
22750 * @cfg {String} locationName
22751 * @cfg {Boolean} draggable default true
22752 * @cfg {Boolean} enableAutocomplete default false
22753 * @cfg {Boolean} enableReverseGeocode default true
22754 * @cfg {String} markerTitle
22757 * Create a new LocationPicker
22758 * @param {Object} config The config object
22762 Roo.bootstrap.LocationPicker = function(config){
22764 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22769 * Fires when the picker initialized.
22770 * @param {Roo.bootstrap.LocationPicker} this
22771 * @param {Google Location} location
22775 * @event positionchanged
22776 * Fires when the picker position changed.
22777 * @param {Roo.bootstrap.LocationPicker} this
22778 * @param {Google Location} location
22780 positionchanged : true,
22783 * Fires when the map resize.
22784 * @param {Roo.bootstrap.LocationPicker} this
22789 * Fires when the map show.
22790 * @param {Roo.bootstrap.LocationPicker} this
22795 * Fires when the map hide.
22796 * @param {Roo.bootstrap.LocationPicker} this
22801 * Fires when click the map.
22802 * @param {Roo.bootstrap.LocationPicker} this
22803 * @param {Map event} e
22807 * @event mapRightClick
22808 * Fires when right click the map.
22809 * @param {Roo.bootstrap.LocationPicker} this
22810 * @param {Map event} e
22812 mapRightClick : true,
22814 * @event markerClick
22815 * Fires when click the marker.
22816 * @param {Roo.bootstrap.LocationPicker} this
22817 * @param {Map event} e
22819 markerClick : true,
22821 * @event markerRightClick
22822 * Fires when right click the marker.
22823 * @param {Roo.bootstrap.LocationPicker} this
22824 * @param {Map event} e
22826 markerRightClick : true,
22828 * @event OverlayViewDraw
22829 * Fires when OverlayView Draw
22830 * @param {Roo.bootstrap.LocationPicker} this
22832 OverlayViewDraw : true,
22834 * @event OverlayViewOnAdd
22835 * Fires when OverlayView Draw
22836 * @param {Roo.bootstrap.LocationPicker} this
22838 OverlayViewOnAdd : true,
22840 * @event OverlayViewOnRemove
22841 * Fires when OverlayView Draw
22842 * @param {Roo.bootstrap.LocationPicker} this
22844 OverlayViewOnRemove : true,
22846 * @event OverlayViewShow
22847 * Fires when OverlayView Draw
22848 * @param {Roo.bootstrap.LocationPicker} this
22849 * @param {Pixel} cpx
22851 OverlayViewShow : true,
22853 * @event OverlayViewHide
22854 * Fires when OverlayView Draw
22855 * @param {Roo.bootstrap.LocationPicker} this
22857 OverlayViewHide : true
22862 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22864 gMapContext: false,
22870 mapTypeControl: false,
22871 disableDoubleClickZoom: false,
22873 streetViewControl: false,
22877 enableAutocomplete: false,
22878 enableReverseGeocode: true,
22881 getAutoCreate: function()
22886 cls: 'roo-location-picker'
22892 initEvents: function(ct, position)
22894 if(!this.el.getWidth() || this.isApplied()){
22898 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22903 initial: function()
22905 if(!this.mapTypeId){
22906 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22909 this.gMapContext = this.GMapContext();
22911 this.initOverlayView();
22913 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22917 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22918 _this.setPosition(_this.gMapContext.marker.position);
22921 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22922 _this.fireEvent('mapClick', this, event);
22926 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22927 _this.fireEvent('mapRightClick', this, event);
22931 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22932 _this.fireEvent('markerClick', this, event);
22936 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22937 _this.fireEvent('markerRightClick', this, event);
22941 this.setPosition(this.gMapContext.location);
22943 this.fireEvent('initial', this, this.gMapContext.location);
22946 initOverlayView: function()
22950 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22954 _this.fireEvent('OverlayViewDraw', _this);
22959 _this.fireEvent('OverlayViewOnAdd', _this);
22962 onRemove: function()
22964 _this.fireEvent('OverlayViewOnRemove', _this);
22967 show: function(cpx)
22969 _this.fireEvent('OverlayViewShow', _this, cpx);
22974 _this.fireEvent('OverlayViewHide', _this);
22980 fromLatLngToContainerPixel: function(event)
22982 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22985 isApplied: function()
22987 return this.getGmapContext() == false ? false : true;
22990 getGmapContext: function()
22992 return this.gMapContext
22995 GMapContext: function()
22997 var position = new google.maps.LatLng(this.latitude, this.longitude);
22999 var _map = new google.maps.Map(this.el.dom, {
23002 mapTypeId: this.mapTypeId,
23003 mapTypeControl: this.mapTypeControl,
23004 disableDoubleClickZoom: this.disableDoubleClickZoom,
23005 scrollwheel: this.scrollwheel,
23006 streetViewControl: this.streetViewControl,
23007 locationName: this.locationName,
23008 draggable: this.draggable,
23009 enableAutocomplete: this.enableAutocomplete,
23010 enableReverseGeocode: this.enableReverseGeocode
23013 var _marker = new google.maps.Marker({
23014 position: position,
23016 title: this.markerTitle,
23017 draggable: this.draggable
23024 location: position,
23025 radius: this.radius,
23026 locationName: this.locationName,
23027 addressComponents: {
23028 formatted_address: null,
23029 addressLine1: null,
23030 addressLine2: null,
23032 streetNumber: null,
23036 stateOrProvince: null
23039 domContainer: this.el.dom,
23040 geodecoder: new google.maps.Geocoder()
23044 drawCircle: function(center, radius, options)
23046 if (this.gMapContext.circle != null) {
23047 this.gMapContext.circle.setMap(null);
23051 options = Roo.apply({}, options, {
23052 strokeColor: "#0000FF",
23053 strokeOpacity: .35,
23055 fillColor: "#0000FF",
23059 options.map = this.gMapContext.map;
23060 options.radius = radius;
23061 options.center = center;
23062 this.gMapContext.circle = new google.maps.Circle(options);
23063 return this.gMapContext.circle;
23069 setPosition: function(location)
23071 this.gMapContext.location = location;
23072 this.gMapContext.marker.setPosition(location);
23073 this.gMapContext.map.panTo(location);
23074 this.drawCircle(location, this.gMapContext.radius, {});
23078 if (this.gMapContext.settings.enableReverseGeocode) {
23079 this.gMapContext.geodecoder.geocode({
23080 latLng: this.gMapContext.location
23081 }, function(results, status) {
23083 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23084 _this.gMapContext.locationName = results[0].formatted_address;
23085 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23087 _this.fireEvent('positionchanged', this, location);
23094 this.fireEvent('positionchanged', this, location);
23099 google.maps.event.trigger(this.gMapContext.map, "resize");
23101 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23103 this.fireEvent('resize', this);
23106 setPositionByLatLng: function(latitude, longitude)
23108 this.setPosition(new google.maps.LatLng(latitude, longitude));
23111 getCurrentPosition: function()
23114 latitude: this.gMapContext.location.lat(),
23115 longitude: this.gMapContext.location.lng()
23119 getAddressName: function()
23121 return this.gMapContext.locationName;
23124 getAddressComponents: function()
23126 return this.gMapContext.addressComponents;
23129 address_component_from_google_geocode: function(address_components)
23133 for (var i = 0; i < address_components.length; i++) {
23134 var component = address_components[i];
23135 if (component.types.indexOf("postal_code") >= 0) {
23136 result.postalCode = component.short_name;
23137 } else if (component.types.indexOf("street_number") >= 0) {
23138 result.streetNumber = component.short_name;
23139 } else if (component.types.indexOf("route") >= 0) {
23140 result.streetName = component.short_name;
23141 } else if (component.types.indexOf("neighborhood") >= 0) {
23142 result.city = component.short_name;
23143 } else if (component.types.indexOf("locality") >= 0) {
23144 result.city = component.short_name;
23145 } else if (component.types.indexOf("sublocality") >= 0) {
23146 result.district = component.short_name;
23147 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23148 result.stateOrProvince = component.short_name;
23149 } else if (component.types.indexOf("country") >= 0) {
23150 result.country = component.short_name;
23154 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23155 result.addressLine2 = "";
23159 setZoomLevel: function(zoom)
23161 this.gMapContext.map.setZoom(zoom);
23174 this.fireEvent('show', this);
23185 this.fireEvent('hide', this);
23190 Roo.apply(Roo.bootstrap.LocationPicker, {
23192 OverlayView : function(map, options)
23194 options = options || {};
23208 * @class Roo.bootstrap.Alert
23209 * @extends Roo.bootstrap.Component
23210 * Bootstrap Alert class
23211 * @cfg {String} title The title of alert
23212 * @cfg {String} html The content of alert
23213 * @cfg {String} weight ( success | info | warning | danger )
23214 * @cfg {String} faicon font-awesomeicon
23217 * Create a new alert
23218 * @param {Object} config The config object
23222 Roo.bootstrap.Alert = function(config){
23223 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23227 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23234 getAutoCreate : function()
23243 cls : 'roo-alert-icon'
23248 cls : 'roo-alert-title',
23253 cls : 'roo-alert-text',
23260 cfg.cn[0].cls += ' fa ' + this.faicon;
23264 cfg.cls += ' alert-' + this.weight;
23270 initEvents: function()
23272 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23275 setTitle : function(str)
23277 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23280 setText : function(str)
23282 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23285 setWeight : function(weight)
23288 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23291 this.weight = weight;
23293 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23296 setIcon : function(icon)
23299 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23304 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);