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',
1376 Roo.log('run?????????????????????');
1377 Roo.each(['xsUrl', 'smUrl', 'mdUrl', 'lgUrl'], function(size){
1379 Roo.log(this[size]);
1386 cls: (this.imgResponsive) ? 'img-responsive' : '',
1387 html: this.html || cfg.html,
1391 img.cls += ' roo-image-responsive-' + size;
1393 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1394 cfg.cls += ' img-' + this.border;
1411 a.target = this.target;
1415 cfg.cn.push((this.href) ? a : img);
1422 createSingleImg : function()
1426 cls: (this.imgResponsive) ? 'img-responsive' : '',
1430 cfg.html = this.html || cfg.html;
1432 cfg.src = this.src || cfg.src;
1434 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1435 cfg.cls += ' img-' + this.border;
1452 a.target = this.target;
1457 return (this.href) ? a : cfg;
1460 initEvents: function() {
1463 this.el.on('click', this.onClick, this);
1467 onClick : function(e)
1469 Roo.log('img onclick');
1470 this.fireEvent('click', this, e);
1484 * @class Roo.bootstrap.Link
1485 * @extends Roo.bootstrap.Component
1486 * Bootstrap Link Class
1487 * @cfg {String} alt image alternative text
1488 * @cfg {String} href a tag href
1489 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1490 * @cfg {String} html the content of the link.
1491 * @cfg {String} anchor name for the anchor link
1493 * @cfg {Boolean} preventDefault (true | false) default false
1497 * Create a new Input
1498 * @param {Object} config The config object
1501 Roo.bootstrap.Link = function(config){
1502 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1508 * The img click event for the img.
1509 * @param {Roo.EventObject} e
1515 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1519 preventDefault: false,
1523 getAutoCreate : function()
1529 // anchor's do not require html/href...
1530 if (this.anchor === false) {
1531 cfg.html = this.html || '';
1532 cfg.href = this.href || '#';
1534 cfg.name = this.anchor;
1535 if (this.html !== false) {
1536 cfg.html = this.html;
1538 if (this.href !== false) {
1539 cfg.href = this.href;
1543 if(this.alt !== false){
1548 if(this.target !== false) {
1549 cfg.target = this.target;
1555 initEvents: function() {
1557 if(!this.href || this.preventDefault){
1558 this.el.on('click', this.onClick, this);
1562 onClick : function(e)
1564 if(this.preventDefault){
1567 //Roo.log('img onclick');
1568 this.fireEvent('click', this, e);
1581 * @class Roo.bootstrap.Header
1582 * @extends Roo.bootstrap.Component
1583 * Bootstrap Header class
1584 * @cfg {String} html content of header
1585 * @cfg {Number} level (1|2|3|4|5|6) default 1
1588 * Create a new Header
1589 * @param {Object} config The config object
1593 Roo.bootstrap.Header = function(config){
1594 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1597 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1605 getAutoCreate : function(){
1610 tag: 'h' + (1 *this.level),
1611 html: this.html || ''
1623 * Ext JS Library 1.1.1
1624 * Copyright(c) 2006-2007, Ext JS, LLC.
1626 * Originally Released Under LGPL - original licence link has changed is not relivant.
1629 * <script type="text/javascript">
1633 * @class Roo.bootstrap.MenuMgr
1634 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1637 Roo.bootstrap.MenuMgr = function(){
1638 var menus, active, groups = {}, attached = false, lastShow = new Date();
1640 // private - called when first menu is created
1643 active = new Roo.util.MixedCollection();
1644 Roo.get(document).addKeyListener(27, function(){
1645 if(active.length > 0){
1653 if(active && active.length > 0){
1654 var c = active.clone();
1664 if(active.length < 1){
1665 Roo.get(document).un("mouseup", onMouseDown);
1673 var last = active.last();
1674 lastShow = new Date();
1677 Roo.get(document).on("mouseup", onMouseDown);
1682 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1683 m.parentMenu.activeChild = m;
1684 }else if(last && last.isVisible()){
1685 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1690 function onBeforeHide(m){
1692 m.activeChild.hide();
1694 if(m.autoHideTimer){
1695 clearTimeout(m.autoHideTimer);
1696 delete m.autoHideTimer;
1701 function onBeforeShow(m){
1702 var pm = m.parentMenu;
1703 if(!pm && !m.allowOtherMenus){
1705 }else if(pm && pm.activeChild && active != m){
1706 pm.activeChild.hide();
1710 // private this should really trigger on mouseup..
1711 function onMouseDown(e){
1712 Roo.log("on Mouse Up");
1713 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1723 function onBeforeCheck(mi, state){
1725 var g = groups[mi.group];
1726 for(var i = 0, l = g.length; i < l; i++){
1728 g[i].setChecked(false);
1737 * Hides all menus that are currently visible
1739 hideAll : function(){
1744 register : function(menu){
1748 menus[menu.id] = menu;
1749 menu.on("beforehide", onBeforeHide);
1750 menu.on("hide", onHide);
1751 menu.on("beforeshow", onBeforeShow);
1752 menu.on("show", onShow);
1754 if(g && menu.events["checkchange"]){
1758 groups[g].push(menu);
1759 menu.on("checkchange", onCheck);
1764 * Returns a {@link Roo.menu.Menu} object
1765 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1766 * be used to generate and return a new Menu instance.
1768 get : function(menu){
1769 if(typeof menu == "string"){ // menu id
1771 }else if(menu.events){ // menu instance
1774 /*else if(typeof menu.length == 'number'){ // array of menu items?
1775 return new Roo.bootstrap.Menu({items:menu});
1776 }else{ // otherwise, must be a config
1777 return new Roo.bootstrap.Menu(menu);
1784 unregister : function(menu){
1785 delete menus[menu.id];
1786 menu.un("beforehide", onBeforeHide);
1787 menu.un("hide", onHide);
1788 menu.un("beforeshow", onBeforeShow);
1789 menu.un("show", onShow);
1791 if(g && menu.events["checkchange"]){
1792 groups[g].remove(menu);
1793 menu.un("checkchange", onCheck);
1798 registerCheckable : function(menuItem){
1799 var g = menuItem.group;
1804 groups[g].push(menuItem);
1805 menuItem.on("beforecheckchange", onBeforeCheck);
1810 unregisterCheckable : function(menuItem){
1811 var g = menuItem.group;
1813 groups[g].remove(menuItem);
1814 menuItem.un("beforecheckchange", onBeforeCheck);
1826 * @class Roo.bootstrap.Menu
1827 * @extends Roo.bootstrap.Component
1828 * Bootstrap Menu class - container for MenuItems
1829 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1833 * @param {Object} config The config object
1837 Roo.bootstrap.Menu = function(config){
1838 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1839 if (this.registerMenu) {
1840 Roo.bootstrap.MenuMgr.register(this);
1845 * Fires before this menu is displayed
1846 * @param {Roo.menu.Menu} this
1851 * Fires before this menu is hidden
1852 * @param {Roo.menu.Menu} this
1857 * Fires after this menu is displayed
1858 * @param {Roo.menu.Menu} this
1863 * Fires after this menu is hidden
1864 * @param {Roo.menu.Menu} this
1869 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1870 * @param {Roo.menu.Menu} this
1871 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1872 * @param {Roo.EventObject} e
1877 * Fires when the mouse is hovering over this menu
1878 * @param {Roo.menu.Menu} this
1879 * @param {Roo.EventObject} e
1880 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1885 * Fires when the mouse exits this menu
1886 * @param {Roo.menu.Menu} this
1887 * @param {Roo.EventObject} e
1888 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1893 * Fires when a menu item contained in this menu is clicked
1894 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1895 * @param {Roo.EventObject} e
1899 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1902 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1906 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1909 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1911 registerMenu : true,
1913 menuItems :false, // stores the menu items..
1919 getChildContainer : function() {
1923 getAutoCreate : function(){
1925 //if (['right'].indexOf(this.align)!==-1) {
1926 // cfg.cn[1].cls += ' pull-right'
1932 cls : 'dropdown-menu' ,
1933 style : 'z-index:1000'
1937 if (this.type === 'submenu') {
1938 cfg.cls = 'submenu active';
1940 if (this.type === 'treeview') {
1941 cfg.cls = 'treeview-menu';
1946 initEvents : function() {
1948 // Roo.log("ADD event");
1949 // Roo.log(this.triggerEl.dom);
1950 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1952 this.triggerEl.addClass('dropdown-toggle');
1953 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1955 this.el.on("mouseover", this.onMouseOver, this);
1956 this.el.on("mouseout", this.onMouseOut, this);
1960 findTargetItem : function(e){
1961 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1965 //Roo.log(t); Roo.log(t.id);
1967 //Roo.log(this.menuitems);
1968 return this.menuitems.get(t.id);
1970 //return this.items.get(t.menuItemId);
1975 onClick : function(e){
1976 Roo.log("menu.onClick");
1977 var t = this.findTargetItem(e);
1978 if(!t || t.isContainer){
1983 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1984 if(t == this.activeItem && t.shouldDeactivate(e)){
1985 this.activeItem.deactivate();
1986 delete this.activeItem;
1990 this.setActiveItem(t, true);
1998 Roo.log('pass click event');
2002 this.fireEvent("click", this, t, e);
2006 onMouseOver : function(e){
2007 var t = this.findTargetItem(e);
2010 // if(t.canActivate && !t.disabled){
2011 // this.setActiveItem(t, true);
2015 this.fireEvent("mouseover", this, e, t);
2017 isVisible : function(){
2018 return !this.hidden;
2020 onMouseOut : function(e){
2021 var t = this.findTargetItem(e);
2024 // if(t == this.activeItem && t.shouldDeactivate(e)){
2025 // this.activeItem.deactivate();
2026 // delete this.activeItem;
2029 this.fireEvent("mouseout", this, e, t);
2034 * Displays this menu relative to another element
2035 * @param {String/HTMLElement/Roo.Element} element The element to align to
2036 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2037 * the element (defaults to this.defaultAlign)
2038 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2040 show : function(el, pos, parentMenu){
2041 this.parentMenu = parentMenu;
2045 this.fireEvent("beforeshow", this);
2046 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2049 * Displays this menu at a specific xy position
2050 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2051 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2053 showAt : function(xy, parentMenu, /* private: */_e){
2054 this.parentMenu = parentMenu;
2059 this.fireEvent("beforeshow", this);
2060 //xy = this.el.adjustForConstraints(xy);
2064 this.hideMenuItems();
2065 this.hidden = false;
2066 this.triggerEl.addClass('open');
2068 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2069 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2074 this.fireEvent("show", this);
2080 this.doFocus.defer(50, this);
2084 doFocus : function(){
2086 this.focusEl.focus();
2091 * Hides this menu and optionally all parent menus
2092 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2094 hide : function(deep){
2096 this.hideMenuItems();
2097 if(this.el && this.isVisible()){
2098 this.fireEvent("beforehide", this);
2099 if(this.activeItem){
2100 this.activeItem.deactivate();
2101 this.activeItem = null;
2103 this.triggerEl.removeClass('open');;
2105 this.fireEvent("hide", this);
2107 if(deep === true && this.parentMenu){
2108 this.parentMenu.hide(true);
2112 onTriggerPress : function(e)
2115 Roo.log('trigger press');
2116 //Roo.log(e.getTarget());
2117 // Roo.log(this.triggerEl.dom);
2118 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2122 if (this.isVisible()) {
2127 this.show(this.triggerEl, false, false);
2136 hideMenuItems : function()
2138 //$(backdrop).remove()
2139 Roo.select('.open',true).each(function(aa) {
2141 aa.removeClass('open');
2142 //var parent = getParent($(this))
2143 //var relatedTarget = { relatedTarget: this }
2145 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2146 //if (e.isDefaultPrevented()) return
2147 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2150 addxtypeChild : function (tree, cntr) {
2151 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2153 this.menuitems.add(comp);
2174 * @class Roo.bootstrap.MenuItem
2175 * @extends Roo.bootstrap.Component
2176 * Bootstrap MenuItem class
2177 * @cfg {String} html the menu label
2178 * @cfg {String} href the link
2179 * @cfg {Boolean} preventDefault (true | false) default true
2180 * @cfg {Boolean} isContainer (true | false) default false
2184 * Create a new MenuItem
2185 * @param {Object} config The config object
2189 Roo.bootstrap.MenuItem = function(config){
2190 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2195 * The raw click event for the entire grid.
2196 * @param {Roo.bootstrap.MenuItem} this
2197 * @param {Roo.EventObject} e
2203 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2207 preventDefault: true,
2208 isContainer : false,
2210 getAutoCreate : function(){
2212 if(this.isContainer){
2215 cls: 'dropdown-menu-item'
2221 cls: 'dropdown-menu-item',
2230 if (this.parent().type == 'treeview') {
2231 cfg.cls = 'treeview-menu';
2234 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2235 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2239 initEvents: function() {
2241 //this.el.select('a').on('click', this.onClick, this);
2244 onClick : function(e)
2246 Roo.log('item on click ');
2247 //if(this.preventDefault){
2248 // e.preventDefault();
2250 //this.parent().hideMenuItems();
2252 this.fireEvent('click', this, e);
2271 * @class Roo.bootstrap.MenuSeparator
2272 * @extends Roo.bootstrap.Component
2273 * Bootstrap MenuSeparator class
2276 * Create a new MenuItem
2277 * @param {Object} config The config object
2281 Roo.bootstrap.MenuSeparator = function(config){
2282 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2285 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2287 getAutoCreate : function(){
2306 * @class Roo.bootstrap.Modal
2307 * @extends Roo.bootstrap.Component
2308 * Bootstrap Modal class
2309 * @cfg {String} title Title of dialog
2310 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2311 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2312 * @cfg {Boolean} specificTitle default false
2313 * @cfg {Array} buttons Array of buttons or standard button set..
2314 * @cfg {String} buttonPosition (left|right|center) default right
2315 * @cfg {Boolean} animate default true
2316 * @cfg {Boolean} allow_close default true
2319 * Create a new Modal Dialog
2320 * @param {Object} config The config object
2323 Roo.bootstrap.Modal = function(config){
2324 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2329 * The raw btnclick event for the button
2330 * @param {Roo.EventObject} e
2334 this.buttons = this.buttons || [];
2337 this.tmpl = Roo.factory(this.tmpl);
2342 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2344 title : 'test dialog',
2354 specificTitle: false,
2356 buttonPosition: 'right',
2370 onRender : function(ct, position)
2372 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2375 var cfg = Roo.apply({}, this.getAutoCreate());
2378 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2380 //if (!cfg.name.length) {
2384 cfg.cls += ' ' + this.cls;
2387 cfg.style = this.style;
2389 this.el = Roo.get(document.body).createChild(cfg, position);
2391 //var type = this.el.dom.type;
2396 if(this.tabIndex !== undefined){
2397 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2401 this.bodyEl = this.el.select('.modal-body',true).first();
2402 this.closeEl = this.el.select('.modal-header .close', true).first();
2403 this.footerEl = this.el.select('.modal-footer',true).first();
2404 this.titleEl = this.el.select('.modal-title',true).first();
2408 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2409 this.maskEl.enableDisplayMode("block");
2411 //this.el.addClass("x-dlg-modal");
2413 if (this.buttons.length) {
2414 Roo.each(this.buttons, function(bb) {
2415 b = Roo.apply({}, bb);
2416 b.xns = b.xns || Roo.bootstrap;
2417 b.xtype = b.xtype || 'Button';
2418 if (typeof(b.listeners) == 'undefined') {
2419 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2422 var btn = Roo.factory(b);
2424 btn.onRender(this.el.select('.modal-footer div').first());
2428 // render the children.
2431 if(typeof(this.items) != 'undefined'){
2432 var items = this.items;
2435 for(var i =0;i < items.length;i++) {
2436 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2440 this.items = nitems;
2442 // where are these used - they used to be body/close/footer
2446 //this.el.addClass([this.fieldClass, this.cls]);
2449 getAutoCreate : function(){
2454 html : this.html || ''
2459 cls : 'modal-title',
2463 if(this.specificTitle){
2469 if (this.allow_close) {
2480 style : 'display: none',
2483 cls: "modal-dialog",
2486 cls : "modal-content",
2489 cls : 'modal-header',
2494 cls : 'modal-footer',
2498 cls: 'btn-' + this.buttonPosition
2515 modal.cls += ' fade';
2521 getChildContainer : function() {
2526 getButtonContainer : function() {
2527 return this.el.select('.modal-footer div',true).first();
2530 initEvents : function()
2532 if (this.allow_close) {
2533 this.closeEl.on('click', this.hide, this);
2539 if (!this.rendered) {
2543 this.el.setStyle('display', 'block');
2547 (function(){ _this.el.addClass('in'); }).defer(50);
2549 this.el.addClass('in');
2552 // not sure how we can show data in here..
2554 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2557 Roo.get(document.body).addClass("x-body-masked");
2558 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2560 this.el.setStyle('zIndex', '10001');
2562 this.fireEvent('show', this);
2569 Roo.get(document.body).removeClass("x-body-masked");
2570 this.el.removeClass('in');
2574 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2576 this.el.setStyle('display', 'none');
2579 this.fireEvent('hide', this);
2582 addButton : function(str, cb)
2586 var b = Roo.apply({}, { html : str } );
2587 b.xns = b.xns || Roo.bootstrap;
2588 b.xtype = b.xtype || 'Button';
2589 if (typeof(b.listeners) == 'undefined') {
2590 b.listeners = { click : cb.createDelegate(this) };
2593 var btn = Roo.factory(b);
2595 btn.onRender(this.el.select('.modal-footer div').first());
2601 setDefaultButton : function(btn)
2603 //this.el.select('.modal-footer').()
2605 resizeTo: function(w,h)
2609 setContentSize : function(w, h)
2613 onButtonClick: function(btn,e)
2616 this.fireEvent('btnclick', btn.name, e);
2619 * Set the title of the Dialog
2620 * @param {String} str new Title
2622 setTitle: function(str) {
2623 this.titleEl.dom.innerHTML = str;
2626 * Set the body of the Dialog
2627 * @param {String} str new Title
2629 setBody: function(str) {
2630 this.bodyEl.dom.innerHTML = str;
2633 * Set the body of the Dialog using the template
2634 * @param {Obj} data - apply this data to the template and replace the body contents.
2636 applyBody: function(obj)
2639 Roo.log("Error - using apply Body without a template");
2642 this.tmpl.overwrite(this.bodyEl, obj);
2648 Roo.apply(Roo.bootstrap.Modal, {
2650 * Button config that displays a single OK button
2659 * Button config that displays Yes and No buttons
2675 * Button config that displays OK and Cancel buttons
2690 * Button config that displays Yes, No and Cancel buttons
2713 * messagebox - can be used as a replace
2717 * @class Roo.MessageBox
2718 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2722 Roo.Msg.alert('Status', 'Changes saved successfully.');
2724 // Prompt for user data:
2725 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2727 // process text value...
2731 // Show a dialog using config options:
2733 title:'Save Changes?',
2734 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2735 buttons: Roo.Msg.YESNOCANCEL,
2742 Roo.bootstrap.MessageBox = function(){
2743 var dlg, opt, mask, waitTimer;
2744 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2745 var buttons, activeTextEl, bwidth;
2749 var handleButton = function(button){
2751 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2755 var handleHide = function(){
2757 dlg.el.removeClass(opt.cls);
2760 // Roo.TaskMgr.stop(waitTimer);
2761 // waitTimer = null;
2766 var updateButtons = function(b){
2769 buttons["ok"].hide();
2770 buttons["cancel"].hide();
2771 buttons["yes"].hide();
2772 buttons["no"].hide();
2773 //dlg.footer.dom.style.display = 'none';
2776 dlg.footerEl.dom.style.display = '';
2777 for(var k in buttons){
2778 if(typeof buttons[k] != "function"){
2781 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2782 width += buttons[k].el.getWidth()+15;
2792 var handleEsc = function(d, k, e){
2793 if(opt && opt.closable !== false){
2803 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2804 * @return {Roo.BasicDialog} The BasicDialog element
2806 getDialog : function(){
2808 dlg = new Roo.bootstrap.Modal( {
2811 //constraintoviewport:false,
2813 //collapsible : false,
2818 //buttonAlign:"center",
2819 closeClick : function(){
2820 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2823 handleButton("cancel");
2828 dlg.on("hide", handleHide);
2830 //dlg.addKeyListener(27, handleEsc);
2832 this.buttons = buttons;
2833 var bt = this.buttonText;
2834 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2835 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2836 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2837 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2839 bodyEl = dlg.bodyEl.createChild({
2841 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2842 '<textarea class="roo-mb-textarea"></textarea>' +
2843 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2845 msgEl = bodyEl.dom.firstChild;
2846 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2847 textboxEl.enableDisplayMode();
2848 textboxEl.addKeyListener([10,13], function(){
2849 if(dlg.isVisible() && opt && opt.buttons){
2852 }else if(opt.buttons.yes){
2853 handleButton("yes");
2857 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2858 textareaEl.enableDisplayMode();
2859 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2860 progressEl.enableDisplayMode();
2861 var pf = progressEl.dom.firstChild;
2863 pp = Roo.get(pf.firstChild);
2864 pp.setHeight(pf.offsetHeight);
2872 * Updates the message box body text
2873 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2874 * the XHTML-compliant non-breaking space character '&#160;')
2875 * @return {Roo.MessageBox} This message box
2877 updateText : function(text){
2878 if(!dlg.isVisible() && !opt.width){
2879 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2881 msgEl.innerHTML = text || ' ';
2883 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2884 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2886 Math.min(opt.width || cw , this.maxWidth),
2887 Math.max(opt.minWidth || this.minWidth, bwidth)
2890 activeTextEl.setWidth(w);
2892 if(dlg.isVisible()){
2893 dlg.fixedcenter = false;
2895 // to big, make it scroll. = But as usual stupid IE does not support
2898 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2899 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2900 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2902 bodyEl.dom.style.height = '';
2903 bodyEl.dom.style.overflowY = '';
2906 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2908 bodyEl.dom.style.overflowX = '';
2911 dlg.setContentSize(w, bodyEl.getHeight());
2912 if(dlg.isVisible()){
2913 dlg.fixedcenter = true;
2919 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2920 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2921 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2922 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2923 * @return {Roo.MessageBox} This message box
2925 updateProgress : function(value, text){
2927 this.updateText(text);
2929 if (pp) { // weird bug on my firefox - for some reason this is not defined
2930 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2936 * Returns true if the message box is currently displayed
2937 * @return {Boolean} True if the message box is visible, else false
2939 isVisible : function(){
2940 return dlg && dlg.isVisible();
2944 * Hides the message box if it is displayed
2947 if(this.isVisible()){
2953 * Displays a new message box, or reinitializes an existing message box, based on the config options
2954 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2955 * The following config object properties are supported:
2957 Property Type Description
2958 ---------- --------------- ------------------------------------------------------------------------------------
2959 animEl String/Element An id or Element from which the message box should animate as it opens and
2960 closes (defaults to undefined)
2961 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2962 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2963 closable Boolean False to hide the top-right close button (defaults to true). Note that
2964 progress and wait dialogs will ignore this property and always hide the
2965 close button as they can only be closed programmatically.
2966 cls String A custom CSS class to apply to the message box element
2967 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2968 displayed (defaults to 75)
2969 fn Function A callback function to execute after closing the dialog. The arguments to the
2970 function will be btn (the name of the button that was clicked, if applicable,
2971 e.g. "ok"), and text (the value of the active text field, if applicable).
2972 Progress and wait dialogs will ignore this option since they do not respond to
2973 user actions and can only be closed programmatically, so any required function
2974 should be called by the same code after it closes the dialog.
2975 icon String A CSS class that provides a background image to be used as an icon for
2976 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2977 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2978 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2979 modal Boolean False to allow user interaction with the page while the message box is
2980 displayed (defaults to true)
2981 msg String A string that will replace the existing message box body text (defaults
2982 to the XHTML-compliant non-breaking space character ' ')
2983 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2984 progress Boolean True to display a progress bar (defaults to false)
2985 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2986 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2987 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2988 title String The title text
2989 value String The string value to set into the active textbox element if displayed
2990 wait Boolean True to display a progress bar (defaults to false)
2991 width Number The width of the dialog in pixels
2998 msg: 'Please enter your address:',
3000 buttons: Roo.MessageBox.OKCANCEL,
3003 animEl: 'addAddressBtn'
3006 * @param {Object} config Configuration options
3007 * @return {Roo.MessageBox} This message box
3009 show : function(options)
3012 // this causes nightmares if you show one dialog after another
3013 // especially on callbacks..
3015 if(this.isVisible()){
3018 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3019 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3020 Roo.log("New Dialog Message:" + options.msg )
3021 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3022 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3025 var d = this.getDialog();
3027 d.setTitle(opt.title || " ");
3028 d.closeEl.setDisplayed(opt.closable !== false);
3029 activeTextEl = textboxEl;
3030 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3035 textareaEl.setHeight(typeof opt.multiline == "number" ?
3036 opt.multiline : this.defaultTextHeight);
3037 activeTextEl = textareaEl;
3046 progressEl.setDisplayed(opt.progress === true);
3047 this.updateProgress(0);
3048 activeTextEl.dom.value = opt.value || "";
3050 dlg.setDefaultButton(activeTextEl);
3052 var bs = opt.buttons;
3056 }else if(bs && bs.yes){
3057 db = buttons["yes"];
3059 dlg.setDefaultButton(db);
3061 bwidth = updateButtons(opt.buttons);
3062 this.updateText(opt.msg);
3064 d.el.addClass(opt.cls);
3066 d.proxyDrag = opt.proxyDrag === true;
3067 d.modal = opt.modal !== false;
3068 d.mask = opt.modal !== false ? mask : false;
3070 // force it to the end of the z-index stack so it gets a cursor in FF
3071 document.body.appendChild(dlg.el.dom);
3072 d.animateTarget = null;
3073 d.show(options.animEl);
3079 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3080 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3081 * and closing the message box when the process is complete.
3082 * @param {String} title The title bar text
3083 * @param {String} msg The message box body text
3084 * @return {Roo.MessageBox} This message box
3086 progress : function(title, msg){
3093 minWidth: this.minProgressWidth,
3100 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3101 * If a callback function is passed it will be called after the user clicks the button, and the
3102 * id of the button that was clicked will be passed as the only parameter to the callback
3103 * (could also be the top-right close button).
3104 * @param {String} title The title bar text
3105 * @param {String} msg The message box body text
3106 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3107 * @param {Object} scope (optional) The scope of the callback function
3108 * @return {Roo.MessageBox} This message box
3110 alert : function(title, msg, fn, scope){
3123 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3124 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3125 * You are responsible for closing the message box when the process is complete.
3126 * @param {String} msg The message box body text
3127 * @param {String} title (optional) The title bar text
3128 * @return {Roo.MessageBox} This message box
3130 wait : function(msg, title){
3141 waitTimer = Roo.TaskMgr.start({
3143 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3151 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3152 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3153 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3154 * @param {String} title The title bar text
3155 * @param {String} msg The message box body text
3156 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3157 * @param {Object} scope (optional) The scope of the callback function
3158 * @return {Roo.MessageBox} This message box
3160 confirm : function(title, msg, fn, scope){
3164 buttons: this.YESNO,
3173 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3174 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3175 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3176 * (could also be the top-right close button) and the text that was entered will be passed as the two
3177 * parameters to the callback.
3178 * @param {String} title The title bar text
3179 * @param {String} msg The message box body text
3180 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3181 * @param {Object} scope (optional) The scope of the callback function
3182 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3183 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3184 * @return {Roo.MessageBox} This message box
3186 prompt : function(title, msg, fn, scope, multiline){
3190 buttons: this.OKCANCEL,
3195 multiline: multiline,
3202 * Button config that displays a single OK button
3207 * Button config that displays Yes and No buttons
3210 YESNO : {yes:true, no:true},
3212 * Button config that displays OK and Cancel buttons
3215 OKCANCEL : {ok:true, cancel:true},
3217 * Button config that displays Yes, No and Cancel buttons
3220 YESNOCANCEL : {yes:true, no:true, cancel:true},
3223 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3226 defaultTextHeight : 75,
3228 * The maximum width in pixels of the message box (defaults to 600)
3233 * The minimum width in pixels of the message box (defaults to 100)
3238 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3239 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3242 minProgressWidth : 250,
3244 * An object containing the default button text strings that can be overriden for localized language support.
3245 * Supported properties are: ok, cancel, yes and no.
3246 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3259 * Shorthand for {@link Roo.MessageBox}
3261 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3262 Roo.Msg = Roo.Msg || Roo.MessageBox;
3271 * @class Roo.bootstrap.Navbar
3272 * @extends Roo.bootstrap.Component
3273 * Bootstrap Navbar class
3276 * Create a new Navbar
3277 * @param {Object} config The config object
3281 Roo.bootstrap.Navbar = function(config){
3282 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3286 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3295 getAutoCreate : function(){
3298 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3302 initEvents :function ()
3304 //Roo.log(this.el.select('.navbar-toggle',true));
3305 this.el.select('.navbar-toggle',true).on('click', function() {
3306 // Roo.log('click');
3307 this.el.select('.navbar-collapse',true).toggleClass('in');
3315 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3317 var size = this.el.getSize();
3318 this.maskEl.setSize(size.width, size.height);
3319 this.maskEl.enableDisplayMode("block");
3328 getChildContainer : function()
3330 if (this.el.select('.collapse').getCount()) {
3331 return this.el.select('.collapse',true).first();
3364 * @class Roo.bootstrap.NavSimplebar
3365 * @extends Roo.bootstrap.Navbar
3366 * Bootstrap Sidebar class
3368 * @cfg {Boolean} inverse is inverted color
3370 * @cfg {String} type (nav | pills | tabs)
3371 * @cfg {Boolean} arrangement stacked | justified
3372 * @cfg {String} align (left | right) alignment
3374 * @cfg {Boolean} main (true|false) main nav bar? default false
3375 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3377 * @cfg {String} tag (header|footer|nav|div) default is nav
3383 * Create a new Sidebar
3384 * @param {Object} config The config object
3388 Roo.bootstrap.NavSimplebar = function(config){
3389 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3392 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3408 getAutoCreate : function(){
3412 tag : this.tag || 'div',
3425 this.type = this.type || 'nav';
3426 if (['tabs','pills'].indexOf(this.type)!==-1) {
3427 cfg.cn[0].cls += ' nav-' + this.type
3431 if (this.type!=='nav') {
3432 Roo.log('nav type must be nav/tabs/pills')
3434 cfg.cn[0].cls += ' navbar-nav'
3440 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3441 cfg.cn[0].cls += ' nav-' + this.arrangement;
3445 if (this.align === 'right') {
3446 cfg.cn[0].cls += ' navbar-right';
3450 cfg.cls += ' navbar-inverse';
3477 * @class Roo.bootstrap.NavHeaderbar
3478 * @extends Roo.bootstrap.NavSimplebar
3479 * Bootstrap Sidebar class
3481 * @cfg {String} brand what is brand
3482 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3483 * @cfg {String} brand_href href of the brand
3484 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3485 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3486 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3487 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3490 * Create a new Sidebar
3491 * @param {Object} config The config object
3495 Roo.bootstrap.NavHeaderbar = function(config){
3496 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3500 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3507 desktopCenter : false,
3510 getAutoCreate : function(){
3513 tag: this.nav || 'nav',
3520 if (this.desktopCenter) {
3521 cn.push({cls : 'container', cn : []});
3528 cls: 'navbar-header',
3533 cls: 'navbar-toggle',
3534 'data-toggle': 'collapse',
3539 html: 'Toggle navigation'
3561 cls: 'collapse navbar-collapse',
3565 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3567 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3568 cfg.cls += ' navbar-' + this.position;
3570 // tag can override this..
3572 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3575 if (this.brand !== '') {
3578 href: this.brand_href ? this.brand_href : '#',
3579 cls: 'navbar-brand',
3587 cfg.cls += ' main-nav';
3595 getHeaderChildContainer : function()
3597 if (this.el.select('.navbar-header').getCount()) {
3598 return this.el.select('.navbar-header',true).first();
3601 return this.getChildContainer();
3605 initEvents : function()
3607 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3609 if (this.autohide) {
3614 Roo.get(document).on('scroll',function(e) {
3615 var ns = Roo.get(document).getScroll().top;
3616 var os = prevScroll;
3620 ft.removeClass('slideDown');
3621 ft.addClass('slideUp');
3624 ft.removeClass('slideUp');
3625 ft.addClass('slideDown');
3646 * @class Roo.bootstrap.NavSidebar
3647 * @extends Roo.bootstrap.Navbar
3648 * Bootstrap Sidebar class
3651 * Create a new Sidebar
3652 * @param {Object} config The config object
3656 Roo.bootstrap.NavSidebar = function(config){
3657 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3660 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3662 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3664 getAutoCreate : function(){
3669 cls: 'sidebar sidebar-nav'
3691 * @class Roo.bootstrap.NavGroup
3692 * @extends Roo.bootstrap.Component
3693 * Bootstrap NavGroup class
3694 * @cfg {String} align (left|right)
3695 * @cfg {Boolean} inverse
3696 * @cfg {String} type (nav|pills|tab) default nav
3697 * @cfg {String} navId - reference Id for navbar.
3701 * Create a new nav group
3702 * @param {Object} config The config object
3705 Roo.bootstrap.NavGroup = function(config){
3706 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3709 Roo.bootstrap.NavGroup.register(this);
3713 * Fires when the active item changes
3714 * @param {Roo.bootstrap.NavGroup} this
3715 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3716 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3723 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3734 getAutoCreate : function()
3736 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3743 if (['tabs','pills'].indexOf(this.type)!==-1) {
3744 cfg.cls += ' nav-' + this.type
3746 if (this.type!=='nav') {
3747 Roo.log('nav type must be nav/tabs/pills')
3749 cfg.cls += ' navbar-nav'
3752 if (this.parent().sidebar) {
3755 cls: 'dashboard-menu sidebar-menu'
3761 if (this.form === true) {
3767 if (this.align === 'right') {
3768 cfg.cls += ' navbar-right';
3770 cfg.cls += ' navbar-left';
3774 if (this.align === 'right') {
3775 cfg.cls += ' navbar-right';
3779 cfg.cls += ' navbar-inverse';
3787 * sets the active Navigation item
3788 * @param {Roo.bootstrap.NavItem} the new current navitem
3790 setActiveItem : function(item)
3793 Roo.each(this.navItems, function(v){
3798 v.setActive(false, true);
3805 item.setActive(true, true);
3806 this.fireEvent('changed', this, item, prev);
3811 * gets the active Navigation item
3812 * @return {Roo.bootstrap.NavItem} the current navitem
3814 getActive : function()
3818 Roo.each(this.navItems, function(v){
3829 indexOfNav : function()
3833 Roo.each(this.navItems, function(v,i){
3844 * adds a Navigation item
3845 * @param {Roo.bootstrap.NavItem} the navitem to add
3847 addItem : function(cfg)
3849 var cn = new Roo.bootstrap.NavItem(cfg);
3851 cn.parentId = this.id;
3852 cn.onRender(this.el, null);
3856 * register a Navigation item
3857 * @param {Roo.bootstrap.NavItem} the navitem to add
3859 register : function(item)
3861 this.navItems.push( item);
3862 item.navId = this.navId;
3867 * clear all the Navigation item
3870 clearAll : function()
3873 this.el.dom.innerHTML = '';
3876 getNavItem: function(tabId)
3879 Roo.each(this.navItems, function(e) {
3880 if (e.tabId == tabId) {
3890 setActiveNext : function()
3892 var i = this.indexOfNav(this.getActive());
3893 if (i > this.navItems.length) {
3896 this.setActiveItem(this.navItems[i+1]);
3898 setActivePrev : function()
3900 var i = this.indexOfNav(this.getActive());
3904 this.setActiveItem(this.navItems[i-1]);
3906 clearWasActive : function(except) {
3907 Roo.each(this.navItems, function(e) {
3908 if (e.tabId != except.tabId && e.was_active) {
3909 e.was_active = false;
3916 getWasActive : function ()
3919 Roo.each(this.navItems, function(e) {
3934 Roo.apply(Roo.bootstrap.NavGroup, {
3938 * register a Navigation Group
3939 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3941 register : function(navgrp)
3943 this.groups[navgrp.navId] = navgrp;
3947 * fetch a Navigation Group based on the navigation ID
3948 * @param {string} the navgroup to add
3949 * @returns {Roo.bootstrap.NavGroup} the navgroup
3951 get: function(navId) {
3952 if (typeof(this.groups[navId]) == 'undefined') {
3954 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3956 return this.groups[navId] ;
3971 * @class Roo.bootstrap.NavItem
3972 * @extends Roo.bootstrap.Component
3973 * Bootstrap Navbar.NavItem class
3974 * @cfg {String} href link to
3975 * @cfg {String} html content of button
3976 * @cfg {String} badge text inside badge
3977 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3978 * @cfg {String} glyphicon name of glyphicon
3979 * @cfg {String} icon name of font awesome icon
3980 * @cfg {Boolean} active Is item active
3981 * @cfg {Boolean} disabled Is item disabled
3983 * @cfg {Boolean} preventDefault (true | false) default false
3984 * @cfg {String} tabId the tab that this item activates.
3985 * @cfg {String} tagtype (a|span) render as a href or span?
3986 * @cfg {Boolean} animateRef (true|false) link to element default false
3989 * Create a new Navbar Item
3990 * @param {Object} config The config object
3992 Roo.bootstrap.NavItem = function(config){
3993 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3998 * The raw click event for the entire grid.
3999 * @param {Roo.EventObject} e
4004 * Fires when the active item active state changes
4005 * @param {Roo.bootstrap.NavItem} this
4006 * @param {boolean} state the new state
4012 * Fires when scroll to element
4013 * @param {Roo.bootstrap.NavItem} this
4014 * @param {Object} options
4015 * @param {Roo.EventObject} e
4023 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4031 preventDefault : false,
4038 getAutoCreate : function(){
4046 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4048 if (this.disabled) {
4049 cfg.cls += ' disabled';
4052 if (this.href || this.html || this.glyphicon || this.icon) {
4056 href : this.href || "#",
4057 html: this.html || ''
4062 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4065 if(this.glyphicon) {
4066 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4071 cfg.cn[0].html += " <span class='caret'></span>";
4075 if (this.badge !== '') {
4077 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4085 initEvents: function()
4087 if (typeof (this.menu) != 'undefined') {
4088 this.menu.parentType = this.xtype;
4089 this.menu.triggerEl = this.el;
4090 this.menu = this.addxtype(Roo.apply({}, this.menu));
4093 this.el.select('a',true).on('click', this.onClick, this);
4095 if(this.tagtype == 'span'){
4096 this.el.select('span',true).on('click', this.onClick, this);
4099 // at this point parent should be available..
4100 this.parent().register(this);
4103 onClick : function(e)
4106 this.preventDefault ||
4113 if (this.disabled) {
4117 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4118 if (tg && tg.transition) {
4119 Roo.log("waiting for the transitionend");
4125 //Roo.log("fire event clicked");
4126 if(this.fireEvent('click', this, e) === false){
4130 if(this.tagtype == 'span'){
4134 //Roo.log(this.href);
4135 var ael = this.el.select('a',true).first();
4138 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4139 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4140 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4141 return; // ignore... - it's a 'hash' to another page.
4145 this.scrollToElement(e);
4149 var p = this.parent();
4151 if (['tabs','pills'].indexOf(p.type)!==-1) {
4152 if (typeof(p.setActiveItem) !== 'undefined') {
4153 p.setActiveItem(this);
4157 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4158 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4159 // remove the collapsed menu expand...
4160 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4164 isActive: function () {
4167 setActive : function(state, fire, is_was_active)
4169 if (this.active && !state & this.navId) {
4170 this.was_active = true;
4171 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4173 nv.clearWasActive(this);
4177 this.active = state;
4180 this.el.removeClass('active');
4181 } else if (!this.el.hasClass('active')) {
4182 this.el.addClass('active');
4185 this.fireEvent('changed', this, state);
4188 // show a panel if it's registered and related..
4190 if (!this.navId || !this.tabId || !state || is_was_active) {
4194 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4198 var pan = tg.getPanelByName(this.tabId);
4202 // if we can not flip to new panel - go back to old nav highlight..
4203 if (false == tg.showPanel(pan)) {
4204 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4206 var onav = nv.getWasActive();
4208 onav.setActive(true, false, true);
4217 // this should not be here...
4218 setDisabled : function(state)
4220 this.disabled = state;
4222 this.el.removeClass('disabled');
4223 } else if (!this.el.hasClass('disabled')) {
4224 this.el.addClass('disabled');
4230 * Fetch the element to display the tooltip on.
4231 * @return {Roo.Element} defaults to this.el
4233 tooltipEl : function()
4235 return this.el.select('' + this.tagtype + '', true).first();
4238 scrollToElement : function(e)
4240 var c = document.body;
4243 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4245 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4246 c = document.documentElement;
4249 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4255 var o = target.calcOffsetsTo(c);
4262 this.fireEvent('scrollto', this, options, e);
4264 Roo.get(c).scrollTo('top', options.value, true);
4277 * <span> icon </span>
4278 * <span> text </span>
4279 * <span>badge </span>
4283 * @class Roo.bootstrap.NavSidebarItem
4284 * @extends Roo.bootstrap.NavItem
4285 * Bootstrap Navbar.NavSidebarItem class
4287 * Create a new Navbar Button
4288 * @param {Object} config The config object
4290 Roo.bootstrap.NavSidebarItem = function(config){
4291 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4296 * The raw click event for the entire grid.
4297 * @param {Roo.EventObject} e
4302 * Fires when the active item active state changes
4303 * @param {Roo.bootstrap.NavSidebarItem} this
4304 * @param {boolean} state the new state
4312 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4315 getAutoCreate : function(){
4320 href : this.href || '#',
4332 html : this.html || ''
4337 cfg.cls += ' active';
4341 if (this.glyphicon || this.icon) {
4342 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4343 a.cn.push({ tag : 'i', cls : c }) ;
4348 if (this.badge !== '') {
4349 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4353 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4354 a.cls += 'dropdown-toggle treeview' ;
4378 * @class Roo.bootstrap.Row
4379 * @extends Roo.bootstrap.Component
4380 * Bootstrap Row class (contains columns...)
4384 * @param {Object} config The config object
4387 Roo.bootstrap.Row = function(config){
4388 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4391 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4393 getAutoCreate : function(){
4412 * @class Roo.bootstrap.Element
4413 * @extends Roo.bootstrap.Component
4414 * Bootstrap Element class
4415 * @cfg {String} html contents of the element
4416 * @cfg {String} tag tag of the element
4417 * @cfg {String} cls class of the element
4418 * @cfg {Boolean} preventDefault (true|false) default false
4419 * @cfg {Boolean} clickable (true|false) default false
4422 * Create a new Element
4423 * @param {Object} config The config object
4426 Roo.bootstrap.Element = function(config){
4427 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4433 * When a element is chick
4434 * @param {Roo.bootstrap.Element} this
4435 * @param {Roo.EventObject} e
4441 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4446 preventDefault: false,
4449 getAutoCreate : function(){
4460 initEvents: function()
4462 Roo.bootstrap.Element.superclass.initEvents.call(this);
4465 this.el.on('click', this.onClick, this);
4470 onClick : function(e)
4472 if(this.preventDefault){
4476 this.fireEvent('click', this, e);
4479 getValue : function()
4481 return this.el.dom.innerHTML;
4484 setValue : function(value)
4486 this.el.dom.innerHTML = value;
4501 * @class Roo.bootstrap.Pagination
4502 * @extends Roo.bootstrap.Component
4503 * Bootstrap Pagination class
4504 * @cfg {String} size xs | sm | md | lg
4505 * @cfg {Boolean} inverse false | true
4508 * Create a new Pagination
4509 * @param {Object} config The config object
4512 Roo.bootstrap.Pagination = function(config){
4513 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4516 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4522 getAutoCreate : function(){
4528 cfg.cls += ' inverse';
4534 cfg.cls += " " + this.cls;
4552 * @class Roo.bootstrap.PaginationItem
4553 * @extends Roo.bootstrap.Component
4554 * Bootstrap PaginationItem class
4555 * @cfg {String} html text
4556 * @cfg {String} href the link
4557 * @cfg {Boolean} preventDefault (true | false) default true
4558 * @cfg {Boolean} active (true | false) default false
4559 * @cfg {Boolean} disabled default false
4563 * Create a new PaginationItem
4564 * @param {Object} config The config object
4568 Roo.bootstrap.PaginationItem = function(config){
4569 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4574 * The raw click event for the entire grid.
4575 * @param {Roo.EventObject} e
4581 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4585 preventDefault: true,
4590 getAutoCreate : function(){
4596 href : this.href ? this.href : '#',
4597 html : this.html ? this.html : ''
4607 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4611 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4617 initEvents: function() {
4619 this.el.on('click', this.onClick, this);
4622 onClick : function(e)
4624 Roo.log('PaginationItem on click ');
4625 if(this.preventDefault){
4633 this.fireEvent('click', this, e);
4649 * @class Roo.bootstrap.Slider
4650 * @extends Roo.bootstrap.Component
4651 * Bootstrap Slider class
4654 * Create a new Slider
4655 * @param {Object} config The config object
4658 Roo.bootstrap.Slider = function(config){
4659 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4662 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4664 getAutoCreate : function(){
4668 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4672 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4684 * Ext JS Library 1.1.1
4685 * Copyright(c) 2006-2007, Ext JS, LLC.
4687 * Originally Released Under LGPL - original licence link has changed is not relivant.
4690 * <script type="text/javascript">
4695 * @class Roo.grid.ColumnModel
4696 * @extends Roo.util.Observable
4697 * This is the default implementation of a ColumnModel used by the Grid. It defines
4698 * the columns in the grid.
4701 var colModel = new Roo.grid.ColumnModel([
4702 {header: "Ticker", width: 60, sortable: true, locked: true},
4703 {header: "Company Name", width: 150, sortable: true},
4704 {header: "Market Cap.", width: 100, sortable: true},
4705 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4706 {header: "Employees", width: 100, sortable: true, resizable: false}
4711 * The config options listed for this class are options which may appear in each
4712 * individual column definition.
4713 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4715 * @param {Object} config An Array of column config objects. See this class's
4716 * config objects for details.
4718 Roo.grid.ColumnModel = function(config){
4720 * The config passed into the constructor
4722 this.config = config;
4725 // if no id, create one
4726 // if the column does not have a dataIndex mapping,
4727 // map it to the order it is in the config
4728 for(var i = 0, len = config.length; i < len; i++){
4730 if(typeof c.dataIndex == "undefined"){
4733 if(typeof c.renderer == "string"){
4734 c.renderer = Roo.util.Format[c.renderer];
4736 if(typeof c.id == "undefined"){
4739 if(c.editor && c.editor.xtype){
4740 c.editor = Roo.factory(c.editor, Roo.grid);
4742 if(c.editor && c.editor.isFormField){
4743 c.editor = new Roo.grid.GridEditor(c.editor);
4745 this.lookup[c.id] = c;
4749 * The width of columns which have no width specified (defaults to 100)
4752 this.defaultWidth = 100;
4755 * Default sortable of columns which have no sortable specified (defaults to false)
4758 this.defaultSortable = false;
4762 * @event widthchange
4763 * Fires when the width of a column changes.
4764 * @param {ColumnModel} this
4765 * @param {Number} columnIndex The column index
4766 * @param {Number} newWidth The new width
4768 "widthchange": true,
4770 * @event headerchange
4771 * Fires when the text of a header changes.
4772 * @param {ColumnModel} this
4773 * @param {Number} columnIndex The column index
4774 * @param {Number} newText The new header text
4776 "headerchange": true,
4778 * @event hiddenchange
4779 * Fires when a column is hidden or "unhidden".
4780 * @param {ColumnModel} this
4781 * @param {Number} columnIndex The column index
4782 * @param {Boolean} hidden true if hidden, false otherwise
4784 "hiddenchange": true,
4786 * @event columnmoved
4787 * Fires when a column is moved.
4788 * @param {ColumnModel} this
4789 * @param {Number} oldIndex
4790 * @param {Number} newIndex
4792 "columnmoved" : true,
4794 * @event columlockchange
4795 * Fires when a column's locked state is changed
4796 * @param {ColumnModel} this
4797 * @param {Number} colIndex
4798 * @param {Boolean} locked true if locked
4800 "columnlockchange" : true
4802 Roo.grid.ColumnModel.superclass.constructor.call(this);
4804 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4806 * @cfg {String} header The header text to display in the Grid view.
4809 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4810 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4811 * specified, the column's index is used as an index into the Record's data Array.
4814 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4815 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4818 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4819 * Defaults to the value of the {@link #defaultSortable} property.
4820 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4823 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4826 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4829 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4832 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4835 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4836 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4837 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4838 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4841 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4844 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4847 * @cfg {String} cursor (Optional)
4850 * @cfg {String} tooltip (Optional)
4853 * Returns the id of the column at the specified index.
4854 * @param {Number} index The column index
4855 * @return {String} the id
4857 getColumnId : function(index){
4858 return this.config[index].id;
4862 * Returns the column for a specified id.
4863 * @param {String} id The column id
4864 * @return {Object} the column
4866 getColumnById : function(id){
4867 return this.lookup[id];
4872 * Returns the column for a specified dataIndex.
4873 * @param {String} dataIndex The column dataIndex
4874 * @return {Object|Boolean} the column or false if not found
4876 getColumnByDataIndex: function(dataIndex){
4877 var index = this.findColumnIndex(dataIndex);
4878 return index > -1 ? this.config[index] : false;
4882 * Returns the index for a specified column id.
4883 * @param {String} id The column id
4884 * @return {Number} the index, or -1 if not found
4886 getIndexById : function(id){
4887 for(var i = 0, len = this.config.length; i < len; i++){
4888 if(this.config[i].id == id){
4896 * Returns the index for a specified column dataIndex.
4897 * @param {String} dataIndex The column dataIndex
4898 * @return {Number} the index, or -1 if not found
4901 findColumnIndex : function(dataIndex){
4902 for(var i = 0, len = this.config.length; i < len; i++){
4903 if(this.config[i].dataIndex == dataIndex){
4911 moveColumn : function(oldIndex, newIndex){
4912 var c = this.config[oldIndex];
4913 this.config.splice(oldIndex, 1);
4914 this.config.splice(newIndex, 0, c);
4915 this.dataMap = null;
4916 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4919 isLocked : function(colIndex){
4920 return this.config[colIndex].locked === true;
4923 setLocked : function(colIndex, value, suppressEvent){
4924 if(this.isLocked(colIndex) == value){
4927 this.config[colIndex].locked = value;
4929 this.fireEvent("columnlockchange", this, colIndex, value);
4933 getTotalLockedWidth : function(){
4935 for(var i = 0; i < this.config.length; i++){
4936 if(this.isLocked(i) && !this.isHidden(i)){
4937 this.totalWidth += this.getColumnWidth(i);
4943 getLockedCount : function(){
4944 for(var i = 0, len = this.config.length; i < len; i++){
4945 if(!this.isLocked(i)){
4952 * Returns the number of columns.
4955 getColumnCount : function(visibleOnly){
4956 if(visibleOnly === true){
4958 for(var i = 0, len = this.config.length; i < len; i++){
4959 if(!this.isHidden(i)){
4965 return this.config.length;
4969 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4970 * @param {Function} fn
4971 * @param {Object} scope (optional)
4972 * @return {Array} result
4974 getColumnsBy : function(fn, scope){
4976 for(var i = 0, len = this.config.length; i < len; i++){
4977 var c = this.config[i];
4978 if(fn.call(scope||this, c, i) === true){
4986 * Returns true if the specified column is sortable.
4987 * @param {Number} col The column index
4990 isSortable : function(col){
4991 if(typeof this.config[col].sortable == "undefined"){
4992 return this.defaultSortable;
4994 return this.config[col].sortable;
4998 * Returns the rendering (formatting) function defined for the column.
4999 * @param {Number} col The column index.
5000 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5002 getRenderer : function(col){
5003 if(!this.config[col].renderer){
5004 return Roo.grid.ColumnModel.defaultRenderer;
5006 return this.config[col].renderer;
5010 * Sets the rendering (formatting) function for a column.
5011 * @param {Number} col The column index
5012 * @param {Function} fn The function to use to process the cell's raw data
5013 * to return HTML markup for the grid view. The render function is called with
5014 * the following parameters:<ul>
5015 * <li>Data value.</li>
5016 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5017 * <li>css A CSS style string to apply to the table cell.</li>
5018 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5019 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5020 * <li>Row index</li>
5021 * <li>Column index</li>
5022 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5024 setRenderer : function(col, fn){
5025 this.config[col].renderer = fn;
5029 * Returns the width for the specified column.
5030 * @param {Number} col The column index
5033 getColumnWidth : function(col){
5034 return this.config[col].width * 1 || this.defaultWidth;
5038 * Sets the width for a column.
5039 * @param {Number} col The column index
5040 * @param {Number} width The new width
5042 setColumnWidth : function(col, width, suppressEvent){
5043 this.config[col].width = width;
5044 this.totalWidth = null;
5046 this.fireEvent("widthchange", this, col, width);
5051 * Returns the total width of all columns.
5052 * @param {Boolean} includeHidden True to include hidden column widths
5055 getTotalWidth : function(includeHidden){
5056 if(!this.totalWidth){
5057 this.totalWidth = 0;
5058 for(var i = 0, len = this.config.length; i < len; i++){
5059 if(includeHidden || !this.isHidden(i)){
5060 this.totalWidth += this.getColumnWidth(i);
5064 return this.totalWidth;
5068 * Returns the header for the specified column.
5069 * @param {Number} col The column index
5072 getColumnHeader : function(col){
5073 return this.config[col].header;
5077 * Sets the header for a column.
5078 * @param {Number} col The column index
5079 * @param {String} header The new header
5081 setColumnHeader : function(col, header){
5082 this.config[col].header = header;
5083 this.fireEvent("headerchange", this, col, header);
5087 * Returns the tooltip for the specified column.
5088 * @param {Number} col The column index
5091 getColumnTooltip : function(col){
5092 return this.config[col].tooltip;
5095 * Sets the tooltip for a column.
5096 * @param {Number} col The column index
5097 * @param {String} tooltip The new tooltip
5099 setColumnTooltip : function(col, tooltip){
5100 this.config[col].tooltip = tooltip;
5104 * Returns the dataIndex for the specified column.
5105 * @param {Number} col The column index
5108 getDataIndex : function(col){
5109 return this.config[col].dataIndex;
5113 * Sets the dataIndex for a column.
5114 * @param {Number} col The column index
5115 * @param {Number} dataIndex The new dataIndex
5117 setDataIndex : function(col, dataIndex){
5118 this.config[col].dataIndex = dataIndex;
5124 * Returns true if the cell is editable.
5125 * @param {Number} colIndex The column index
5126 * @param {Number} rowIndex The row index
5129 isCellEditable : function(colIndex, rowIndex){
5130 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5134 * Returns the editor defined for the cell/column.
5135 * return false or null to disable editing.
5136 * @param {Number} colIndex The column index
5137 * @param {Number} rowIndex The row index
5140 getCellEditor : function(colIndex, rowIndex){
5141 return this.config[colIndex].editor;
5145 * Sets if a column is editable.
5146 * @param {Number} col The column index
5147 * @param {Boolean} editable True if the column is editable
5149 setEditable : function(col, editable){
5150 this.config[col].editable = editable;
5155 * Returns true if the column is hidden.
5156 * @param {Number} colIndex The column index
5159 isHidden : function(colIndex){
5160 return this.config[colIndex].hidden;
5165 * Returns true if the column width cannot be changed
5167 isFixed : function(colIndex){
5168 return this.config[colIndex].fixed;
5172 * Returns true if the column can be resized
5175 isResizable : function(colIndex){
5176 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5179 * Sets if a column is hidden.
5180 * @param {Number} colIndex The column index
5181 * @param {Boolean} hidden True if the column is hidden
5183 setHidden : function(colIndex, hidden){
5184 this.config[colIndex].hidden = hidden;
5185 this.totalWidth = null;
5186 this.fireEvent("hiddenchange", this, colIndex, hidden);
5190 * Sets the editor for a column.
5191 * @param {Number} col The column index
5192 * @param {Object} editor The editor object
5194 setEditor : function(col, editor){
5195 this.config[col].editor = editor;
5199 Roo.grid.ColumnModel.defaultRenderer = function(value){
5200 if(typeof value == "string" && value.length < 1){
5206 // Alias for backwards compatibility
5207 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5210 * Ext JS Library 1.1.1
5211 * Copyright(c) 2006-2007, Ext JS, LLC.
5213 * Originally Released Under LGPL - original licence link has changed is not relivant.
5216 * <script type="text/javascript">
5220 * @class Roo.LoadMask
5221 * A simple utility class for generically masking elements while loading data. If the element being masked has
5222 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5223 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5224 * element's UpdateManager load indicator and will be destroyed after the initial load.
5226 * Create a new LoadMask
5227 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5228 * @param {Object} config The config object
5230 Roo.LoadMask = function(el, config){
5231 this.el = Roo.get(el);
5232 Roo.apply(this, config);
5234 this.store.on('beforeload', this.onBeforeLoad, this);
5235 this.store.on('load', this.onLoad, this);
5236 this.store.on('loadexception', this.onLoadException, this);
5237 this.removeMask = false;
5239 var um = this.el.getUpdateManager();
5240 um.showLoadIndicator = false; // disable the default indicator
5241 um.on('beforeupdate', this.onBeforeLoad, this);
5242 um.on('update', this.onLoad, this);
5243 um.on('failure', this.onLoad, this);
5244 this.removeMask = true;
5248 Roo.LoadMask.prototype = {
5250 * @cfg {Boolean} removeMask
5251 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5252 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5256 * The text to display in a centered loading message box (defaults to 'Loading...')
5260 * @cfg {String} msgCls
5261 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5263 msgCls : 'x-mask-loading',
5266 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5272 * Disables the mask to prevent it from being displayed
5274 disable : function(){
5275 this.disabled = true;
5279 * Enables the mask so that it can be displayed
5281 enable : function(){
5282 this.disabled = false;
5285 onLoadException : function()
5289 if (typeof(arguments[3]) != 'undefined') {
5290 Roo.MessageBox.alert("Error loading",arguments[3]);
5294 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5295 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5304 this.el.unmask(this.removeMask);
5309 this.el.unmask(this.removeMask);
5313 onBeforeLoad : function(){
5315 this.el.mask(this.msg, this.msgCls);
5320 destroy : function(){
5322 this.store.un('beforeload', this.onBeforeLoad, this);
5323 this.store.un('load', this.onLoad, this);
5324 this.store.un('loadexception', this.onLoadException, this);
5326 var um = this.el.getUpdateManager();
5327 um.un('beforeupdate', this.onBeforeLoad, this);
5328 um.un('update', this.onLoad, this);
5329 um.un('failure', this.onLoad, this);
5340 * @class Roo.bootstrap.Table
5341 * @extends Roo.bootstrap.Component
5342 * Bootstrap Table class
5343 * @cfg {String} cls table class
5344 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5345 * @cfg {String} bgcolor Specifies the background color for a table
5346 * @cfg {Number} border Specifies whether the table cells should have borders or not
5347 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5348 * @cfg {Number} cellspacing Specifies the space between cells
5349 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5350 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5351 * @cfg {String} sortable Specifies that the table should be sortable
5352 * @cfg {String} summary Specifies a summary of the content of a table
5353 * @cfg {Number} width Specifies the width of a table
5354 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5356 * @cfg {boolean} striped Should the rows be alternative striped
5357 * @cfg {boolean} bordered Add borders to the table
5358 * @cfg {boolean} hover Add hover highlighting
5359 * @cfg {boolean} condensed Format condensed
5360 * @cfg {boolean} responsive Format condensed
5361 * @cfg {Boolean} loadMask (true|false) default false
5362 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5363 * @cfg {Boolean} thead (true|false) generate thead, default true
5364 * @cfg {Boolean} RowSelection (true|false) default false
5365 * @cfg {Boolean} CellSelection (true|false) default false
5366 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5370 * Create a new Table
5371 * @param {Object} config The config object
5374 Roo.bootstrap.Table = function(config){
5375 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5378 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5379 this.sm = this.selModel;
5380 this.sm.xmodule = this.xmodule || false;
5382 if (this.cm && typeof(this.cm.config) == 'undefined') {
5383 this.colModel = new Roo.grid.ColumnModel(this.cm);
5384 this.cm = this.colModel;
5385 this.cm.xmodule = this.xmodule || false;
5388 this.store= Roo.factory(this.store, Roo.data);
5389 this.ds = this.store;
5390 this.ds.xmodule = this.xmodule || false;
5393 if (this.footer && this.store) {
5394 this.footer.dataSource = this.ds;
5395 this.footer = Roo.factory(this.footer);
5402 * Fires when a cell is clicked
5403 * @param {Roo.bootstrap.Table} this
5404 * @param {Roo.Element} el
5405 * @param {Number} rowIndex
5406 * @param {Number} columnIndex
5407 * @param {Roo.EventObject} e
5411 * @event celldblclick
5412 * Fires when a cell is double clicked
5413 * @param {Roo.bootstrap.Table} this
5414 * @param {Roo.Element} el
5415 * @param {Number} rowIndex
5416 * @param {Number} columnIndex
5417 * @param {Roo.EventObject} e
5419 "celldblclick" : true,
5422 * Fires when a row is clicked
5423 * @param {Roo.bootstrap.Table} this
5424 * @param {Roo.Element} el
5425 * @param {Number} rowIndex
5426 * @param {Roo.EventObject} e
5430 * @event rowdblclick
5431 * Fires when a row is double clicked
5432 * @param {Roo.bootstrap.Table} this
5433 * @param {Roo.Element} el
5434 * @param {Number} rowIndex
5435 * @param {Roo.EventObject} e
5437 "rowdblclick" : true,
5440 * Fires when a mouseover occur
5441 * @param {Roo.bootstrap.Table} this
5442 * @param {Roo.Element} el
5443 * @param {Number} rowIndex
5444 * @param {Number} columnIndex
5445 * @param {Roo.EventObject} e
5450 * Fires when a mouseout occur
5451 * @param {Roo.bootstrap.Table} this
5452 * @param {Roo.Element} el
5453 * @param {Number} rowIndex
5454 * @param {Number} columnIndex
5455 * @param {Roo.EventObject} e
5460 * Fires when a row is rendered, so you can change add a style to it.
5461 * @param {Roo.bootstrap.Table} this
5462 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5466 * @event rowsrendered
5467 * Fires when all the rows have been rendered
5468 * @param {Roo.bootstrap.Table} this
5470 'rowsrendered' : true
5475 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5499 RowSelection : false,
5500 CellSelection : false,
5503 // Roo.Element - the tbody
5506 getAutoCreate : function(){
5507 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5516 cfg.cls += ' table-striped';
5520 cfg.cls += ' table-hover';
5522 if (this.bordered) {
5523 cfg.cls += ' table-bordered';
5525 if (this.condensed) {
5526 cfg.cls += ' table-condensed';
5528 if (this.responsive) {
5529 cfg.cls += ' table-responsive';
5533 cfg.cls+= ' ' +this.cls;
5536 // this lot should be simplifed...
5539 cfg.align=this.align;
5542 cfg.bgcolor=this.bgcolor;
5545 cfg.border=this.border;
5547 if (this.cellpadding) {
5548 cfg.cellpadding=this.cellpadding;
5550 if (this.cellspacing) {
5551 cfg.cellspacing=this.cellspacing;
5554 cfg.frame=this.frame;
5557 cfg.rules=this.rules;
5559 if (this.sortable) {
5560 cfg.sortable=this.sortable;
5563 cfg.summary=this.summary;
5566 cfg.width=this.width;
5569 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5572 if(this.store || this.cm){
5574 cfg.cn.push(this.renderHeader());
5577 cfg.cn.push(this.renderBody());
5580 cfg.cn.push(this.renderFooter());
5583 cfg.cls+= ' TableGrid';
5586 return { cn : [ cfg ] };
5589 initEvents : function()
5591 if(!this.store || !this.cm){
5595 //Roo.log('initEvents with ds!!!!');
5597 this.mainBody = this.el.select('tbody', true).first();
5602 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5603 e.on('click', _this.sort, _this);
5606 this.el.on("click", this.onClick, this);
5607 this.el.on("dblclick", this.onDblClick, this);
5609 // why is this done????? = it breaks dialogs??
5610 //this.parent().el.setStyle('position', 'relative');
5614 this.footer.parentId = this.id;
5615 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5618 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5620 this.store.on('load', this.onLoad, this);
5621 this.store.on('beforeload', this.onBeforeLoad, this);
5622 this.store.on('update', this.onUpdate, this);
5623 this.store.on('add', this.onAdd, this);
5627 onMouseover : function(e, el)
5629 var cell = Roo.get(el);
5635 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5636 cell = cell.findParent('td', false, true);
5639 var row = cell.findParent('tr', false, true);
5640 var cellIndex = cell.dom.cellIndex;
5641 var rowIndex = row.dom.rowIndex - 1; // start from 0
5643 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5647 onMouseout : function(e, el)
5649 var cell = Roo.get(el);
5655 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5656 cell = cell.findParent('td', false, true);
5659 var row = cell.findParent('tr', false, true);
5660 var cellIndex = cell.dom.cellIndex;
5661 var rowIndex = row.dom.rowIndex - 1; // start from 0
5663 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5667 onClick : function(e, el)
5669 var cell = Roo.get(el);
5671 if(!cell || (!this.CellSelection && !this.RowSelection)){
5675 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5676 cell = cell.findParent('td', false, true);
5679 if(!cell || typeof(cell) == 'undefined'){
5683 var row = cell.findParent('tr', false, true);
5685 if(!row || typeof(row) == 'undefined'){
5689 var cellIndex = cell.dom.cellIndex;
5690 var rowIndex = this.getRowIndex(row);
5692 if(this.CellSelection){
5693 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5696 if(this.RowSelection){
5697 this.fireEvent('rowclick', this, row, rowIndex, e);
5703 onDblClick : function(e,el)
5705 var cell = Roo.get(el);
5707 if(!cell || (!this.CellSelection && !this.RowSelection)){
5711 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5712 cell = cell.findParent('td', false, true);
5715 if(!cell || typeof(cell) == 'undefined'){
5719 var row = cell.findParent('tr', false, true);
5721 if(!row || typeof(row) == 'undefined'){
5725 var cellIndex = cell.dom.cellIndex;
5726 var rowIndex = this.getRowIndex(row);
5728 if(this.CellSelection){
5729 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5732 if(this.RowSelection){
5733 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5737 sort : function(e,el)
5739 var col = Roo.get(el);
5741 if(!col.hasClass('sortable')){
5745 var sort = col.attr('sort');
5748 if(col.hasClass('glyphicon-arrow-up')){
5752 this.store.sortInfo = {field : sort, direction : dir};
5755 Roo.log("calling footer first");
5756 this.footer.onClick('first');
5759 this.store.load({ params : { start : 0 } });
5763 renderHeader : function()
5772 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5774 var config = cm.config[i];
5779 html: cm.getColumnHeader(i)
5782 if(typeof(config.tooltip) != 'undefined'){
5783 c.tooltip = config.tooltip;
5786 if(typeof(config.colspan) != 'undefined'){
5787 c.colspan = config.colspan;
5790 if(typeof(config.hidden) != 'undefined' && config.hidden){
5791 c.style += ' display:none;';
5794 if(typeof(config.dataIndex) != 'undefined'){
5795 c.sort = config.dataIndex;
5798 if(typeof(config.sortable) != 'undefined' && config.sortable){
5802 if(typeof(config.align) != 'undefined' && config.align.length){
5803 c.style += ' text-align:' + config.align + ';';
5806 if(typeof(config.width) != 'undefined'){
5807 c.style += ' width:' + config.width + 'px;';
5810 if(typeof(config.cls) != 'undefined'){
5811 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5820 renderBody : function()
5830 colspan : this.cm.getColumnCount()
5840 renderFooter : function()
5850 colspan : this.cm.getColumnCount()
5864 Roo.log('ds onload');
5869 var ds = this.store;
5871 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5872 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5874 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5875 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5878 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5879 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5883 var tbody = this.mainBody;
5885 if(ds.getCount() > 0){
5886 ds.data.each(function(d,rowIndex){
5887 var row = this.renderRow(cm, ds, rowIndex);
5889 tbody.createChild(row);
5893 if(row.cellObjects.length){
5894 Roo.each(row.cellObjects, function(r){
5895 _this.renderCellObject(r);
5902 Roo.each(this.el.select('tbody td', true).elements, function(e){
5903 e.on('mouseover', _this.onMouseover, _this);
5906 Roo.each(this.el.select('tbody td', true).elements, function(e){
5907 e.on('mouseout', _this.onMouseout, _this);
5909 this.fireEvent('rowsrendered', this);
5910 //if(this.loadMask){
5911 // this.maskEl.hide();
5916 onUpdate : function(ds,record)
5918 this.refreshRow(record);
5921 onRemove : function(ds, record, index, isUpdate){
5922 if(isUpdate !== true){
5923 this.fireEvent("beforerowremoved", this, index, record);
5925 var bt = this.mainBody.dom;
5927 var rows = this.el.select('tbody > tr', true).elements;
5929 if(typeof(rows[index]) != 'undefined'){
5930 bt.removeChild(rows[index].dom);
5933 // if(bt.rows[index]){
5934 // bt.removeChild(bt.rows[index]);
5937 if(isUpdate !== true){
5938 //this.stripeRows(index);
5939 //this.syncRowHeights(index, index);
5941 this.fireEvent("rowremoved", this, index, record);
5945 onAdd : function(ds, records, rowIndex)
5947 //Roo.log('on Add called');
5948 // - note this does not handle multiple adding very well..
5949 var bt = this.mainBody.dom;
5950 for (var i =0 ; i < records.length;i++) {
5951 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5952 //Roo.log(records[i]);
5953 //Roo.log(this.store.getAt(rowIndex+i));
5954 this.insertRow(this.store, rowIndex + i, false);
5961 refreshRow : function(record){
5962 var ds = this.store, index;
5963 if(typeof record == 'number'){
5965 record = ds.getAt(index);
5967 index = ds.indexOf(record);
5969 this.insertRow(ds, index, true);
5970 this.onRemove(ds, record, index+1, true);
5971 //this.syncRowHeights(index, index);
5973 this.fireEvent("rowupdated", this, index, record);
5976 insertRow : function(dm, rowIndex, isUpdate){
5979 this.fireEvent("beforerowsinserted", this, rowIndex);
5981 //var s = this.getScrollState();
5982 var row = this.renderRow(this.cm, this.store, rowIndex);
5983 // insert before rowIndex..
5984 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5988 if(row.cellObjects.length){
5989 Roo.each(row.cellObjects, function(r){
5990 _this.renderCellObject(r);
5995 this.fireEvent("rowsinserted", this, rowIndex);
5996 //this.syncRowHeights(firstRow, lastRow);
5997 //this.stripeRows(firstRow);
6004 getRowDom : function(rowIndex)
6006 var rows = this.el.select('tbody > tr', true).elements;
6008 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6011 // returns the object tree for a tr..
6014 renderRow : function(cm, ds, rowIndex)
6017 var d = ds.getAt(rowIndex);
6024 var cellObjects = [];
6026 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6027 var config = cm.config[i];
6029 var renderer = cm.getRenderer(i);
6033 if(typeof(renderer) !== 'undefined'){
6034 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6036 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6037 // and are rendered into the cells after the row is rendered - using the id for the element.
6039 if(typeof(value) === 'object'){
6049 rowIndex : rowIndex,
6054 this.fireEvent('rowclass', this, rowcfg);
6058 cls : rowcfg.rowClass,
6060 html: (typeof(value) === 'object') ? '' : value
6067 if(typeof(config.colspan) != 'undefined'){
6068 td.colspan = config.colspan;
6071 if(typeof(config.hidden) != 'undefined' && config.hidden){
6072 td.style += ' display:none;';
6075 if(typeof(config.align) != 'undefined' && config.align.length){
6076 td.style += ' text-align:' + config.align + ';';
6079 if(typeof(config.width) != 'undefined'){
6080 td.style += ' width:' + config.width + 'px;';
6083 if(typeof(config.cursor) != 'undefined'){
6084 td.style += ' cursor:' + config.cursor + ';';
6087 if(typeof(config.cls) != 'undefined'){
6088 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6095 row.cellObjects = cellObjects;
6103 onBeforeLoad : function()
6105 //Roo.log('ds onBeforeLoad');
6109 //if(this.loadMask){
6110 // this.maskEl.show();
6118 this.el.select('tbody', true).first().dom.innerHTML = '';
6121 * Show or hide a row.
6122 * @param {Number} rowIndex to show or hide
6123 * @param {Boolean} state hide
6125 setRowVisibility : function(rowIndex, state)
6127 var bt = this.mainBody.dom;
6129 var rows = this.el.select('tbody > tr', true).elements;
6131 if(typeof(rows[rowIndex]) == 'undefined'){
6134 rows[rowIndex].dom.style.display = state ? '' : 'none';
6138 getSelectionModel : function(){
6140 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6142 return this.selModel;
6145 * Render the Roo.bootstrap object from renderder
6147 renderCellObject : function(r)
6151 var t = r.cfg.render(r.container);
6154 Roo.each(r.cfg.cn, function(c){
6156 container: t.getChildContainer(),
6159 _this.renderCellObject(child);
6164 getRowIndex : function(row)
6168 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6191 * @class Roo.bootstrap.TableCell
6192 * @extends Roo.bootstrap.Component
6193 * Bootstrap TableCell class
6194 * @cfg {String} html cell contain text
6195 * @cfg {String} cls cell class
6196 * @cfg {String} tag cell tag (td|th) default td
6197 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6198 * @cfg {String} align Aligns the content in a cell
6199 * @cfg {String} axis Categorizes cells
6200 * @cfg {String} bgcolor Specifies the background color of a cell
6201 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6202 * @cfg {Number} colspan Specifies the number of columns a cell should span
6203 * @cfg {String} headers Specifies one or more header cells a cell is related to
6204 * @cfg {Number} height Sets the height of a cell
6205 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6206 * @cfg {Number} rowspan Sets the number of rows a cell should span
6207 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6208 * @cfg {String} valign Vertical aligns the content in a cell
6209 * @cfg {Number} width Specifies the width of a cell
6212 * Create a new TableCell
6213 * @param {Object} config The config object
6216 Roo.bootstrap.TableCell = function(config){
6217 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6220 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6240 getAutoCreate : function(){
6241 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6261 cfg.align=this.align
6267 cfg.bgcolor=this.bgcolor
6270 cfg.charoff=this.charoff
6273 cfg.colspan=this.colspan
6276 cfg.headers=this.headers
6279 cfg.height=this.height
6282 cfg.nowrap=this.nowrap
6285 cfg.rowspan=this.rowspan
6288 cfg.scope=this.scope
6291 cfg.valign=this.valign
6294 cfg.width=this.width
6313 * @class Roo.bootstrap.TableRow
6314 * @extends Roo.bootstrap.Component
6315 * Bootstrap TableRow class
6316 * @cfg {String} cls row class
6317 * @cfg {String} align Aligns the content in a table row
6318 * @cfg {String} bgcolor Specifies a background color for a table row
6319 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6320 * @cfg {String} valign Vertical aligns the content in a table row
6323 * Create a new TableRow
6324 * @param {Object} config The config object
6327 Roo.bootstrap.TableRow = function(config){
6328 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6331 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6339 getAutoCreate : function(){
6340 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6350 cfg.align = this.align;
6353 cfg.bgcolor = this.bgcolor;
6356 cfg.charoff = this.charoff;
6359 cfg.valign = this.valign;
6377 * @class Roo.bootstrap.TableBody
6378 * @extends Roo.bootstrap.Component
6379 * Bootstrap TableBody class
6380 * @cfg {String} cls element class
6381 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6382 * @cfg {String} align Aligns the content inside the element
6383 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6384 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6387 * Create a new TableBody
6388 * @param {Object} config The config object
6391 Roo.bootstrap.TableBody = function(config){
6392 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6395 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6403 getAutoCreate : function(){
6404 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6418 cfg.align = this.align;
6421 cfg.charoff = this.charoff;
6424 cfg.valign = this.valign;
6431 // initEvents : function()
6438 // this.store = Roo.factory(this.store, Roo.data);
6439 // this.store.on('load', this.onLoad, this);
6441 // this.store.load();
6445 // onLoad: function ()
6447 // this.fireEvent('load', this);
6457 * Ext JS Library 1.1.1
6458 * Copyright(c) 2006-2007, Ext JS, LLC.
6460 * Originally Released Under LGPL - original licence link has changed is not relivant.
6463 * <script type="text/javascript">
6466 // as we use this in bootstrap.
6467 Roo.namespace('Roo.form');
6469 * @class Roo.form.Action
6470 * Internal Class used to handle form actions
6472 * @param {Roo.form.BasicForm} el The form element or its id
6473 * @param {Object} config Configuration options
6478 // define the action interface
6479 Roo.form.Action = function(form, options){
6481 this.options = options || {};
6484 * Client Validation Failed
6487 Roo.form.Action.CLIENT_INVALID = 'client';
6489 * Server Validation Failed
6492 Roo.form.Action.SERVER_INVALID = 'server';
6494 * Connect to Server Failed
6497 Roo.form.Action.CONNECT_FAILURE = 'connect';
6499 * Reading Data from Server Failed
6502 Roo.form.Action.LOAD_FAILURE = 'load';
6504 Roo.form.Action.prototype = {
6506 failureType : undefined,
6507 response : undefined,
6511 run : function(options){
6516 success : function(response){
6521 handleResponse : function(response){
6525 // default connection failure
6526 failure : function(response){
6528 this.response = response;
6529 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6530 this.form.afterAction(this, false);
6533 processResponse : function(response){
6534 this.response = response;
6535 if(!response.responseText){
6538 this.result = this.handleResponse(response);
6542 // utility functions used internally
6543 getUrl : function(appendParams){
6544 var url = this.options.url || this.form.url || this.form.el.dom.action;
6546 var p = this.getParams();
6548 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6554 getMethod : function(){
6555 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6558 getParams : function(){
6559 var bp = this.form.baseParams;
6560 var p = this.options.params;
6562 if(typeof p == "object"){
6563 p = Roo.urlEncode(Roo.applyIf(p, bp));
6564 }else if(typeof p == 'string' && bp){
6565 p += '&' + Roo.urlEncode(bp);
6568 p = Roo.urlEncode(bp);
6573 createCallback : function(){
6575 success: this.success,
6576 failure: this.failure,
6578 timeout: (this.form.timeout*1000),
6579 upload: this.form.fileUpload ? this.success : undefined
6584 Roo.form.Action.Submit = function(form, options){
6585 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6588 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6591 haveProgress : false,
6592 uploadComplete : false,
6594 // uploadProgress indicator.
6595 uploadProgress : function()
6597 if (!this.form.progressUrl) {
6601 if (!this.haveProgress) {
6602 Roo.MessageBox.progress("Uploading", "Uploading");
6604 if (this.uploadComplete) {
6605 Roo.MessageBox.hide();
6609 this.haveProgress = true;
6611 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6613 var c = new Roo.data.Connection();
6615 url : this.form.progressUrl,
6620 success : function(req){
6621 //console.log(data);
6625 rdata = Roo.decode(req.responseText)
6627 Roo.log("Invalid data from server..");
6631 if (!rdata || !rdata.success) {
6633 Roo.MessageBox.alert(Roo.encode(rdata));
6636 var data = rdata.data;
6638 if (this.uploadComplete) {
6639 Roo.MessageBox.hide();
6644 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6645 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6648 this.uploadProgress.defer(2000,this);
6651 failure: function(data) {
6652 Roo.log('progress url failed ');
6663 // run get Values on the form, so it syncs any secondary forms.
6664 this.form.getValues();
6666 var o = this.options;
6667 var method = this.getMethod();
6668 var isPost = method == 'POST';
6669 if(o.clientValidation === false || this.form.isValid()){
6671 if (this.form.progressUrl) {
6672 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6673 (new Date() * 1) + '' + Math.random());
6678 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6679 form:this.form.el.dom,
6680 url:this.getUrl(!isPost),
6682 params:isPost ? this.getParams() : null,
6683 isUpload: this.form.fileUpload
6686 this.uploadProgress();
6688 }else if (o.clientValidation !== false){ // client validation failed
6689 this.failureType = Roo.form.Action.CLIENT_INVALID;
6690 this.form.afterAction(this, false);
6694 success : function(response)
6696 this.uploadComplete= true;
6697 if (this.haveProgress) {
6698 Roo.MessageBox.hide();
6702 var result = this.processResponse(response);
6703 if(result === true || result.success){
6704 this.form.afterAction(this, true);
6708 this.form.markInvalid(result.errors);
6709 this.failureType = Roo.form.Action.SERVER_INVALID;
6711 this.form.afterAction(this, false);
6713 failure : function(response)
6715 this.uploadComplete= true;
6716 if (this.haveProgress) {
6717 Roo.MessageBox.hide();
6720 this.response = response;
6721 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6722 this.form.afterAction(this, false);
6725 handleResponse : function(response){
6726 if(this.form.errorReader){
6727 var rs = this.form.errorReader.read(response);
6730 for(var i = 0, len = rs.records.length; i < len; i++) {
6731 var r = rs.records[i];
6735 if(errors.length < 1){
6739 success : rs.success,
6745 ret = Roo.decode(response.responseText);
6749 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6759 Roo.form.Action.Load = function(form, options){
6760 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6761 this.reader = this.form.reader;
6764 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6769 Roo.Ajax.request(Roo.apply(
6770 this.createCallback(), {
6771 method:this.getMethod(),
6772 url:this.getUrl(false),
6773 params:this.getParams()
6777 success : function(response){
6779 var result = this.processResponse(response);
6780 if(result === true || !result.success || !result.data){
6781 this.failureType = Roo.form.Action.LOAD_FAILURE;
6782 this.form.afterAction(this, false);
6785 this.form.clearInvalid();
6786 this.form.setValues(result.data);
6787 this.form.afterAction(this, true);
6790 handleResponse : function(response){
6791 if(this.form.reader){
6792 var rs = this.form.reader.read(response);
6793 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6795 success : rs.success,
6799 return Roo.decode(response.responseText);
6803 Roo.form.Action.ACTION_TYPES = {
6804 'load' : Roo.form.Action.Load,
6805 'submit' : Roo.form.Action.Submit
6814 * @class Roo.bootstrap.Form
6815 * @extends Roo.bootstrap.Component
6816 * Bootstrap Form class
6817 * @cfg {String} method GET | POST (default POST)
6818 * @cfg {String} labelAlign top | left (default top)
6819 * @cfg {String} align left | right - for navbars
6820 * @cfg {Boolean} loadMask load mask when submit (default true)
6825 * @param {Object} config The config object
6829 Roo.bootstrap.Form = function(config){
6830 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6833 * @event clientvalidation
6834 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6835 * @param {Form} this
6836 * @param {Boolean} valid true if the form has passed client-side validation
6838 clientvalidation: true,
6840 * @event beforeaction
6841 * Fires before any action is performed. Return false to cancel the action.
6842 * @param {Form} this
6843 * @param {Action} action The action to be performed
6847 * @event actionfailed
6848 * Fires when an action fails.
6849 * @param {Form} this
6850 * @param {Action} action The action that failed
6852 actionfailed : true,
6854 * @event actioncomplete
6855 * Fires when an action is completed.
6856 * @param {Form} this
6857 * @param {Action} action The action that completed
6859 actioncomplete : true
6864 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6867 * @cfg {String} method
6868 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6873 * The URL to use for form actions if one isn't supplied in the action options.
6876 * @cfg {Boolean} fileUpload
6877 * Set to true if this form is a file upload.
6881 * @cfg {Object} baseParams
6882 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6886 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6890 * @cfg {Sting} align (left|right) for navbar forms
6895 activeAction : null,
6898 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6899 * element by passing it or its id or mask the form itself by passing in true.
6902 waitMsgTarget : false,
6906 getAutoCreate : function(){
6910 method : this.method || 'POST',
6911 id : this.id || Roo.id(),
6914 if (this.parent().xtype.match(/^Nav/)) {
6915 cfg.cls = 'navbar-form navbar-' + this.align;
6919 if (this.labelAlign == 'left' ) {
6920 cfg.cls += ' form-horizontal';
6926 initEvents : function()
6928 this.el.on('submit', this.onSubmit, this);
6929 // this was added as random key presses on the form where triggering form submit.
6930 this.el.on('keypress', function(e) {
6931 if (e.getCharCode() != 13) {
6934 // we might need to allow it for textareas.. and some other items.
6935 // check e.getTarget().
6937 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6941 Roo.log("keypress blocked");
6949 onSubmit : function(e){
6954 * Returns true if client-side validation on the form is successful.
6957 isValid : function(){
6958 var items = this.getItems();
6960 items.each(function(f){
6969 * Returns true if any fields in this form have changed since their original load.
6972 isDirty : function(){
6974 var items = this.getItems();
6975 items.each(function(f){
6985 * Performs a predefined action (submit or load) or custom actions you define on this form.
6986 * @param {String} actionName The name of the action type
6987 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6988 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6989 * accept other config options):
6991 Property Type Description
6992 ---------------- --------------- ----------------------------------------------------------------------------------
6993 url String The url for the action (defaults to the form's url)
6994 method String The form method to use (defaults to the form's method, or POST if not defined)
6995 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6996 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6997 validate the form on the client (defaults to false)
6999 * @return {BasicForm} this
7001 doAction : function(action, options){
7002 if(typeof action == 'string'){
7003 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7005 if(this.fireEvent('beforeaction', this, action) !== false){
7006 this.beforeAction(action);
7007 action.run.defer(100, action);
7013 beforeAction : function(action){
7014 var o = action.options;
7017 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7019 // not really supported yet.. ??
7021 //if(this.waitMsgTarget === true){
7022 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7023 //}else if(this.waitMsgTarget){
7024 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7025 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7027 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7033 afterAction : function(action, success){
7034 this.activeAction = null;
7035 var o = action.options;
7037 //if(this.waitMsgTarget === true){
7039 //}else if(this.waitMsgTarget){
7040 // this.waitMsgTarget.unmask();
7042 // Roo.MessageBox.updateProgress(1);
7043 // Roo.MessageBox.hide();
7050 Roo.callback(o.success, o.scope, [this, action]);
7051 this.fireEvent('actioncomplete', this, action);
7055 // failure condition..
7056 // we have a scenario where updates need confirming.
7057 // eg. if a locking scenario exists..
7058 // we look for { errors : { needs_confirm : true }} in the response.
7060 (typeof(action.result) != 'undefined') &&
7061 (typeof(action.result.errors) != 'undefined') &&
7062 (typeof(action.result.errors.needs_confirm) != 'undefined')
7065 Roo.log("not supported yet");
7068 Roo.MessageBox.confirm(
7069 "Change requires confirmation",
7070 action.result.errorMsg,
7075 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7085 Roo.callback(o.failure, o.scope, [this, action]);
7086 // show an error message if no failed handler is set..
7087 if (!this.hasListener('actionfailed')) {
7088 Roo.log("need to add dialog support");
7090 Roo.MessageBox.alert("Error",
7091 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7092 action.result.errorMsg :
7093 "Saving Failed, please check your entries or try again"
7098 this.fireEvent('actionfailed', this, action);
7103 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7104 * @param {String} id The value to search for
7107 findField : function(id){
7108 var items = this.getItems();
7109 var field = items.get(id);
7111 items.each(function(f){
7112 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7119 return field || null;
7122 * Mark fields in this form invalid in bulk.
7123 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7124 * @return {BasicForm} this
7126 markInvalid : function(errors){
7127 if(errors instanceof Array){
7128 for(var i = 0, len = errors.length; i < len; i++){
7129 var fieldError = errors[i];
7130 var f = this.findField(fieldError.id);
7132 f.markInvalid(fieldError.msg);
7138 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7139 field.markInvalid(errors[id]);
7143 //Roo.each(this.childForms || [], function (f) {
7144 // f.markInvalid(errors);
7151 * Set values for fields in this form in bulk.
7152 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7153 * @return {BasicForm} this
7155 setValues : function(values){
7156 if(values instanceof Array){ // array of objects
7157 for(var i = 0, len = values.length; i < len; i++){
7159 var f = this.findField(v.id);
7161 f.setValue(v.value);
7162 if(this.trackResetOnLoad){
7163 f.originalValue = f.getValue();
7167 }else{ // object hash
7170 if(typeof values[id] != 'function' && (field = this.findField(id))){
7172 if (field.setFromData &&
7174 field.displayField &&
7175 // combos' with local stores can
7176 // be queried via setValue()
7177 // to set their value..
7178 (field.store && !field.store.isLocal)
7182 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7183 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7184 field.setFromData(sd);
7187 field.setValue(values[id]);
7191 if(this.trackResetOnLoad){
7192 field.originalValue = field.getValue();
7198 //Roo.each(this.childForms || [], function (f) {
7199 // f.setValues(values);
7206 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7207 * they are returned as an array.
7208 * @param {Boolean} asString
7211 getValues : function(asString){
7212 //if (this.childForms) {
7213 // copy values from the child forms
7214 // Roo.each(this.childForms, function (f) {
7215 // this.setValues(f.getValues());
7221 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7222 if(asString === true){
7225 return Roo.urlDecode(fs);
7229 * Returns the fields in this form as an object with key/value pairs.
7230 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7233 getFieldValues : function(with_hidden)
7235 var items = this.getItems();
7237 items.each(function(f){
7241 var v = f.getValue();
7242 if (f.inputType =='radio') {
7243 if (typeof(ret[f.getName()]) == 'undefined') {
7244 ret[f.getName()] = ''; // empty..
7247 if (!f.el.dom.checked) {
7255 // not sure if this supported any more..
7256 if ((typeof(v) == 'object') && f.getRawValue) {
7257 v = f.getRawValue() ; // dates..
7259 // combo boxes where name != hiddenName...
7260 if (f.name != f.getName()) {
7261 ret[f.name] = f.getRawValue();
7263 ret[f.getName()] = v;
7270 * Clears all invalid messages in this form.
7271 * @return {BasicForm} this
7273 clearInvalid : function(){
7274 var items = this.getItems();
7276 items.each(function(f){
7287 * @return {BasicForm} this
7290 var items = this.getItems();
7291 items.each(function(f){
7295 Roo.each(this.childForms || [], function (f) {
7302 getItems : function()
7304 var r=new Roo.util.MixedCollection(false, function(o){
7305 return o.id || (o.id = Roo.id());
7307 var iter = function(el) {
7314 Roo.each(el.items,function(e) {
7334 * Ext JS Library 1.1.1
7335 * Copyright(c) 2006-2007, Ext JS, LLC.
7337 * Originally Released Under LGPL - original licence link has changed is not relivant.
7340 * <script type="text/javascript">
7343 * @class Roo.form.VTypes
7344 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7347 Roo.form.VTypes = function(){
7348 // closure these in so they are only created once.
7349 var alpha = /^[a-zA-Z_]+$/;
7350 var alphanum = /^[a-zA-Z0-9_]+$/;
7351 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7352 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7354 // All these messages and functions are configurable
7357 * The function used to validate email addresses
7358 * @param {String} value The email address
7360 'email' : function(v){
7361 return email.test(v);
7364 * The error text to display when the email validation function returns false
7367 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7369 * The keystroke filter mask to be applied on email input
7372 'emailMask' : /[a-z0-9_\.\-@]/i,
7375 * The function used to validate URLs
7376 * @param {String} value The URL
7378 'url' : function(v){
7382 * The error text to display when the url validation function returns false
7385 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7388 * The function used to validate alpha values
7389 * @param {String} value The value
7391 'alpha' : function(v){
7392 return alpha.test(v);
7395 * The error text to display when the alpha validation function returns false
7398 'alphaText' : 'This field should only contain letters and _',
7400 * The keystroke filter mask to be applied on alpha input
7403 'alphaMask' : /[a-z_]/i,
7406 * The function used to validate alphanumeric values
7407 * @param {String} value The value
7409 'alphanum' : function(v){
7410 return alphanum.test(v);
7413 * The error text to display when the alphanumeric validation function returns false
7416 'alphanumText' : 'This field should only contain letters, numbers and _',
7418 * The keystroke filter mask to be applied on alphanumeric input
7421 'alphanumMask' : /[a-z0-9_]/i
7431 * @class Roo.bootstrap.Input
7432 * @extends Roo.bootstrap.Component
7433 * Bootstrap Input class
7434 * @cfg {Boolean} disabled is it disabled
7435 * @cfg {String} fieldLabel - the label associated
7436 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7437 * @cfg {String} name name of the input
7438 * @cfg {string} fieldLabel - the label associated
7439 * @cfg {string} inputType - input / file submit ...
7440 * @cfg {string} placeholder - placeholder to put in text.
7441 * @cfg {string} before - input group add on before
7442 * @cfg {string} after - input group add on after
7443 * @cfg {string} size - (lg|sm) or leave empty..
7444 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7445 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7446 * @cfg {Number} md colspan out of 12 for computer-sized screens
7447 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7448 * @cfg {string} value default value of the input
7449 * @cfg {Number} labelWidth set the width of label (0-12)
7450 * @cfg {String} labelAlign (top|left)
7451 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7452 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7454 * @cfg {String} align (left|center|right) Default left
7459 * Create a new Input
7460 * @param {Object} config The config object
7463 Roo.bootstrap.Input = function(config){
7464 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7469 * Fires when this field receives input focus.
7470 * @param {Roo.form.Field} this
7475 * Fires when this field loses input focus.
7476 * @param {Roo.form.Field} this
7481 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7482 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7483 * @param {Roo.form.Field} this
7484 * @param {Roo.EventObject} e The event object
7489 * Fires just before the field blurs if the field value has changed.
7490 * @param {Roo.form.Field} this
7491 * @param {Mixed} newValue The new value
7492 * @param {Mixed} oldValue The original value
7497 * Fires after the field has been marked as invalid.
7498 * @param {Roo.form.Field} this
7499 * @param {String} msg The validation message
7504 * Fires after the field has been validated with no errors.
7505 * @param {Roo.form.Field} this
7510 * Fires after the key up
7511 * @param {Roo.form.Field} this
7512 * @param {Roo.EventObject} e The event Object
7518 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7520 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7521 automatic validation (defaults to "keyup").
7523 validationEvent : "keyup",
7525 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7527 validateOnBlur : true,
7529 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7531 validationDelay : 250,
7533 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7535 focusClass : "x-form-focus", // not needed???
7539 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7541 invalidClass : "has-warning",
7544 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7546 validClass : "has-success",
7549 * @cfg {Boolean} hasFeedback (true|false) default true
7554 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7556 invalidFeedbackClass : "glyphicon-warning-sign",
7559 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7561 validFeedbackClass : "glyphicon-ok",
7564 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7566 selectOnFocus : false,
7569 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7573 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7578 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7580 disableKeyFilter : false,
7583 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7587 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7591 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7593 blankText : "This field is required",
7596 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7600 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7602 maxLength : Number.MAX_VALUE,
7604 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7606 minLengthText : "The minimum length for this field is {0}",
7608 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7610 maxLengthText : "The maximum length for this field is {0}",
7614 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7615 * If available, this function will be called only after the basic validators all return true, and will be passed the
7616 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7620 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7621 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7622 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7626 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7630 autocomplete: false,
7649 formatedValue : false,
7651 parentLabelAlign : function()
7654 while (parent.parent()) {
7655 parent = parent.parent();
7656 if (typeof(parent.labelAlign) !='undefined') {
7657 return parent.labelAlign;
7664 getAutoCreate : function(){
7666 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7672 if(this.inputType != 'hidden'){
7673 cfg.cls = 'form-group' //input-group
7679 type : this.inputType,
7681 cls : 'form-control',
7682 placeholder : this.placeholder || '',
7683 autocomplete : this.autocomplete || 'new-password'
7688 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7691 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7692 input.maxLength = this.maxLength;
7695 if (this.disabled) {
7696 input.disabled=true;
7699 if (this.readOnly) {
7700 input.readonly=true;
7704 input.name = this.name;
7707 input.cls += ' input-' + this.size;
7710 ['xs','sm','md','lg'].map(function(size){
7711 if (settings[size]) {
7712 cfg.cls += ' col-' + size + '-' + settings[size];
7716 var inputblock = input;
7720 cls: 'glyphicon form-control-feedback'
7723 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7726 cls : 'has-feedback',
7734 if (this.before || this.after) {
7737 cls : 'input-group',
7741 if (this.before && typeof(this.before) == 'string') {
7743 inputblock.cn.push({
7745 cls : 'roo-input-before input-group-addon',
7749 if (this.before && typeof(this.before) == 'object') {
7750 this.before = Roo.factory(this.before);
7751 Roo.log(this.before);
7752 inputblock.cn.push({
7754 cls : 'roo-input-before input-group-' +
7755 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7759 inputblock.cn.push(input);
7761 if (this.after && typeof(this.after) == 'string') {
7762 inputblock.cn.push({
7764 cls : 'roo-input-after input-group-addon',
7768 if (this.after && typeof(this.after) == 'object') {
7769 this.after = Roo.factory(this.after);
7770 Roo.log(this.after);
7771 inputblock.cn.push({
7773 cls : 'roo-input-after input-group-' +
7774 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7778 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7779 inputblock.cls += ' has-feedback';
7780 inputblock.cn.push(feedback);
7784 if (align ==='left' && this.fieldLabel.length) {
7785 Roo.log("left and has label");
7791 cls : 'control-label col-sm-' + this.labelWidth,
7792 html : this.fieldLabel
7796 cls : "col-sm-" + (12 - this.labelWidth),
7803 } else if ( this.fieldLabel.length) {
7809 //cls : 'input-group-addon',
7810 html : this.fieldLabel
7820 Roo.log(" no label && no align");
7829 Roo.log('input-parentType: ' + this.parentType);
7831 if (this.parentType === 'Navbar' && this.parent().bar) {
7832 cfg.cls += ' navbar-form';
7840 * return the real input element.
7842 inputEl: function ()
7844 return this.el.select('input.form-control',true).first();
7847 tooltipEl : function()
7849 return this.inputEl();
7852 setDisabled : function(v)
7854 var i = this.inputEl().dom;
7856 i.removeAttribute('disabled');
7860 i.setAttribute('disabled','true');
7862 initEvents : function()
7865 this.inputEl().on("keydown" , this.fireKey, this);
7866 this.inputEl().on("focus", this.onFocus, this);
7867 this.inputEl().on("blur", this.onBlur, this);
7869 this.inputEl().relayEvent('keyup', this);
7871 // reference to original value for reset
7872 this.originalValue = this.getValue();
7873 //Roo.form.TextField.superclass.initEvents.call(this);
7874 if(this.validationEvent == 'keyup'){
7875 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7876 this.inputEl().on('keyup', this.filterValidation, this);
7878 else if(this.validationEvent !== false){
7879 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7882 if(this.selectOnFocus){
7883 this.on("focus", this.preFocus, this);
7886 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7887 this.inputEl().on("keypress", this.filterKeys, this);
7890 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7891 this.el.on("click", this.autoSize, this);
7894 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7895 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7898 if (typeof(this.before) == 'object') {
7899 this.before.render(this.el.select('.roo-input-before',true).first());
7901 if (typeof(this.after) == 'object') {
7902 this.after.render(this.el.select('.roo-input-after',true).first());
7907 filterValidation : function(e){
7908 if(!e.isNavKeyPress()){
7909 this.validationTask.delay(this.validationDelay);
7913 * Validates the field value
7914 * @return {Boolean} True if the value is valid, else false
7916 validate : function(){
7917 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7918 if(this.disabled || this.validateValue(this.getRawValue())){
7929 * Validates a value according to the field's validation rules and marks the field as invalid
7930 * if the validation fails
7931 * @param {Mixed} value The value to validate
7932 * @return {Boolean} True if the value is valid, else false
7934 validateValue : function(value){
7935 if(value.length < 1) { // if it's blank
7936 if(this.allowBlank){
7942 if(value.length < this.minLength){
7945 if(value.length > this.maxLength){
7949 var vt = Roo.form.VTypes;
7950 if(!vt[this.vtype](value, this)){
7954 if(typeof this.validator == "function"){
7955 var msg = this.validator(value);
7961 if(this.regex && !this.regex.test(value)){
7971 fireKey : function(e){
7972 //Roo.log('field ' + e.getKey());
7973 if(e.isNavKeyPress()){
7974 this.fireEvent("specialkey", this, e);
7977 focus : function (selectText){
7979 this.inputEl().focus();
7980 if(selectText === true){
7981 this.inputEl().dom.select();
7987 onFocus : function(){
7988 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7989 // this.el.addClass(this.focusClass);
7992 this.hasFocus = true;
7993 this.startValue = this.getValue();
7994 this.fireEvent("focus", this);
7998 beforeBlur : Roo.emptyFn,
8002 onBlur : function(){
8004 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8005 //this.el.removeClass(this.focusClass);
8007 this.hasFocus = false;
8008 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8011 var v = this.getValue();
8012 if(String(v) !== String(this.startValue)){
8013 this.fireEvent('change', this, v, this.startValue);
8015 this.fireEvent("blur", this);
8019 * Resets the current field value to the originally loaded value and clears any validation messages
8022 this.setValue(this.originalValue);
8026 * Returns the name of the field
8027 * @return {Mixed} name The name field
8029 getName: function(){
8033 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8034 * @return {Mixed} value The field value
8036 getValue : function(){
8038 var v = this.inputEl().getValue();
8043 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8044 * @return {Mixed} value The field value
8046 getRawValue : function(){
8047 var v = this.inputEl().getValue();
8053 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8054 * @param {Mixed} value The value to set
8056 setRawValue : function(v){
8057 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8060 selectText : function(start, end){
8061 var v = this.getRawValue();
8063 start = start === undefined ? 0 : start;
8064 end = end === undefined ? v.length : end;
8065 var d = this.inputEl().dom;
8066 if(d.setSelectionRange){
8067 d.setSelectionRange(start, end);
8068 }else if(d.createTextRange){
8069 var range = d.createTextRange();
8070 range.moveStart("character", start);
8071 range.moveEnd("character", v.length-end);
8078 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8079 * @param {Mixed} value The value to set
8081 setValue : function(v){
8084 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8090 processValue : function(value){
8091 if(this.stripCharsRe){
8092 var newValue = value.replace(this.stripCharsRe, '');
8093 if(newValue !== value){
8094 this.setRawValue(newValue);
8101 preFocus : function(){
8103 if(this.selectOnFocus){
8104 this.inputEl().dom.select();
8107 filterKeys : function(e){
8109 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8112 var c = e.getCharCode(), cc = String.fromCharCode(c);
8113 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8116 if(!this.maskRe.test(cc)){
8121 * Clear any invalid styles/messages for this field
8123 clearInvalid : function(){
8125 if(!this.el || this.preventMark){ // not rendered
8128 this.el.removeClass(this.invalidClass);
8130 this.fireEvent('valid', this);
8134 * Mark this field as valid
8136 markValid : function(){
8137 if(!this.el || this.preventMark){ // not rendered
8141 this.el.removeClass([this.invalidClass, this.validClass]);
8143 if(this.disabled || this.allowBlank){
8147 this.el.addClass(this.validClass);
8149 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8151 var feedback = this.el.select('.form-control-feedback', true).first();
8154 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8155 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8160 this.fireEvent('valid', this);
8164 * Mark this field as invalid
8165 * @param {String} msg The validation message
8167 markInvalid : function(msg){
8168 if(!this.el || this.preventMark){ // not rendered
8172 this.el.removeClass([this.invalidClass, this.validClass]);
8174 if(this.disabled || this.allowBlank){
8178 this.el.addClass(this.invalidClass);
8180 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8182 var feedback = this.el.select('.form-control-feedback', true).first();
8185 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8187 if(this.getValue().length){
8188 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8195 this.fireEvent('invalid', this, msg);
8198 SafariOnKeyDown : function(event)
8200 // this is a workaround for a password hang bug on chrome/ webkit.
8202 var isSelectAll = false;
8204 if(this.inputEl().dom.selectionEnd > 0){
8205 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8207 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8208 event.preventDefault();
8213 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8215 event.preventDefault();
8216 // this is very hacky as keydown always get's upper case.
8218 var cc = String.fromCharCode(event.getCharCode());
8219 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8223 adjustWidth : function(tag, w){
8224 tag = tag.toLowerCase();
8225 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8226 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8230 if(tag == 'textarea'){
8233 }else if(Roo.isOpera){
8237 if(tag == 'textarea'){
8256 * @class Roo.bootstrap.TextArea
8257 * @extends Roo.bootstrap.Input
8258 * Bootstrap TextArea class
8259 * @cfg {Number} cols Specifies the visible width of a text area
8260 * @cfg {Number} rows Specifies the visible number of lines in a text area
8261 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8262 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8263 * @cfg {string} html text
8266 * Create a new TextArea
8267 * @param {Object} config The config object
8270 Roo.bootstrap.TextArea = function(config){
8271 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8275 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8285 getAutoCreate : function(){
8287 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8298 value : this.value || '',
8299 html: this.html || '',
8300 cls : 'form-control',
8301 placeholder : this.placeholder || ''
8305 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8306 input.maxLength = this.maxLength;
8310 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8314 input.cols = this.cols;
8317 if (this.readOnly) {
8318 input.readonly = true;
8322 input.name = this.name;
8326 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8330 ['xs','sm','md','lg'].map(function(size){
8331 if (settings[size]) {
8332 cfg.cls += ' col-' + size + '-' + settings[size];
8336 var inputblock = input;
8338 if(this.hasFeedback && !this.allowBlank){
8342 cls: 'glyphicon form-control-feedback'
8346 cls : 'has-feedback',
8355 if (this.before || this.after) {
8358 cls : 'input-group',
8362 inputblock.cn.push({
8364 cls : 'input-group-addon',
8369 inputblock.cn.push(input);
8371 if(this.hasFeedback && !this.allowBlank){
8372 inputblock.cls += ' has-feedback';
8373 inputblock.cn.push(feedback);
8377 inputblock.cn.push({
8379 cls : 'input-group-addon',
8386 if (align ==='left' && this.fieldLabel.length) {
8387 Roo.log("left and has label");
8393 cls : 'control-label col-sm-' + this.labelWidth,
8394 html : this.fieldLabel
8398 cls : "col-sm-" + (12 - this.labelWidth),
8405 } else if ( this.fieldLabel.length) {
8411 //cls : 'input-group-addon',
8412 html : this.fieldLabel
8422 Roo.log(" no label && no align");
8432 if (this.disabled) {
8433 input.disabled=true;
8440 * return the real textarea element.
8442 inputEl: function ()
8444 return this.el.select('textarea.form-control',true).first();
8452 * trigger field - base class for combo..
8457 * @class Roo.bootstrap.TriggerField
8458 * @extends Roo.bootstrap.Input
8459 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8460 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8461 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8462 * for which you can provide a custom implementation. For example:
8464 var trigger = new Roo.bootstrap.TriggerField();
8465 trigger.onTriggerClick = myTriggerFn;
8466 trigger.applyTo('my-field');
8469 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8470 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8471 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8472 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8473 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8476 * Create a new TriggerField.
8477 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8478 * to the base TextField)
8480 Roo.bootstrap.TriggerField = function(config){
8481 this.mimicing = false;
8482 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8485 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8487 * @cfg {String} triggerClass A CSS class to apply to the trigger
8490 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8495 * @cfg {Boolean} removable (true|false) special filter default false
8499 /** @cfg {Boolean} grow @hide */
8500 /** @cfg {Number} growMin @hide */
8501 /** @cfg {Number} growMax @hide */
8507 autoSize: Roo.emptyFn,
8514 actionMode : 'wrap',
8519 getAutoCreate : function(){
8521 var align = this.labelAlign || this.parentLabelAlign();
8526 cls: 'form-group' //input-group
8533 type : this.inputType,
8534 cls : 'form-control',
8535 autocomplete: 'new-password',
8536 placeholder : this.placeholder || ''
8540 input.name = this.name;
8543 input.cls += ' input-' + this.size;
8546 if (this.disabled) {
8547 input.disabled=true;
8550 var inputblock = input;
8552 if(this.hasFeedback && !this.allowBlank){
8556 cls: 'glyphicon form-control-feedback'
8559 if(this.removable && !this.editable && !this.tickable){
8561 cls : 'has-feedback',
8567 cls : 'roo-combo-removable-btn close'
8574 cls : 'has-feedback',
8583 if(this.removable && !this.editable && !this.tickable){
8585 cls : 'roo-removable',
8591 cls : 'roo-combo-removable-btn close'
8598 if (this.before || this.after) {
8601 cls : 'input-group',
8605 inputblock.cn.push({
8607 cls : 'input-group-addon',
8612 inputblock.cn.push(input);
8614 if(this.hasFeedback && !this.allowBlank){
8615 inputblock.cls += ' has-feedback';
8616 inputblock.cn.push(feedback);
8620 inputblock.cn.push({
8622 cls : 'input-group-addon',
8635 cls: 'form-hidden-field'
8643 Roo.log('multiple');
8651 cls: 'form-hidden-field'
8655 cls: 'select2-choices',
8659 cls: 'select2-search-field',
8672 cls: 'select2-container input-group',
8677 // cls: 'typeahead typeahead-long dropdown-menu',
8678 // style: 'display:none'
8683 if(!this.multiple && this.showToggleBtn){
8689 if (this.caret != false) {
8692 cls: 'fa fa-' + this.caret
8699 cls : 'input-group-addon btn dropdown-toggle',
8704 cls: 'combobox-clear',
8718 combobox.cls += ' select2-container-multi';
8721 if (align ==='left' && this.fieldLabel.length) {
8723 Roo.log("left and has label");
8729 cls : 'control-label col-sm-' + this.labelWidth,
8730 html : this.fieldLabel
8734 cls : "col-sm-" + (12 - this.labelWidth),
8741 } else if ( this.fieldLabel.length) {
8747 //cls : 'input-group-addon',
8748 html : this.fieldLabel
8758 Roo.log(" no label && no align");
8765 ['xs','sm','md','lg'].map(function(size){
8766 if (settings[size]) {
8767 cfg.cls += ' col-' + size + '-' + settings[size];
8778 onResize : function(w, h){
8779 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8780 // if(typeof w == 'number'){
8781 // var x = w - this.trigger.getWidth();
8782 // this.inputEl().setWidth(this.adjustWidth('input', x));
8783 // this.trigger.setStyle('left', x+'px');
8788 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8791 getResizeEl : function(){
8792 return this.inputEl();
8796 getPositionEl : function(){
8797 return this.inputEl();
8801 alignErrorIcon : function(){
8802 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8806 initEvents : function(){
8810 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8811 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8812 if(!this.multiple && this.showToggleBtn){
8813 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8814 if(this.hideTrigger){
8815 this.trigger.setDisplayed(false);
8817 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8821 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8824 if(this.removable && !this.editable && !this.tickable){
8825 var close = this.closeTriggerEl();
8828 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8829 close.on('click', this.removeBtnClick, this, close);
8833 //this.trigger.addClassOnOver('x-form-trigger-over');
8834 //this.trigger.addClassOnClick('x-form-trigger-click');
8837 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8841 closeTriggerEl : function()
8843 var close = this.el.select('.roo-combo-removable-btn', true).first();
8844 return close ? close : false;
8847 removeBtnClick : function(e, h, el)
8851 this.fireEvent("remove", this);
8854 createList : function()
8856 this.list = Roo.get(document.body).createChild({
8858 cls: 'typeahead typeahead-long dropdown-menu',
8859 style: 'display:none'
8862 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8867 initTrigger : function(){
8872 onDestroy : function(){
8874 this.trigger.removeAllListeners();
8875 // this.trigger.remove();
8878 // this.wrap.remove();
8880 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8884 onFocus : function(){
8885 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8888 this.wrap.addClass('x-trigger-wrap-focus');
8889 this.mimicing = true;
8890 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8891 if(this.monitorTab){
8892 this.el.on("keydown", this.checkTab, this);
8899 checkTab : function(e){
8900 if(e.getKey() == e.TAB){
8906 onBlur : function(){
8911 mimicBlur : function(e, t){
8913 if(!this.wrap.contains(t) && this.validateBlur()){
8920 triggerBlur : function(){
8921 this.mimicing = false;
8922 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8923 if(this.monitorTab){
8924 this.el.un("keydown", this.checkTab, this);
8926 //this.wrap.removeClass('x-trigger-wrap-focus');
8927 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8931 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8932 validateBlur : function(e, t){
8937 onDisable : function(){
8938 this.inputEl().dom.disabled = true;
8939 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8941 // this.wrap.addClass('x-item-disabled');
8946 onEnable : function(){
8947 this.inputEl().dom.disabled = false;
8948 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8950 // this.el.removeClass('x-item-disabled');
8955 onShow : function(){
8956 var ae = this.getActionEl();
8959 ae.dom.style.display = '';
8960 ae.dom.style.visibility = 'visible';
8966 onHide : function(){
8967 var ae = this.getActionEl();
8968 ae.dom.style.display = 'none';
8972 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8973 * by an implementing function.
8975 * @param {EventObject} e
8977 onTriggerClick : Roo.emptyFn
8981 * Ext JS Library 1.1.1
8982 * Copyright(c) 2006-2007, Ext JS, LLC.
8984 * Originally Released Under LGPL - original licence link has changed is not relivant.
8987 * <script type="text/javascript">
8992 * @class Roo.data.SortTypes
8994 * Defines the default sorting (casting?) comparison functions used when sorting data.
8996 Roo.data.SortTypes = {
8998 * Default sort that does nothing
8999 * @param {Mixed} s The value being converted
9000 * @return {Mixed} The comparison value
9007 * The regular expression used to strip tags
9011 stripTagsRE : /<\/?[^>]+>/gi,
9014 * Strips all HTML tags to sort on text only
9015 * @param {Mixed} s The value being converted
9016 * @return {String} The comparison value
9018 asText : function(s){
9019 return String(s).replace(this.stripTagsRE, "");
9023 * Strips all HTML tags to sort on text only - Case insensitive
9024 * @param {Mixed} s The value being converted
9025 * @return {String} The comparison value
9027 asUCText : function(s){
9028 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9032 * Case insensitive string
9033 * @param {Mixed} s The value being converted
9034 * @return {String} The comparison value
9036 asUCString : function(s) {
9037 return String(s).toUpperCase();
9042 * @param {Mixed} s The value being converted
9043 * @return {Number} The comparison value
9045 asDate : function(s) {
9049 if(s instanceof Date){
9052 return Date.parse(String(s));
9057 * @param {Mixed} s The value being converted
9058 * @return {Float} The comparison value
9060 asFloat : function(s) {
9061 var val = parseFloat(String(s).replace(/,/g, ""));
9062 if(isNaN(val)) val = 0;
9068 * @param {Mixed} s The value being converted
9069 * @return {Number} The comparison value
9071 asInt : function(s) {
9072 var val = parseInt(String(s).replace(/,/g, ""));
9073 if(isNaN(val)) val = 0;
9078 * Ext JS Library 1.1.1
9079 * Copyright(c) 2006-2007, Ext JS, LLC.
9081 * Originally Released Under LGPL - original licence link has changed is not relivant.
9084 * <script type="text/javascript">
9088 * @class Roo.data.Record
9089 * Instances of this class encapsulate both record <em>definition</em> information, and record
9090 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9091 * to access Records cached in an {@link Roo.data.Store} object.<br>
9093 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9094 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9097 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9099 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9100 * {@link #create}. The parameters are the same.
9101 * @param {Array} data An associative Array of data values keyed by the field name.
9102 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9103 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9104 * not specified an integer id is generated.
9106 Roo.data.Record = function(data, id){
9107 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9112 * Generate a constructor for a specific record layout.
9113 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9114 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9115 * Each field definition object may contain the following properties: <ul>
9116 * <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,
9117 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9118 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9119 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9120 * is being used, then this is a string containing the javascript expression to reference the data relative to
9121 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9122 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9123 * this may be omitted.</p></li>
9124 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9125 * <ul><li>auto (Default, implies no conversion)</li>
9130 * <li>date</li></ul></p></li>
9131 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9132 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9133 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9134 * by the Reader into an object that will be stored in the Record. It is passed the
9135 * following parameters:<ul>
9136 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9138 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9140 * <br>usage:<br><pre><code>
9141 var TopicRecord = Roo.data.Record.create(
9142 {name: 'title', mapping: 'topic_title'},
9143 {name: 'author', mapping: 'username'},
9144 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9145 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9146 {name: 'lastPoster', mapping: 'user2'},
9147 {name: 'excerpt', mapping: 'post_text'}
9150 var myNewRecord = new TopicRecord({
9151 title: 'Do my job please',
9154 lastPost: new Date(),
9155 lastPoster: 'Animal',
9156 excerpt: 'No way dude!'
9158 myStore.add(myNewRecord);
9163 Roo.data.Record.create = function(o){
9165 f.superclass.constructor.apply(this, arguments);
9167 Roo.extend(f, Roo.data.Record);
9168 var p = f.prototype;
9169 p.fields = new Roo.util.MixedCollection(false, function(field){
9172 for(var i = 0, len = o.length; i < len; i++){
9173 p.fields.add(new Roo.data.Field(o[i]));
9175 f.getField = function(name){
9176 return p.fields.get(name);
9181 Roo.data.Record.AUTO_ID = 1000;
9182 Roo.data.Record.EDIT = 'edit';
9183 Roo.data.Record.REJECT = 'reject';
9184 Roo.data.Record.COMMIT = 'commit';
9186 Roo.data.Record.prototype = {
9188 * Readonly flag - true if this record has been modified.
9197 join : function(store){
9202 * Set the named field to the specified value.
9203 * @param {String} name The name of the field to set.
9204 * @param {Object} value The value to set the field to.
9206 set : function(name, value){
9207 if(this.data[name] == value){
9214 if(typeof this.modified[name] == 'undefined'){
9215 this.modified[name] = this.data[name];
9217 this.data[name] = value;
9218 if(!this.editing && this.store){
9219 this.store.afterEdit(this);
9224 * Get the value of the named field.
9225 * @param {String} name The name of the field to get the value of.
9226 * @return {Object} The value of the field.
9228 get : function(name){
9229 return this.data[name];
9233 beginEdit : function(){
9234 this.editing = true;
9239 cancelEdit : function(){
9240 this.editing = false;
9241 delete this.modified;
9245 endEdit : function(){
9246 this.editing = false;
9247 if(this.dirty && this.store){
9248 this.store.afterEdit(this);
9253 * Usually called by the {@link Roo.data.Store} which owns the Record.
9254 * Rejects all changes made to the Record since either creation, or the last commit operation.
9255 * Modified fields are reverted to their original values.
9257 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9258 * of reject operations.
9260 reject : function(){
9261 var m = this.modified;
9263 if(typeof m[n] != "function"){
9264 this.data[n] = m[n];
9268 delete this.modified;
9269 this.editing = false;
9271 this.store.afterReject(this);
9276 * Usually called by the {@link Roo.data.Store} which owns the Record.
9277 * Commits all changes made to the Record since either creation, or the last commit operation.
9279 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9280 * of commit operations.
9282 commit : function(){
9284 delete this.modified;
9285 this.editing = false;
9287 this.store.afterCommit(this);
9292 hasError : function(){
9293 return this.error != null;
9297 clearError : function(){
9302 * Creates a copy of this record.
9303 * @param {String} id (optional) A new record id if you don't want to use this record's id
9306 copy : function(newId) {
9307 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9311 * Ext JS Library 1.1.1
9312 * Copyright(c) 2006-2007, Ext JS, LLC.
9314 * Originally Released Under LGPL - original licence link has changed is not relivant.
9317 * <script type="text/javascript">
9323 * @class Roo.data.Store
9324 * @extends Roo.util.Observable
9325 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9326 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9328 * 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
9329 * has no knowledge of the format of the data returned by the Proxy.<br>
9331 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9332 * instances from the data object. These records are cached and made available through accessor functions.
9334 * Creates a new Store.
9335 * @param {Object} config A config object containing the objects needed for the Store to access data,
9336 * and read the data into Records.
9338 Roo.data.Store = function(config){
9339 this.data = new Roo.util.MixedCollection(false);
9340 this.data.getKey = function(o){
9343 this.baseParams = {};
9350 "multisort" : "_multisort"
9353 if(config && config.data){
9354 this.inlineData = config.data;
9358 Roo.apply(this, config);
9360 if(this.reader){ // reader passed
9361 this.reader = Roo.factory(this.reader, Roo.data);
9362 this.reader.xmodule = this.xmodule || false;
9363 if(!this.recordType){
9364 this.recordType = this.reader.recordType;
9366 if(this.reader.onMetaChange){
9367 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9371 if(this.recordType){
9372 this.fields = this.recordType.prototype.fields;
9378 * @event datachanged
9379 * Fires when the data cache has changed, and a widget which is using this Store
9380 * as a Record cache should refresh its view.
9381 * @param {Store} this
9386 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9387 * @param {Store} this
9388 * @param {Object} meta The JSON metadata
9393 * Fires when Records have been added to the Store
9394 * @param {Store} this
9395 * @param {Roo.data.Record[]} records The array of Records added
9396 * @param {Number} index The index at which the record(s) were added
9401 * Fires when a Record has been removed from the Store
9402 * @param {Store} this
9403 * @param {Roo.data.Record} record The Record that was removed
9404 * @param {Number} index The index at which the record was removed
9409 * Fires when a Record has been updated
9410 * @param {Store} this
9411 * @param {Roo.data.Record} record The Record that was updated
9412 * @param {String} operation The update operation being performed. Value may be one of:
9414 Roo.data.Record.EDIT
9415 Roo.data.Record.REJECT
9416 Roo.data.Record.COMMIT
9422 * Fires when the data cache has been cleared.
9423 * @param {Store} this
9428 * Fires before a request is made for a new data object. If the beforeload handler returns false
9429 * the load action will be canceled.
9430 * @param {Store} this
9431 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9435 * @event beforeloadadd
9436 * Fires after a new set of Records has been loaded.
9437 * @param {Store} this
9438 * @param {Roo.data.Record[]} records The Records that were loaded
9439 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9441 beforeloadadd : true,
9444 * Fires after a new set of Records has been loaded, before they are added to the store.
9445 * @param {Store} this
9446 * @param {Roo.data.Record[]} records The Records that were loaded
9447 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9448 * @params {Object} return from reader
9452 * @event loadexception
9453 * Fires if an exception occurs in the Proxy during loading.
9454 * Called with the signature of the Proxy's "loadexception" event.
9455 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9458 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9459 * @param {Object} load options
9460 * @param {Object} jsonData from your request (normally this contains the Exception)
9462 loadexception : true
9466 this.proxy = Roo.factory(this.proxy, Roo.data);
9467 this.proxy.xmodule = this.xmodule || false;
9468 this.relayEvents(this.proxy, ["loadexception"]);
9470 this.sortToggle = {};
9471 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9473 Roo.data.Store.superclass.constructor.call(this);
9475 if(this.inlineData){
9476 this.loadData(this.inlineData);
9477 delete this.inlineData;
9481 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9483 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9484 * without a remote query - used by combo/forms at present.
9488 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9491 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9494 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9495 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9498 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9499 * on any HTTP request
9502 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9505 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9509 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9510 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9515 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9516 * loaded or when a record is removed. (defaults to false).
9518 pruneModifiedRecords : false,
9524 * Add Records to the Store and fires the add event.
9525 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9527 add : function(records){
9528 records = [].concat(records);
9529 for(var i = 0, len = records.length; i < len; i++){
9530 records[i].join(this);
9532 var index = this.data.length;
9533 this.data.addAll(records);
9534 this.fireEvent("add", this, records, index);
9538 * Remove a Record from the Store and fires the remove event.
9539 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9541 remove : function(record){
9542 var index = this.data.indexOf(record);
9543 this.data.removeAt(index);
9544 if(this.pruneModifiedRecords){
9545 this.modified.remove(record);
9547 this.fireEvent("remove", this, record, index);
9551 * Remove all Records from the Store and fires the clear event.
9553 removeAll : function(){
9555 if(this.pruneModifiedRecords){
9558 this.fireEvent("clear", this);
9562 * Inserts Records to the Store at the given index and fires the add event.
9563 * @param {Number} index The start index at which to insert the passed Records.
9564 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9566 insert : function(index, records){
9567 records = [].concat(records);
9568 for(var i = 0, len = records.length; i < len; i++){
9569 this.data.insert(index, records[i]);
9570 records[i].join(this);
9572 this.fireEvent("add", this, records, index);
9576 * Get the index within the cache of the passed Record.
9577 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9578 * @return {Number} The index of the passed Record. Returns -1 if not found.
9580 indexOf : function(record){
9581 return this.data.indexOf(record);
9585 * Get the index within the cache of the Record with the passed id.
9586 * @param {String} id The id of the Record to find.
9587 * @return {Number} The index of the Record. Returns -1 if not found.
9589 indexOfId : function(id){
9590 return this.data.indexOfKey(id);
9594 * Get the Record with the specified id.
9595 * @param {String} id The id of the Record to find.
9596 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9598 getById : function(id){
9599 return this.data.key(id);
9603 * Get the Record at the specified index.
9604 * @param {Number} index The index of the Record to find.
9605 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9607 getAt : function(index){
9608 return this.data.itemAt(index);
9612 * Returns a range of Records between specified indices.
9613 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9614 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9615 * @return {Roo.data.Record[]} An array of Records
9617 getRange : function(start, end){
9618 return this.data.getRange(start, end);
9622 storeOptions : function(o){
9623 o = Roo.apply({}, o);
9626 this.lastOptions = o;
9630 * Loads the Record cache from the configured Proxy using the configured Reader.
9632 * If using remote paging, then the first load call must specify the <em>start</em>
9633 * and <em>limit</em> properties in the options.params property to establish the initial
9634 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9636 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9637 * and this call will return before the new data has been loaded. Perform any post-processing
9638 * in a callback function, or in a "load" event handler.</strong>
9640 * @param {Object} options An object containing properties which control loading options:<ul>
9641 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9642 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9643 * passed the following arguments:<ul>
9644 * <li>r : Roo.data.Record[]</li>
9645 * <li>options: Options object from the load call</li>
9646 * <li>success: Boolean success indicator</li></ul></li>
9647 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9648 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9651 load : function(options){
9652 options = options || {};
9653 if(this.fireEvent("beforeload", this, options) !== false){
9654 this.storeOptions(options);
9655 var p = Roo.apply(options.params || {}, this.baseParams);
9656 // if meta was not loaded from remote source.. try requesting it.
9657 if (!this.reader.metaFromRemote) {
9660 if(this.sortInfo && this.remoteSort){
9661 var pn = this.paramNames;
9662 p[pn["sort"]] = this.sortInfo.field;
9663 p[pn["dir"]] = this.sortInfo.direction;
9665 if (this.multiSort) {
9666 var pn = this.paramNames;
9667 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9670 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9675 * Reloads the Record cache from the configured Proxy using the configured Reader and
9676 * the options from the last load operation performed.
9677 * @param {Object} options (optional) An object containing properties which may override the options
9678 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9679 * the most recently used options are reused).
9681 reload : function(options){
9682 this.load(Roo.applyIf(options||{}, this.lastOptions));
9686 // Called as a callback by the Reader during a load operation.
9687 loadRecords : function(o, options, success){
9688 if(!o || success === false){
9689 if(success !== false){
9690 this.fireEvent("load", this, [], options, o);
9692 if(options.callback){
9693 options.callback.call(options.scope || this, [], options, false);
9697 // if data returned failure - throw an exception.
9698 if (o.success === false) {
9699 // show a message if no listener is registered.
9700 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9701 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9703 // loadmask wil be hooked into this..
9704 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9707 var r = o.records, t = o.totalRecords || r.length;
9709 this.fireEvent("beforeloadadd", this, r, options, o);
9711 if(!options || options.add !== true){
9712 if(this.pruneModifiedRecords){
9715 for(var i = 0, len = r.length; i < len; i++){
9719 this.data = this.snapshot;
9720 delete this.snapshot;
9723 this.data.addAll(r);
9724 this.totalLength = t;
9726 this.fireEvent("datachanged", this);
9728 this.totalLength = Math.max(t, this.data.length+r.length);
9731 this.fireEvent("load", this, r, options, o);
9732 if(options.callback){
9733 options.callback.call(options.scope || this, r, options, true);
9739 * Loads data from a passed data block. A Reader which understands the format of the data
9740 * must have been configured in the constructor.
9741 * @param {Object} data The data block from which to read the Records. The format of the data expected
9742 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9743 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9745 loadData : function(o, append){
9746 var r = this.reader.readRecords(o);
9747 this.loadRecords(r, {add: append}, true);
9751 * Gets the number of cached records.
9753 * <em>If using paging, this may not be the total size of the dataset. If the data object
9754 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9755 * the data set size</em>
9757 getCount : function(){
9758 return this.data.length || 0;
9762 * Gets the total number of records in the dataset as returned by the server.
9764 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9765 * the dataset size</em>
9767 getTotalCount : function(){
9768 return this.totalLength || 0;
9772 * Returns the sort state of the Store as an object with two properties:
9774 field {String} The name of the field by which the Records are sorted
9775 direction {String} The sort order, "ASC" or "DESC"
9778 getSortState : function(){
9779 return this.sortInfo;
9783 applySort : function(){
9784 if(this.sortInfo && !this.remoteSort){
9785 var s = this.sortInfo, f = s.field;
9786 var st = this.fields.get(f).sortType;
9787 var fn = function(r1, r2){
9788 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9789 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9791 this.data.sort(s.direction, fn);
9792 if(this.snapshot && this.snapshot != this.data){
9793 this.snapshot.sort(s.direction, fn);
9799 * Sets the default sort column and order to be used by the next load operation.
9800 * @param {String} fieldName The name of the field to sort by.
9801 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9803 setDefaultSort : function(field, dir){
9804 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9809 * If remote sorting is used, the sort is performed on the server, and the cache is
9810 * reloaded. If local sorting is used, the cache is sorted internally.
9811 * @param {String} fieldName The name of the field to sort by.
9812 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9814 sort : function(fieldName, dir){
9815 var f = this.fields.get(fieldName);
9817 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9819 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9820 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9825 this.sortToggle[f.name] = dir;
9826 this.sortInfo = {field: f.name, direction: dir};
9827 if(!this.remoteSort){
9829 this.fireEvent("datachanged", this);
9831 this.load(this.lastOptions);
9836 * Calls the specified function for each of the Records in the cache.
9837 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9838 * Returning <em>false</em> aborts and exits the iteration.
9839 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9841 each : function(fn, scope){
9842 this.data.each(fn, scope);
9846 * Gets all records modified since the last commit. Modified records are persisted across load operations
9847 * (e.g., during paging).
9848 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9850 getModifiedRecords : function(){
9851 return this.modified;
9855 createFilterFn : function(property, value, anyMatch){
9856 if(!value.exec){ // not a regex
9857 value = String(value);
9858 if(value.length == 0){
9861 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9864 return value.test(r.data[property]);
9869 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9870 * @param {String} property A field on your records
9871 * @param {Number} start The record index to start at (defaults to 0)
9872 * @param {Number} end The last record index to include (defaults to length - 1)
9873 * @return {Number} The sum
9875 sum : function(property, start, end){
9876 var rs = this.data.items, v = 0;
9878 end = (end || end === 0) ? end : rs.length-1;
9880 for(var i = start; i <= end; i++){
9881 v += (rs[i].data[property] || 0);
9887 * Filter the records by a specified property.
9888 * @param {String} field A field on your records
9889 * @param {String/RegExp} value Either a string that the field
9890 * should start with or a RegExp to test against the field
9891 * @param {Boolean} anyMatch True to match any part not just the beginning
9893 filter : function(property, value, anyMatch){
9894 var fn = this.createFilterFn(property, value, anyMatch);
9895 return fn ? this.filterBy(fn) : this.clearFilter();
9899 * Filter by a function. The specified function will be called with each
9900 * record in this data source. If the function returns true the record is included,
9901 * otherwise it is filtered.
9902 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9903 * @param {Object} scope (optional) The scope of the function (defaults to this)
9905 filterBy : function(fn, scope){
9906 this.snapshot = this.snapshot || this.data;
9907 this.data = this.queryBy(fn, scope||this);
9908 this.fireEvent("datachanged", this);
9912 * Query the records by a specified property.
9913 * @param {String} field A field on your records
9914 * @param {String/RegExp} value Either a string that the field
9915 * should start with or a RegExp to test against the field
9916 * @param {Boolean} anyMatch True to match any part not just the beginning
9917 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9919 query : function(property, value, anyMatch){
9920 var fn = this.createFilterFn(property, value, anyMatch);
9921 return fn ? this.queryBy(fn) : this.data.clone();
9925 * Query by a function. The specified function will be called with each
9926 * record in this data source. If the function returns true the record is included
9928 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9929 * @param {Object} scope (optional) The scope of the function (defaults to this)
9930 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9932 queryBy : function(fn, scope){
9933 var data = this.snapshot || this.data;
9934 return data.filterBy(fn, scope||this);
9938 * Collects unique values for a particular dataIndex from this store.
9939 * @param {String} dataIndex The property to collect
9940 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9941 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9942 * @return {Array} An array of the unique values
9944 collect : function(dataIndex, allowNull, bypassFilter){
9945 var d = (bypassFilter === true && this.snapshot) ?
9946 this.snapshot.items : this.data.items;
9947 var v, sv, r = [], l = {};
9948 for(var i = 0, len = d.length; i < len; i++){
9949 v = d[i].data[dataIndex];
9951 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9960 * Revert to a view of the Record cache with no filtering applied.
9961 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9963 clearFilter : function(suppressEvent){
9964 if(this.snapshot && this.snapshot != this.data){
9965 this.data = this.snapshot;
9966 delete this.snapshot;
9967 if(suppressEvent !== true){
9968 this.fireEvent("datachanged", this);
9974 afterEdit : function(record){
9975 if(this.modified.indexOf(record) == -1){
9976 this.modified.push(record);
9978 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9982 afterReject : function(record){
9983 this.modified.remove(record);
9984 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9988 afterCommit : function(record){
9989 this.modified.remove(record);
9990 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9994 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9995 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9997 commitChanges : function(){
9998 var m = this.modified.slice(0);
10000 for(var i = 0, len = m.length; i < len; i++){
10006 * Cancel outstanding changes on all changed records.
10008 rejectChanges : function(){
10009 var m = this.modified.slice(0);
10010 this.modified = [];
10011 for(var i = 0, len = m.length; i < len; i++){
10016 onMetaChange : function(meta, rtype, o){
10017 this.recordType = rtype;
10018 this.fields = rtype.prototype.fields;
10019 delete this.snapshot;
10020 this.sortInfo = meta.sortInfo || this.sortInfo;
10021 this.modified = [];
10022 this.fireEvent('metachange', this, this.reader.meta);
10025 moveIndex : function(data, type)
10027 var index = this.indexOf(data);
10029 var newIndex = index + type;
10033 this.insert(newIndex, data);
10038 * Ext JS Library 1.1.1
10039 * Copyright(c) 2006-2007, Ext JS, LLC.
10041 * Originally Released Under LGPL - original licence link has changed is not relivant.
10044 * <script type="text/javascript">
10048 * @class Roo.data.SimpleStore
10049 * @extends Roo.data.Store
10050 * Small helper class to make creating Stores from Array data easier.
10051 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10052 * @cfg {Array} fields An array of field definition objects, or field name strings.
10053 * @cfg {Array} data The multi-dimensional array of data
10055 * @param {Object} config
10057 Roo.data.SimpleStore = function(config){
10058 Roo.data.SimpleStore.superclass.constructor.call(this, {
10060 reader: new Roo.data.ArrayReader({
10063 Roo.data.Record.create(config.fields)
10065 proxy : new Roo.data.MemoryProxy(config.data)
10069 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10071 * Ext JS Library 1.1.1
10072 * Copyright(c) 2006-2007, Ext JS, LLC.
10074 * Originally Released Under LGPL - original licence link has changed is not relivant.
10077 * <script type="text/javascript">
10082 * @extends Roo.data.Store
10083 * @class Roo.data.JsonStore
10084 * Small helper class to make creating Stores for JSON data easier. <br/>
10086 var store = new Roo.data.JsonStore({
10087 url: 'get-images.php',
10089 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10092 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10093 * JsonReader and HttpProxy (unless inline data is provided).</b>
10094 * @cfg {Array} fields An array of field definition objects, or field name strings.
10096 * @param {Object} config
10098 Roo.data.JsonStore = function(c){
10099 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10100 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10101 reader: new Roo.data.JsonReader(c, c.fields)
10104 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10106 * Ext JS Library 1.1.1
10107 * Copyright(c) 2006-2007, Ext JS, LLC.
10109 * Originally Released Under LGPL - original licence link has changed is not relivant.
10112 * <script type="text/javascript">
10116 Roo.data.Field = function(config){
10117 if(typeof config == "string"){
10118 config = {name: config};
10120 Roo.apply(this, config);
10123 this.type = "auto";
10126 var st = Roo.data.SortTypes;
10127 // named sortTypes are supported, here we look them up
10128 if(typeof this.sortType == "string"){
10129 this.sortType = st[this.sortType];
10132 // set default sortType for strings and dates
10133 if(!this.sortType){
10136 this.sortType = st.asUCString;
10139 this.sortType = st.asDate;
10142 this.sortType = st.none;
10147 var stripRe = /[\$,%]/g;
10149 // prebuilt conversion function for this field, instead of
10150 // switching every time we're reading a value
10152 var cv, dateFormat = this.dateFormat;
10157 cv = function(v){ return v; };
10160 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10164 return v !== undefined && v !== null && v !== '' ?
10165 parseInt(String(v).replace(stripRe, ""), 10) : '';
10170 return v !== undefined && v !== null && v !== '' ?
10171 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10176 cv = function(v){ return v === true || v === "true" || v == 1; };
10183 if(v instanceof Date){
10187 if(dateFormat == "timestamp"){
10188 return new Date(v*1000);
10190 return Date.parseDate(v, dateFormat);
10192 var parsed = Date.parse(v);
10193 return parsed ? new Date(parsed) : null;
10202 Roo.data.Field.prototype = {
10210 * Ext JS Library 1.1.1
10211 * Copyright(c) 2006-2007, Ext JS, LLC.
10213 * Originally Released Under LGPL - original licence link has changed is not relivant.
10216 * <script type="text/javascript">
10219 // Base class for reading structured data from a data source. This class is intended to be
10220 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10223 * @class Roo.data.DataReader
10224 * Base class for reading structured data from a data source. This class is intended to be
10225 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10228 Roo.data.DataReader = function(meta, recordType){
10232 this.recordType = recordType instanceof Array ?
10233 Roo.data.Record.create(recordType) : recordType;
10236 Roo.data.DataReader.prototype = {
10238 * Create an empty record
10239 * @param {Object} data (optional) - overlay some values
10240 * @return {Roo.data.Record} record created.
10242 newRow : function(d) {
10244 this.recordType.prototype.fields.each(function(c) {
10246 case 'int' : da[c.name] = 0; break;
10247 case 'date' : da[c.name] = new Date(); break;
10248 case 'float' : da[c.name] = 0.0; break;
10249 case 'boolean' : da[c.name] = false; break;
10250 default : da[c.name] = ""; break;
10254 return new this.recordType(Roo.apply(da, d));
10259 * Ext JS Library 1.1.1
10260 * Copyright(c) 2006-2007, Ext JS, LLC.
10262 * Originally Released Under LGPL - original licence link has changed is not relivant.
10265 * <script type="text/javascript">
10269 * @class Roo.data.DataProxy
10270 * @extends Roo.data.Observable
10271 * This class is an abstract base class for implementations which provide retrieval of
10272 * unformatted data objects.<br>
10274 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10275 * (of the appropriate type which knows how to parse the data object) to provide a block of
10276 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10278 * Custom implementations must implement the load method as described in
10279 * {@link Roo.data.HttpProxy#load}.
10281 Roo.data.DataProxy = function(){
10284 * @event beforeload
10285 * Fires before a network request is made to retrieve a data object.
10286 * @param {Object} This DataProxy object.
10287 * @param {Object} params The params parameter to the load function.
10292 * Fires before the load method's callback is called.
10293 * @param {Object} This DataProxy object.
10294 * @param {Object} o The data object.
10295 * @param {Object} arg The callback argument object passed to the load function.
10299 * @event loadexception
10300 * Fires if an Exception occurs during data retrieval.
10301 * @param {Object} This DataProxy object.
10302 * @param {Object} o The data object.
10303 * @param {Object} arg The callback argument object passed to the load function.
10304 * @param {Object} e The Exception.
10306 loadexception : true
10308 Roo.data.DataProxy.superclass.constructor.call(this);
10311 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10314 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10318 * Ext JS Library 1.1.1
10319 * Copyright(c) 2006-2007, Ext JS, LLC.
10321 * Originally Released Under LGPL - original licence link has changed is not relivant.
10324 * <script type="text/javascript">
10327 * @class Roo.data.MemoryProxy
10328 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10329 * to the Reader when its load method is called.
10331 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10333 Roo.data.MemoryProxy = function(data){
10337 Roo.data.MemoryProxy.superclass.constructor.call(this);
10341 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10343 * Load data from the requested source (in this case an in-memory
10344 * data object passed to the constructor), read the data object into
10345 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10346 * process that block using the passed callback.
10347 * @param {Object} params This parameter is not used by the MemoryProxy class.
10348 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10349 * object into a block of Roo.data.Records.
10350 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10351 * The function must be passed <ul>
10352 * <li>The Record block object</li>
10353 * <li>The "arg" argument from the load function</li>
10354 * <li>A boolean success indicator</li>
10356 * @param {Object} scope The scope in which to call the callback
10357 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10359 load : function(params, reader, callback, scope, arg){
10360 params = params || {};
10363 result = reader.readRecords(this.data);
10365 this.fireEvent("loadexception", this, arg, null, e);
10366 callback.call(scope, null, arg, false);
10369 callback.call(scope, result, arg, true);
10373 update : function(params, records){
10378 * Ext JS Library 1.1.1
10379 * Copyright(c) 2006-2007, Ext JS, LLC.
10381 * Originally Released Under LGPL - original licence link has changed is not relivant.
10384 * <script type="text/javascript">
10387 * @class Roo.data.HttpProxy
10388 * @extends Roo.data.DataProxy
10389 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10390 * configured to reference a certain URL.<br><br>
10392 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10393 * from which the running page was served.<br><br>
10395 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10397 * Be aware that to enable the browser to parse an XML document, the server must set
10398 * the Content-Type header in the HTTP response to "text/xml".
10400 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10401 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10402 * will be used to make the request.
10404 Roo.data.HttpProxy = function(conn){
10405 Roo.data.HttpProxy.superclass.constructor.call(this);
10406 // is conn a conn config or a real conn?
10408 this.useAjax = !conn || !conn.events;
10412 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10413 // thse are take from connection...
10416 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10419 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10420 * extra parameters to each request made by this object. (defaults to undefined)
10423 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10424 * to each request made by this object. (defaults to undefined)
10427 * @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)
10430 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10433 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10439 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10443 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10444 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10445 * a finer-grained basis than the DataProxy events.
10447 getConnection : function(){
10448 return this.useAjax ? Roo.Ajax : this.conn;
10452 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10453 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10454 * process that block using the passed callback.
10455 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10456 * for the request to the remote server.
10457 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10458 * object into a block of Roo.data.Records.
10459 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10460 * The function must be passed <ul>
10461 * <li>The Record block object</li>
10462 * <li>The "arg" argument from the load function</li>
10463 * <li>A boolean success indicator</li>
10465 * @param {Object} scope The scope in which to call the callback
10466 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10468 load : function(params, reader, callback, scope, arg){
10469 if(this.fireEvent("beforeload", this, params) !== false){
10471 params : params || {},
10473 callback : callback,
10478 callback : this.loadResponse,
10482 Roo.applyIf(o, this.conn);
10483 if(this.activeRequest){
10484 Roo.Ajax.abort(this.activeRequest);
10486 this.activeRequest = Roo.Ajax.request(o);
10488 this.conn.request(o);
10491 callback.call(scope||this, null, arg, false);
10496 loadResponse : function(o, success, response){
10497 delete this.activeRequest;
10499 this.fireEvent("loadexception", this, o, response);
10500 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10505 result = o.reader.read(response);
10507 this.fireEvent("loadexception", this, o, response, e);
10508 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10512 this.fireEvent("load", this, o, o.request.arg);
10513 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10517 update : function(dataSet){
10522 updateResponse : function(dataSet){
10527 * Ext JS Library 1.1.1
10528 * Copyright(c) 2006-2007, Ext JS, LLC.
10530 * Originally Released Under LGPL - original licence link has changed is not relivant.
10533 * <script type="text/javascript">
10537 * @class Roo.data.ScriptTagProxy
10538 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10539 * other than the originating domain of the running page.<br><br>
10541 * <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
10542 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10544 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10545 * source code that is used as the source inside a <script> tag.<br><br>
10547 * In order for the browser to process the returned data, the server must wrap the data object
10548 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10549 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10550 * depending on whether the callback name was passed:
10553 boolean scriptTag = false;
10554 String cb = request.getParameter("callback");
10557 response.setContentType("text/javascript");
10559 response.setContentType("application/x-json");
10561 Writer out = response.getWriter();
10563 out.write(cb + "(");
10565 out.print(dataBlock.toJsonString());
10572 * @param {Object} config A configuration object.
10574 Roo.data.ScriptTagProxy = function(config){
10575 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10576 Roo.apply(this, config);
10577 this.head = document.getElementsByTagName("head")[0];
10580 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10582 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10584 * @cfg {String} url The URL from which to request the data object.
10587 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10591 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10592 * the server the name of the callback function set up by the load call to process the returned data object.
10593 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10594 * javascript output which calls this named function passing the data object as its only parameter.
10596 callbackParam : "callback",
10598 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10599 * name to the request.
10604 * Load data from the configured URL, read the data object into
10605 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10606 * process that block using the passed callback.
10607 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10608 * for the request to the remote server.
10609 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10610 * object into a block of Roo.data.Records.
10611 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10612 * The function must be passed <ul>
10613 * <li>The Record block object</li>
10614 * <li>The "arg" argument from the load function</li>
10615 * <li>A boolean success indicator</li>
10617 * @param {Object} scope The scope in which to call the callback
10618 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10620 load : function(params, reader, callback, scope, arg){
10621 if(this.fireEvent("beforeload", this, params) !== false){
10623 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10625 var url = this.url;
10626 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10628 url += "&_dc=" + (new Date().getTime());
10630 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10633 cb : "stcCallback"+transId,
10634 scriptId : "stcScript"+transId,
10638 callback : callback,
10644 window[trans.cb] = function(o){
10645 conn.handleResponse(o, trans);
10648 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10650 if(this.autoAbort !== false){
10654 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10656 var script = document.createElement("script");
10657 script.setAttribute("src", url);
10658 script.setAttribute("type", "text/javascript");
10659 script.setAttribute("id", trans.scriptId);
10660 this.head.appendChild(script);
10662 this.trans = trans;
10664 callback.call(scope||this, null, arg, false);
10669 isLoading : function(){
10670 return this.trans ? true : false;
10674 * Abort the current server request.
10676 abort : function(){
10677 if(this.isLoading()){
10678 this.destroyTrans(this.trans);
10683 destroyTrans : function(trans, isLoaded){
10684 this.head.removeChild(document.getElementById(trans.scriptId));
10685 clearTimeout(trans.timeoutId);
10687 window[trans.cb] = undefined;
10689 delete window[trans.cb];
10692 // if hasn't been loaded, wait for load to remove it to prevent script error
10693 window[trans.cb] = function(){
10694 window[trans.cb] = undefined;
10696 delete window[trans.cb];
10703 handleResponse : function(o, trans){
10704 this.trans = false;
10705 this.destroyTrans(trans, true);
10708 result = trans.reader.readRecords(o);
10710 this.fireEvent("loadexception", this, o, trans.arg, e);
10711 trans.callback.call(trans.scope||window, null, trans.arg, false);
10714 this.fireEvent("load", this, o, trans.arg);
10715 trans.callback.call(trans.scope||window, result, trans.arg, true);
10719 handleFailure : function(trans){
10720 this.trans = false;
10721 this.destroyTrans(trans, false);
10722 this.fireEvent("loadexception", this, null, trans.arg);
10723 trans.callback.call(trans.scope||window, null, trans.arg, false);
10727 * Ext JS Library 1.1.1
10728 * Copyright(c) 2006-2007, Ext JS, LLC.
10730 * Originally Released Under LGPL - original licence link has changed is not relivant.
10733 * <script type="text/javascript">
10737 * @class Roo.data.JsonReader
10738 * @extends Roo.data.DataReader
10739 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10740 * based on mappings in a provided Roo.data.Record constructor.
10742 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10743 * in the reply previously.
10748 var RecordDef = Roo.data.Record.create([
10749 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10750 {name: 'occupation'} // This field will use "occupation" as the mapping.
10752 var myReader = new Roo.data.JsonReader({
10753 totalProperty: "results", // The property which contains the total dataset size (optional)
10754 root: "rows", // The property which contains an Array of row objects
10755 id: "id" // The property within each row object that provides an ID for the record (optional)
10759 * This would consume a JSON file like this:
10761 { 'results': 2, 'rows': [
10762 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10763 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10766 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10767 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10768 * paged from the remote server.
10769 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10770 * @cfg {String} root name of the property which contains the Array of row objects.
10771 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10772 * @cfg {Array} fields Array of field definition objects
10774 * Create a new JsonReader
10775 * @param {Object} meta Metadata configuration options
10776 * @param {Object} recordType Either an Array of field definition objects,
10777 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10779 Roo.data.JsonReader = function(meta, recordType){
10782 // set some defaults:
10783 Roo.applyIf(meta, {
10784 totalProperty: 'total',
10785 successProperty : 'success',
10790 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10792 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10795 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10796 * Used by Store query builder to append _requestMeta to params.
10799 metaFromRemote : false,
10801 * This method is only used by a DataProxy which has retrieved data from a remote server.
10802 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10803 * @return {Object} data A data block which is used by an Roo.data.Store object as
10804 * a cache of Roo.data.Records.
10806 read : function(response){
10807 var json = response.responseText;
10809 var o = /* eval:var:o */ eval("("+json+")");
10811 throw {message: "JsonReader.read: Json object not found"};
10817 this.metaFromRemote = true;
10818 this.meta = o.metaData;
10819 this.recordType = Roo.data.Record.create(o.metaData.fields);
10820 this.onMetaChange(this.meta, this.recordType, o);
10822 return this.readRecords(o);
10825 // private function a store will implement
10826 onMetaChange : function(meta, recordType, o){
10833 simpleAccess: function(obj, subsc) {
10840 getJsonAccessor: function(){
10842 return function(expr) {
10844 return(re.test(expr))
10845 ? new Function("obj", "return obj." + expr)
10850 return Roo.emptyFn;
10855 * Create a data block containing Roo.data.Records from an XML document.
10856 * @param {Object} o An object which contains an Array of row objects in the property specified
10857 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10858 * which contains the total size of the dataset.
10859 * @return {Object} data A data block which is used by an Roo.data.Store object as
10860 * a cache of Roo.data.Records.
10862 readRecords : function(o){
10864 * After any data loads, the raw JSON data is available for further custom processing.
10868 var s = this.meta, Record = this.recordType,
10869 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10871 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10873 if(s.totalProperty) {
10874 this.getTotal = this.getJsonAccessor(s.totalProperty);
10876 if(s.successProperty) {
10877 this.getSuccess = this.getJsonAccessor(s.successProperty);
10879 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10881 var g = this.getJsonAccessor(s.id);
10882 this.getId = function(rec) {
10884 return (r === undefined || r === "") ? null : r;
10887 this.getId = function(){return null;};
10890 for(var jj = 0; jj < fl; jj++){
10892 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10893 this.ef[jj] = this.getJsonAccessor(map);
10897 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10898 if(s.totalProperty){
10899 var vt = parseInt(this.getTotal(o), 10);
10904 if(s.successProperty){
10905 var vs = this.getSuccess(o);
10906 if(vs === false || vs === 'false'){
10911 for(var i = 0; i < c; i++){
10914 var id = this.getId(n);
10915 for(var j = 0; j < fl; j++){
10917 var v = this.ef[j](n);
10919 Roo.log('missing convert for ' + f.name);
10923 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10925 var record = new Record(values, id);
10927 records[i] = record;
10933 totalRecords : totalRecords
10938 * Ext JS Library 1.1.1
10939 * Copyright(c) 2006-2007, Ext JS, LLC.
10941 * Originally Released Under LGPL - original licence link has changed is not relivant.
10944 * <script type="text/javascript">
10948 * @class Roo.data.ArrayReader
10949 * @extends Roo.data.DataReader
10950 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10951 * Each element of that Array represents a row of data fields. The
10952 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10953 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10957 var RecordDef = Roo.data.Record.create([
10958 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10959 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10961 var myReader = new Roo.data.ArrayReader({
10962 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10966 * This would consume an Array like this:
10968 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10970 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10972 * Create a new JsonReader
10973 * @param {Object} meta Metadata configuration options.
10974 * @param {Object} recordType Either an Array of field definition objects
10975 * as specified to {@link Roo.data.Record#create},
10976 * or an {@link Roo.data.Record} object
10977 * created using {@link Roo.data.Record#create}.
10979 Roo.data.ArrayReader = function(meta, recordType){
10980 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10983 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10985 * Create a data block containing Roo.data.Records from an XML document.
10986 * @param {Object} o An Array of row objects which represents the dataset.
10987 * @return {Object} data A data block which is used by an Roo.data.Store object as
10988 * a cache of Roo.data.Records.
10990 readRecords : function(o){
10991 var sid = this.meta ? this.meta.id : null;
10992 var recordType = this.recordType, fields = recordType.prototype.fields;
10995 for(var i = 0; i < root.length; i++){
10998 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10999 for(var j = 0, jlen = fields.length; j < jlen; j++){
11000 var f = fields.items[j];
11001 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11002 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11004 values[f.name] = v;
11006 var record = new recordType(values, id);
11008 records[records.length] = record;
11012 totalRecords : records.length
11021 * @class Roo.bootstrap.ComboBox
11022 * @extends Roo.bootstrap.TriggerField
11023 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11024 * @cfg {Boolean} append (true|false) default false
11025 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11026 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11027 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11028 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11029 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11031 * Create a new ComboBox.
11032 * @param {Object} config Configuration options
11034 Roo.bootstrap.ComboBox = function(config){
11035 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11039 * Fires when the dropdown list is expanded
11040 * @param {Roo.bootstrap.ComboBox} combo This combo box
11045 * Fires when the dropdown list is collapsed
11046 * @param {Roo.bootstrap.ComboBox} combo This combo box
11050 * @event beforeselect
11051 * Fires before a list item is selected. Return false to cancel the selection.
11052 * @param {Roo.bootstrap.ComboBox} combo This combo box
11053 * @param {Roo.data.Record} record The data record returned from the underlying store
11054 * @param {Number} index The index of the selected item in the dropdown list
11056 'beforeselect' : true,
11059 * Fires when a list item is selected
11060 * @param {Roo.bootstrap.ComboBox} combo This combo box
11061 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11062 * @param {Number} index The index of the selected item in the dropdown list
11066 * @event beforequery
11067 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11068 * The event object passed has these properties:
11069 * @param {Roo.bootstrap.ComboBox} combo This combo box
11070 * @param {String} query The query
11071 * @param {Boolean} forceAll true to force "all" query
11072 * @param {Boolean} cancel true to cancel the query
11073 * @param {Object} e The query event object
11075 'beforequery': true,
11078 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11079 * @param {Roo.bootstrap.ComboBox} combo This combo box
11084 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11085 * @param {Roo.bootstrap.ComboBox} combo This combo box
11086 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11091 * Fires when the remove value from the combobox array
11092 * @param {Roo.bootstrap.ComboBox} combo This combo box
11096 * @event specialfilter
11097 * Fires when specialfilter
11098 * @param {Roo.bootstrap.ComboBox} combo This combo box
11100 'specialfilter' : true
11105 this.tickItems = [];
11107 this.selectedIndex = -1;
11108 if(this.mode == 'local'){
11109 if(config.queryDelay === undefined){
11110 this.queryDelay = 10;
11112 if(config.minChars === undefined){
11118 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11121 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11122 * rendering into an Roo.Editor, defaults to false)
11125 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11126 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11129 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11132 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11133 * the dropdown list (defaults to undefined, with no header element)
11137 * @cfg {String/Roo.Template} tpl The template to use to render the output
11141 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11143 listWidth: undefined,
11145 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11146 * mode = 'remote' or 'text' if mode = 'local')
11148 displayField: undefined,
11151 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11152 * mode = 'remote' or 'value' if mode = 'local').
11153 * Note: use of a valueField requires the user make a selection
11154 * in order for a value to be mapped.
11156 valueField: undefined,
11160 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11161 * field's data value (defaults to the underlying DOM element's name)
11163 hiddenName: undefined,
11165 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11169 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11171 selectedClass: 'active',
11174 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11178 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11179 * anchor positions (defaults to 'tl-bl')
11181 listAlign: 'tl-bl?',
11183 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11187 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11188 * query specified by the allQuery config option (defaults to 'query')
11190 triggerAction: 'query',
11192 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11193 * (defaults to 4, does not apply if editable = false)
11197 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11198 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11202 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11203 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11207 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11208 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11212 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11213 * when editable = true (defaults to false)
11215 selectOnFocus:false,
11217 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11219 queryParam: 'query',
11221 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11222 * when mode = 'remote' (defaults to 'Loading...')
11224 loadingText: 'Loading...',
11226 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11230 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11234 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11235 * traditional select (defaults to true)
11239 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11243 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11247 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11248 * listWidth has a higher value)
11252 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11253 * allow the user to set arbitrary text into the field (defaults to false)
11255 forceSelection:false,
11257 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11258 * if typeAhead = true (defaults to 250)
11260 typeAheadDelay : 250,
11262 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11263 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11265 valueNotFoundText : undefined,
11267 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11269 blockFocus : false,
11272 * @cfg {Boolean} disableClear Disable showing of clear button.
11274 disableClear : false,
11276 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11278 alwaysQuery : false,
11281 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11286 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11288 invalidClass : "has-warning",
11291 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11293 validClass : "has-success",
11296 * @cfg {Boolean} specialFilter (true|false) special filter default false
11298 specialFilter : false,
11310 btnPosition : 'right',
11311 triggerList : true,
11312 showToggleBtn : true,
11313 // element that contains real text value.. (when hidden is used..)
11315 getAutoCreate : function()
11322 if(!this.tickable){
11323 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11328 * ComboBox with tickable selections
11331 var align = this.labelAlign || this.parentLabelAlign();
11334 cls : 'form-group roo-combobox-tickable' //input-group
11339 cls : 'tickable-buttons',
11344 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11351 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11358 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11365 buttons.cn.unshift({
11367 cls: 'select2-search-field-input'
11373 Roo.each(buttons.cn, function(c){
11375 c.cls += ' btn-' + _this.size;
11378 if (_this.disabled) {
11389 cls: 'form-hidden-field'
11393 cls: 'select2-choices',
11397 cls: 'select2-search-field',
11409 cls: 'select2-container input-group select2-container-multi',
11414 // cls: 'typeahead typeahead-long dropdown-menu',
11415 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11420 if(this.hasFeedback && !this.allowBlank){
11424 cls: 'glyphicon form-control-feedback'
11427 combobox.cn.push(feedback);
11430 if (align ==='left' && this.fieldLabel.length) {
11432 Roo.log("left and has label");
11438 cls : 'control-label col-sm-' + this.labelWidth,
11439 html : this.fieldLabel
11443 cls : "col-sm-" + (12 - this.labelWidth),
11450 } else if ( this.fieldLabel.length) {
11456 //cls : 'input-group-addon',
11457 html : this.fieldLabel
11467 Roo.log(" no label && no align");
11474 ['xs','sm','md','lg'].map(function(size){
11475 if (settings[size]) {
11476 cfg.cls += ' col-' + size + '-' + settings[size];
11485 initEvents: function()
11489 throw "can not find store for combo";
11491 this.store = Roo.factory(this.store, Roo.data);
11494 this.initTickableEvents();
11498 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11500 if(this.hiddenName){
11502 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11504 this.hiddenField.dom.value =
11505 this.hiddenValue !== undefined ? this.hiddenValue :
11506 this.value !== undefined ? this.value : '';
11508 // prevent input submission
11509 this.el.dom.removeAttribute('name');
11510 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11515 // this.el.dom.setAttribute('autocomplete', 'off');
11518 var cls = 'x-combo-list';
11520 //this.list = new Roo.Layer({
11521 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11527 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11528 _this.list.setWidth(lw);
11531 this.list.on('mouseover', this.onViewOver, this);
11532 this.list.on('mousemove', this.onViewMove, this);
11534 this.list.on('scroll', this.onViewScroll, this);
11537 this.list.swallowEvent('mousewheel');
11538 this.assetHeight = 0;
11541 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11542 this.assetHeight += this.header.getHeight();
11545 this.innerList = this.list.createChild({cls:cls+'-inner'});
11546 this.innerList.on('mouseover', this.onViewOver, this);
11547 this.innerList.on('mousemove', this.onViewMove, this);
11548 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11550 if(this.allowBlank && !this.pageSize && !this.disableClear){
11551 this.footer = this.list.createChild({cls:cls+'-ft'});
11552 this.pageTb = new Roo.Toolbar(this.footer);
11556 this.footer = this.list.createChild({cls:cls+'-ft'});
11557 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11558 {pageSize: this.pageSize});
11562 if (this.pageTb && this.allowBlank && !this.disableClear) {
11564 this.pageTb.add(new Roo.Toolbar.Fill(), {
11565 cls: 'x-btn-icon x-btn-clear',
11567 handler: function()
11570 _this.clearValue();
11571 _this.onSelect(false, -1);
11576 this.assetHeight += this.footer.getHeight();
11581 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11584 this.view = new Roo.View(this.list, this.tpl, {
11585 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11587 //this.view.wrapEl.setDisplayed(false);
11588 this.view.on('click', this.onViewClick, this);
11592 this.store.on('beforeload', this.onBeforeLoad, this);
11593 this.store.on('load', this.onLoad, this);
11594 this.store.on('loadexception', this.onLoadException, this);
11596 if(this.resizable){
11597 this.resizer = new Roo.Resizable(this.list, {
11598 pinned:true, handles:'se'
11600 this.resizer.on('resize', function(r, w, h){
11601 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11602 this.listWidth = w;
11603 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11604 this.restrictHeight();
11606 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11609 if(!this.editable){
11610 this.editable = true;
11611 this.setEditable(false);
11616 if (typeof(this.events.add.listeners) != 'undefined') {
11618 this.addicon = this.wrap.createChild(
11619 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11621 this.addicon.on('click', function(e) {
11622 this.fireEvent('add', this);
11625 if (typeof(this.events.edit.listeners) != 'undefined') {
11627 this.editicon = this.wrap.createChild(
11628 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11629 if (this.addicon) {
11630 this.editicon.setStyle('margin-left', '40px');
11632 this.editicon.on('click', function(e) {
11634 // we fire even if inothing is selected..
11635 this.fireEvent('edit', this, this.lastData );
11641 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11642 "up" : function(e){
11643 this.inKeyMode = true;
11647 "down" : function(e){
11648 if(!this.isExpanded()){
11649 this.onTriggerClick();
11651 this.inKeyMode = true;
11656 "enter" : function(e){
11657 // this.onViewClick();
11661 if(this.fireEvent("specialkey", this, e)){
11662 this.onViewClick(false);
11668 "esc" : function(e){
11672 "tab" : function(e){
11675 if(this.fireEvent("specialkey", this, e)){
11676 this.onViewClick(false);
11684 doRelay : function(foo, bar, hname){
11685 if(hname == 'down' || this.scope.isExpanded()){
11686 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11695 this.queryDelay = Math.max(this.queryDelay || 10,
11696 this.mode == 'local' ? 10 : 250);
11699 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11701 if(this.typeAhead){
11702 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11704 if(this.editable !== false){
11705 this.inputEl().on("keyup", this.onKeyUp, this);
11707 if(this.forceSelection){
11708 this.inputEl().on('blur', this.doForce, this);
11712 this.choices = this.el.select('ul.select2-choices', true).first();
11713 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11717 initTickableEvents: function()
11721 if(this.hiddenName){
11723 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11725 this.hiddenField.dom.value =
11726 this.hiddenValue !== undefined ? this.hiddenValue :
11727 this.value !== undefined ? this.value : '';
11729 // prevent input submission
11730 this.el.dom.removeAttribute('name');
11731 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11736 // this.list = this.el.select('ul.dropdown-menu',true).first();
11738 this.choices = this.el.select('ul.select2-choices', true).first();
11739 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11740 if(this.triggerList){
11741 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11744 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11745 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11747 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11748 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11750 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11751 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11753 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11754 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11755 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11758 this.cancelBtn.hide();
11763 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11764 _this.list.setWidth(lw);
11767 this.list.on('mouseover', this.onViewOver, this);
11768 this.list.on('mousemove', this.onViewMove, this);
11770 this.list.on('scroll', this.onViewScroll, this);
11773 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>';
11776 this.view = new Roo.View(this.list, this.tpl, {
11777 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11780 //this.view.wrapEl.setDisplayed(false);
11781 this.view.on('click', this.onViewClick, this);
11785 this.store.on('beforeload', this.onBeforeLoad, this);
11786 this.store.on('load', this.onLoad, this);
11787 this.store.on('loadexception', this.onLoadException, this);
11790 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11791 "up" : function(e){
11792 this.inKeyMode = true;
11796 "down" : function(e){
11797 this.inKeyMode = true;
11801 "enter" : function(e){
11802 if(this.fireEvent("specialkey", this, e)){
11803 this.onViewClick(false);
11809 "esc" : function(e){
11810 this.onTickableFooterButtonClick(e, false, false);
11813 "tab" : function(e){
11814 this.fireEvent("specialkey", this, e);
11816 this.onTickableFooterButtonClick(e, false, false);
11823 doRelay : function(e, fn, key){
11824 if(this.scope.isExpanded()){
11825 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11834 this.queryDelay = Math.max(this.queryDelay || 10,
11835 this.mode == 'local' ? 10 : 250);
11838 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11840 if(this.typeAhead){
11841 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11844 if(this.editable !== false){
11845 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11850 onDestroy : function(){
11852 this.view.setStore(null);
11853 this.view.el.removeAllListeners();
11854 this.view.el.remove();
11855 this.view.purgeListeners();
11858 this.list.dom.innerHTML = '';
11862 this.store.un('beforeload', this.onBeforeLoad, this);
11863 this.store.un('load', this.onLoad, this);
11864 this.store.un('loadexception', this.onLoadException, this);
11866 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11870 fireKey : function(e){
11871 if(e.isNavKeyPress() && !this.list.isVisible()){
11872 this.fireEvent("specialkey", this, e);
11877 onResize: function(w, h){
11878 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11880 // if(typeof w != 'number'){
11881 // // we do not handle it!?!?
11884 // var tw = this.trigger.getWidth();
11885 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11886 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11888 // this.inputEl().setWidth( this.adjustWidth('input', x));
11890 // //this.trigger.setStyle('left', x+'px');
11892 // if(this.list && this.listWidth === undefined){
11893 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11894 // this.list.setWidth(lw);
11895 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11903 * Allow or prevent the user from directly editing the field text. If false is passed,
11904 * the user will only be able to select from the items defined in the dropdown list. This method
11905 * is the runtime equivalent of setting the 'editable' config option at config time.
11906 * @param {Boolean} value True to allow the user to directly edit the field text
11908 setEditable : function(value){
11909 if(value == this.editable){
11912 this.editable = value;
11914 this.inputEl().dom.setAttribute('readOnly', true);
11915 this.inputEl().on('mousedown', this.onTriggerClick, this);
11916 this.inputEl().addClass('x-combo-noedit');
11918 this.inputEl().dom.setAttribute('readOnly', false);
11919 this.inputEl().un('mousedown', this.onTriggerClick, this);
11920 this.inputEl().removeClass('x-combo-noedit');
11926 onBeforeLoad : function(combo,opts){
11927 if(!this.hasFocus){
11931 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11933 this.restrictHeight();
11934 this.selectedIndex = -1;
11938 onLoad : function(){
11940 this.hasQuery = false;
11942 if(!this.hasFocus){
11946 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11947 this.loading.hide();
11950 if(this.store.getCount() > 0){
11952 this.restrictHeight();
11953 if(this.lastQuery == this.allQuery){
11954 if(this.editable && !this.tickable){
11955 this.inputEl().dom.select();
11959 !this.selectByValue(this.value, true) &&
11962 !this.store.lastOptions ||
11963 typeof(this.store.lastOptions.add) == 'undefined' ||
11964 this.store.lastOptions.add != true
11967 this.select(0, true);
11970 if(this.autoFocus){
11973 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11974 this.taTask.delay(this.typeAheadDelay);
11978 this.onEmptyResults();
11984 onLoadException : function()
11986 this.hasQuery = false;
11988 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11989 this.loading.hide();
11992 if(this.tickable && this.editable){
11998 Roo.log(this.store.reader.jsonData);
11999 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12001 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12007 onTypeAhead : function(){
12008 if(this.store.getCount() > 0){
12009 var r = this.store.getAt(0);
12010 var newValue = r.data[this.displayField];
12011 var len = newValue.length;
12012 var selStart = this.getRawValue().length;
12014 if(selStart != len){
12015 this.setRawValue(newValue);
12016 this.selectText(selStart, newValue.length);
12022 onSelect : function(record, index){
12024 if(this.fireEvent('beforeselect', this, record, index) !== false){
12026 this.setFromData(index > -1 ? record.data : false);
12029 this.fireEvent('select', this, record, index);
12034 * Returns the currently selected field value or empty string if no value is set.
12035 * @return {String} value The selected value
12037 getValue : function(){
12040 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12043 if(this.valueField){
12044 return typeof this.value != 'undefined' ? this.value : '';
12046 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12051 * Clears any text/value currently set in the field
12053 clearValue : function(){
12054 if(this.hiddenField){
12055 this.hiddenField.dom.value = '';
12058 this.setRawValue('');
12059 this.lastSelectionText = '';
12060 this.lastData = false;
12062 var close = this.closeTriggerEl();
12071 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12072 * will be displayed in the field. If the value does not match the data value of an existing item,
12073 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12074 * Otherwise the field will be blank (although the value will still be set).
12075 * @param {String} value The value to match
12077 setValue : function(v){
12084 if(this.valueField){
12085 var r = this.findRecord(this.valueField, v);
12087 text = r.data[this.displayField];
12088 }else if(this.valueNotFoundText !== undefined){
12089 text = this.valueNotFoundText;
12092 this.lastSelectionText = text;
12093 if(this.hiddenField){
12094 this.hiddenField.dom.value = v;
12096 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12099 var close = this.closeTriggerEl();
12102 (v.length || v * 1 > 0) ? close.show() : close.hide();
12106 * @property {Object} the last set data for the element
12111 * Sets the value of the field based on a object which is related to the record format for the store.
12112 * @param {Object} value the value to set as. or false on reset?
12114 setFromData : function(o){
12121 var dv = ''; // display value
12122 var vv = ''; // value value..
12124 if (this.displayField) {
12125 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12127 // this is an error condition!!!
12128 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12131 if(this.valueField){
12132 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12135 var close = this.closeTriggerEl();
12138 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12141 if(this.hiddenField){
12142 this.hiddenField.dom.value = vv;
12144 this.lastSelectionText = dv;
12145 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12149 // no hidden field.. - we store the value in 'value', but still display
12150 // display field!!!!
12151 this.lastSelectionText = dv;
12152 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12159 reset : function(){
12160 // overridden so that last data is reset..
12167 this.setValue(this.originalValue);
12168 this.clearInvalid();
12169 this.lastData = false;
12171 this.view.clearSelections();
12175 findRecord : function(prop, value){
12177 if(this.store.getCount() > 0){
12178 this.store.each(function(r){
12179 if(r.data[prop] == value){
12189 getName: function()
12191 // returns hidden if it's set..
12192 if (!this.rendered) {return ''};
12193 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12197 onViewMove : function(e, t){
12198 this.inKeyMode = false;
12202 onViewOver : function(e, t){
12203 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12206 var item = this.view.findItemFromChild(t);
12209 var index = this.view.indexOf(item);
12210 this.select(index, false);
12215 onViewClick : function(view, doFocus, el, e)
12217 var index = this.view.getSelectedIndexes()[0];
12219 var r = this.store.getAt(index);
12223 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12230 Roo.each(this.tickItems, function(v,k){
12232 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12233 _this.tickItems.splice(k, 1);
12235 if(typeof(e) == 'undefined' && view == false){
12236 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12248 this.tickItems.push(r.data);
12250 if(typeof(e) == 'undefined' && view == false){
12251 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12258 this.onSelect(r, index);
12260 if(doFocus !== false && !this.blockFocus){
12261 this.inputEl().focus();
12266 restrictHeight : function(){
12267 //this.innerList.dom.style.height = '';
12268 //var inner = this.innerList.dom;
12269 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12270 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12271 //this.list.beginUpdate();
12272 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12273 this.list.alignTo(this.inputEl(), this.listAlign);
12274 this.list.alignTo(this.inputEl(), this.listAlign);
12275 //this.list.endUpdate();
12279 onEmptyResults : function(){
12281 if(this.tickable && this.editable){
12282 this.restrictHeight();
12290 * Returns true if the dropdown list is expanded, else false.
12292 isExpanded : function(){
12293 return this.list.isVisible();
12297 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12298 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12299 * @param {String} value The data value of the item to select
12300 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12301 * selected item if it is not currently in view (defaults to true)
12302 * @return {Boolean} True if the value matched an item in the list, else false
12304 selectByValue : function(v, scrollIntoView){
12305 if(v !== undefined && v !== null){
12306 var r = this.findRecord(this.valueField || this.displayField, v);
12308 this.select(this.store.indexOf(r), scrollIntoView);
12316 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12317 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12318 * @param {Number} index The zero-based index of the list item to select
12319 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12320 * selected item if it is not currently in view (defaults to true)
12322 select : function(index, scrollIntoView){
12323 this.selectedIndex = index;
12324 this.view.select(index);
12325 if(scrollIntoView !== false){
12326 var el = this.view.getNode(index);
12328 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12331 this.list.scrollChildIntoView(el, false);
12337 selectNext : function(){
12338 var ct = this.store.getCount();
12340 if(this.selectedIndex == -1){
12342 }else if(this.selectedIndex < ct-1){
12343 this.select(this.selectedIndex+1);
12349 selectPrev : function(){
12350 var ct = this.store.getCount();
12352 if(this.selectedIndex == -1){
12354 }else if(this.selectedIndex != 0){
12355 this.select(this.selectedIndex-1);
12361 onKeyUp : function(e){
12362 if(this.editable !== false && !e.isSpecialKey()){
12363 this.lastKey = e.getKey();
12364 this.dqTask.delay(this.queryDelay);
12369 validateBlur : function(){
12370 return !this.list || !this.list.isVisible();
12374 initQuery : function(){
12376 var v = this.getRawValue();
12378 if(this.tickable && this.editable){
12379 v = this.tickableInputEl().getValue();
12386 doForce : function(){
12387 if(this.inputEl().dom.value.length > 0){
12388 this.inputEl().dom.value =
12389 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12395 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12396 * query allowing the query action to be canceled if needed.
12397 * @param {String} query The SQL query to execute
12398 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12399 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12400 * saved in the current store (defaults to false)
12402 doQuery : function(q, forceAll){
12404 if(q === undefined || q === null){
12409 forceAll: forceAll,
12413 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12418 forceAll = qe.forceAll;
12419 if(forceAll === true || (q.length >= this.minChars)){
12421 this.hasQuery = true;
12423 if(this.lastQuery != q || this.alwaysQuery){
12424 this.lastQuery = q;
12425 if(this.mode == 'local'){
12426 this.selectedIndex = -1;
12428 this.store.clearFilter();
12431 if(this.specialFilter){
12432 this.fireEvent('specialfilter', this);
12437 this.store.filter(this.displayField, q);
12440 this.store.fireEvent("datachanged", this.store);
12447 this.store.baseParams[this.queryParam] = q;
12449 var options = {params : this.getParams(q)};
12452 options.add = true;
12453 options.params.start = this.page * this.pageSize;
12456 this.store.load(options);
12459 * this code will make the page width larger, at the beginning, the list not align correctly,
12460 * we should expand the list on onLoad
12461 * so command out it
12466 this.selectedIndex = -1;
12471 this.loadNext = false;
12475 getParams : function(q){
12477 //p[this.queryParam] = q;
12481 p.limit = this.pageSize;
12487 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12489 collapse : function(){
12490 if(!this.isExpanded()){
12497 this.hasFocus = false;
12499 this.cancelBtn.hide();
12500 this.trigger.show();
12503 this.tickableInputEl().dom.value = '';
12504 this.tickableInputEl().blur();
12509 Roo.get(document).un('mousedown', this.collapseIf, this);
12510 Roo.get(document).un('mousewheel', this.collapseIf, this);
12511 if (!this.editable) {
12512 Roo.get(document).un('keydown', this.listKeyPress, this);
12514 this.fireEvent('collapse', this);
12518 collapseIf : function(e){
12519 var in_combo = e.within(this.el);
12520 var in_list = e.within(this.list);
12521 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12523 if (in_combo || in_list || is_list) {
12524 //e.stopPropagation();
12529 this.onTickableFooterButtonClick(e, false, false);
12537 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12539 expand : function(){
12541 if(this.isExpanded() || !this.hasFocus){
12545 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12546 this.list.setWidth(lw);
12553 this.restrictHeight();
12557 this.tickItems = Roo.apply([], this.item);
12560 this.cancelBtn.show();
12561 this.trigger.hide();
12564 this.tickableInputEl().focus();
12569 Roo.get(document).on('mousedown', this.collapseIf, this);
12570 Roo.get(document).on('mousewheel', this.collapseIf, this);
12571 if (!this.editable) {
12572 Roo.get(document).on('keydown', this.listKeyPress, this);
12575 this.fireEvent('expand', this);
12579 // Implements the default empty TriggerField.onTriggerClick function
12580 onTriggerClick : function(e)
12582 Roo.log('trigger click');
12584 if(this.disabled || !this.triggerList){
12589 this.loadNext = false;
12591 if(this.isExpanded()){
12593 if (!this.blockFocus) {
12594 this.inputEl().focus();
12598 this.hasFocus = true;
12599 if(this.triggerAction == 'all') {
12600 this.doQuery(this.allQuery, true);
12602 this.doQuery(this.getRawValue());
12604 if (!this.blockFocus) {
12605 this.inputEl().focus();
12610 onTickableTriggerClick : function(e)
12617 this.loadNext = false;
12618 this.hasFocus = true;
12620 if(this.triggerAction == 'all') {
12621 this.doQuery(this.allQuery, true);
12623 this.doQuery(this.getRawValue());
12627 onSearchFieldClick : function(e)
12629 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12630 this.onTickableFooterButtonClick(e, false, false);
12634 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12639 this.loadNext = false;
12640 this.hasFocus = true;
12642 if(this.triggerAction == 'all') {
12643 this.doQuery(this.allQuery, true);
12645 this.doQuery(this.getRawValue());
12649 listKeyPress : function(e)
12651 //Roo.log('listkeypress');
12652 // scroll to first matching element based on key pres..
12653 if (e.isSpecialKey()) {
12656 var k = String.fromCharCode(e.getKey()).toUpperCase();
12659 var csel = this.view.getSelectedNodes();
12660 var cselitem = false;
12662 var ix = this.view.indexOf(csel[0]);
12663 cselitem = this.store.getAt(ix);
12664 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12670 this.store.each(function(v) {
12672 // start at existing selection.
12673 if (cselitem.id == v.id) {
12679 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12680 match = this.store.indexOf(v);
12686 if (match === false) {
12687 return true; // no more action?
12690 this.view.select(match);
12691 var sn = Roo.get(this.view.getSelectedNodes()[0])
12692 sn.scrollIntoView(sn.dom.parentNode, false);
12695 onViewScroll : function(e, t){
12697 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){
12701 this.hasQuery = true;
12703 this.loading = this.list.select('.loading', true).first();
12705 if(this.loading === null){
12706 this.list.createChild({
12708 cls: 'loading select2-more-results select2-active',
12709 html: 'Loading more results...'
12712 this.loading = this.list.select('.loading', true).first();
12714 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12716 this.loading.hide();
12719 this.loading.show();
12724 this.loadNext = true;
12726 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12731 addItem : function(o)
12733 var dv = ''; // display value
12735 if (this.displayField) {
12736 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12738 // this is an error condition!!!
12739 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12746 var choice = this.choices.createChild({
12748 cls: 'select2-search-choice',
12757 cls: 'select2-search-choice-close',
12762 }, this.searchField);
12764 var close = choice.select('a.select2-search-choice-close', true).first()
12766 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12774 this.inputEl().dom.value = '';
12779 onRemoveItem : function(e, _self, o)
12781 e.preventDefault();
12783 this.lastItem = Roo.apply([], this.item);
12785 var index = this.item.indexOf(o.data) * 1;
12788 Roo.log('not this item?!');
12792 this.item.splice(index, 1);
12797 this.fireEvent('remove', this, e);
12803 syncValue : function()
12805 if(!this.item.length){
12812 Roo.each(this.item, function(i){
12813 if(_this.valueField){
12814 value.push(i[_this.valueField]);
12821 this.value = value.join(',');
12823 if(this.hiddenField){
12824 this.hiddenField.dom.value = this.value;
12827 this.store.fireEvent("datachanged", this.store);
12830 clearItem : function()
12832 if(!this.multiple){
12838 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12847 inputEl: function ()
12850 return this.searchField;
12852 return this.el.select('input.form-control',true).first();
12856 onTickableFooterButtonClick : function(e, btn, el)
12858 e.preventDefault();
12860 this.lastItem = Roo.apply([], this.item);
12862 if(btn && btn.name == 'cancel'){
12863 this.tickItems = Roo.apply([], this.item);
12872 Roo.each(this.tickItems, function(o){
12880 validate : function()
12882 var v = this.getRawValue();
12885 v = this.getValue();
12888 if(this.disabled || this.allowBlank || v.length){
12893 this.markInvalid();
12897 tickableInputEl : function()
12899 if(!this.tickable || !this.editable){
12900 return this.inputEl();
12903 return this.inputEl().select('.select2-search-field-input', true).first();
12909 * @cfg {Boolean} grow
12913 * @cfg {Number} growMin
12917 * @cfg {Number} growMax
12927 * Ext JS Library 1.1.1
12928 * Copyright(c) 2006-2007, Ext JS, LLC.
12930 * Originally Released Under LGPL - original licence link has changed is not relivant.
12933 * <script type="text/javascript">
12938 * @extends Roo.util.Observable
12939 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12940 * This class also supports single and multi selection modes. <br>
12941 * Create a data model bound view:
12943 var store = new Roo.data.Store(...);
12945 var view = new Roo.View({
12947 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12949 singleSelect: true,
12950 selectedClass: "ydataview-selected",
12954 // listen for node click?
12955 view.on("click", function(vw, index, node, e){
12956 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12960 dataModel.load("foobar.xml");
12962 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12964 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12965 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12967 * Note: old style constructor is still suported (container, template, config)
12970 * Create a new View
12971 * @param {Object} config The config object
12974 Roo.View = function(config, depreciated_tpl, depreciated_config){
12976 this.parent = false;
12978 if (typeof(depreciated_tpl) == 'undefined') {
12979 // new way.. - universal constructor.
12980 Roo.apply(this, config);
12981 this.el = Roo.get(this.el);
12984 this.el = Roo.get(config);
12985 this.tpl = depreciated_tpl;
12986 Roo.apply(this, depreciated_config);
12988 this.wrapEl = this.el.wrap().wrap();
12989 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12992 if(typeof(this.tpl) == "string"){
12993 this.tpl = new Roo.Template(this.tpl);
12995 // support xtype ctors..
12996 this.tpl = new Roo.factory(this.tpl, Roo);
13000 this.tpl.compile();
13005 * @event beforeclick
13006 * Fires before a click is processed. Returns false to cancel the default action.
13007 * @param {Roo.View} this
13008 * @param {Number} index The index of the target node
13009 * @param {HTMLElement} node The target node
13010 * @param {Roo.EventObject} e The raw event object
13012 "beforeclick" : true,
13015 * Fires when a template node is clicked.
13016 * @param {Roo.View} this
13017 * @param {Number} index The index of the target node
13018 * @param {HTMLElement} node The target node
13019 * @param {Roo.EventObject} e The raw event object
13024 * Fires when a template node is double clicked.
13025 * @param {Roo.View} this
13026 * @param {Number} index The index of the target node
13027 * @param {HTMLElement} node The target node
13028 * @param {Roo.EventObject} e The raw event object
13032 * @event contextmenu
13033 * Fires when a template node is right clicked.
13034 * @param {Roo.View} this
13035 * @param {Number} index The index of the target node
13036 * @param {HTMLElement} node The target node
13037 * @param {Roo.EventObject} e The raw event object
13039 "contextmenu" : true,
13041 * @event selectionchange
13042 * Fires when the selected nodes change.
13043 * @param {Roo.View} this
13044 * @param {Array} selections Array of the selected nodes
13046 "selectionchange" : true,
13049 * @event beforeselect
13050 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13051 * @param {Roo.View} this
13052 * @param {HTMLElement} node The node to be selected
13053 * @param {Array} selections Array of currently selected nodes
13055 "beforeselect" : true,
13057 * @event preparedata
13058 * Fires on every row to render, to allow you to change the data.
13059 * @param {Roo.View} this
13060 * @param {Object} data to be rendered (change this)
13062 "preparedata" : true
13070 "click": this.onClick,
13071 "dblclick": this.onDblClick,
13072 "contextmenu": this.onContextMenu,
13076 this.selections = [];
13078 this.cmp = new Roo.CompositeElementLite([]);
13080 this.store = Roo.factory(this.store, Roo.data);
13081 this.setStore(this.store, true);
13084 if ( this.footer && this.footer.xtype) {
13086 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13088 this.footer.dataSource = this.store
13089 this.footer.container = fctr;
13090 this.footer = Roo.factory(this.footer, Roo);
13091 fctr.insertFirst(this.el);
13093 // this is a bit insane - as the paging toolbar seems to detach the el..
13094 // dom.parentNode.parentNode.parentNode
13095 // they get detached?
13099 Roo.View.superclass.constructor.call(this);
13104 Roo.extend(Roo.View, Roo.util.Observable, {
13107 * @cfg {Roo.data.Store} store Data store to load data from.
13112 * @cfg {String|Roo.Element} el The container element.
13117 * @cfg {String|Roo.Template} tpl The template used by this View
13121 * @cfg {String} dataName the named area of the template to use as the data area
13122 * Works with domtemplates roo-name="name"
13126 * @cfg {String} selectedClass The css class to add to selected nodes
13128 selectedClass : "x-view-selected",
13130 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13135 * @cfg {String} text to display on mask (default Loading)
13139 * @cfg {Boolean} multiSelect Allow multiple selection
13141 multiSelect : false,
13143 * @cfg {Boolean} singleSelect Allow single selection
13145 singleSelect: false,
13148 * @cfg {Boolean} toggleSelect - selecting
13150 toggleSelect : false,
13153 * @cfg {Boolean} tickable - selecting
13158 * Returns the element this view is bound to.
13159 * @return {Roo.Element}
13161 getEl : function(){
13162 return this.wrapEl;
13168 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13170 refresh : function(){
13171 //Roo.log('refresh');
13174 // if we are using something like 'domtemplate', then
13175 // the what gets used is:
13176 // t.applySubtemplate(NAME, data, wrapping data..)
13177 // the outer template then get' applied with
13178 // the store 'extra data'
13179 // and the body get's added to the
13180 // roo-name="data" node?
13181 // <span class='roo-tpl-{name}'></span> ?????
13185 this.clearSelections();
13186 this.el.update("");
13188 var records = this.store.getRange();
13189 if(records.length < 1) {
13191 // is this valid?? = should it render a template??
13193 this.el.update(this.emptyText);
13197 if (this.dataName) {
13198 this.el.update(t.apply(this.store.meta)); //????
13199 el = this.el.child('.roo-tpl-' + this.dataName);
13202 for(var i = 0, len = records.length; i < len; i++){
13203 var data = this.prepareData(records[i].data, i, records[i]);
13204 this.fireEvent("preparedata", this, data, i, records[i]);
13206 var d = Roo.apply({}, data);
13209 Roo.apply(d, {'roo-id' : Roo.id()});
13213 Roo.each(this.parent.item, function(item){
13214 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13217 Roo.apply(d, {'roo-data-checked' : 'checked'});
13221 html[html.length] = Roo.util.Format.trim(
13223 t.applySubtemplate(this.dataName, d, this.store.meta) :
13230 el.update(html.join(""));
13231 this.nodes = el.dom.childNodes;
13232 this.updateIndexes(0);
13237 * Function to override to reformat the data that is sent to
13238 * the template for each node.
13239 * DEPRICATED - use the preparedata event handler.
13240 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13241 * a JSON object for an UpdateManager bound view).
13243 prepareData : function(data, index, record)
13245 this.fireEvent("preparedata", this, data, index, record);
13249 onUpdate : function(ds, record){
13250 // Roo.log('on update');
13251 this.clearSelections();
13252 var index = this.store.indexOf(record);
13253 var n = this.nodes[index];
13254 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13255 n.parentNode.removeChild(n);
13256 this.updateIndexes(index, index);
13262 onAdd : function(ds, records, index)
13264 //Roo.log(['on Add', ds, records, index] );
13265 this.clearSelections();
13266 if(this.nodes.length == 0){
13270 var n = this.nodes[index];
13271 for(var i = 0, len = records.length; i < len; i++){
13272 var d = this.prepareData(records[i].data, i, records[i]);
13274 this.tpl.insertBefore(n, d);
13277 this.tpl.append(this.el, d);
13280 this.updateIndexes(index);
13283 onRemove : function(ds, record, index){
13284 // Roo.log('onRemove');
13285 this.clearSelections();
13286 var el = this.dataName ?
13287 this.el.child('.roo-tpl-' + this.dataName) :
13290 el.dom.removeChild(this.nodes[index]);
13291 this.updateIndexes(index);
13295 * Refresh an individual node.
13296 * @param {Number} index
13298 refreshNode : function(index){
13299 this.onUpdate(this.store, this.store.getAt(index));
13302 updateIndexes : function(startIndex, endIndex){
13303 var ns = this.nodes;
13304 startIndex = startIndex || 0;
13305 endIndex = endIndex || ns.length - 1;
13306 for(var i = startIndex; i <= endIndex; i++){
13307 ns[i].nodeIndex = i;
13312 * Changes the data store this view uses and refresh the view.
13313 * @param {Store} store
13315 setStore : function(store, initial){
13316 if(!initial && this.store){
13317 this.store.un("datachanged", this.refresh);
13318 this.store.un("add", this.onAdd);
13319 this.store.un("remove", this.onRemove);
13320 this.store.un("update", this.onUpdate);
13321 this.store.un("clear", this.refresh);
13322 this.store.un("beforeload", this.onBeforeLoad);
13323 this.store.un("load", this.onLoad);
13324 this.store.un("loadexception", this.onLoad);
13328 store.on("datachanged", this.refresh, this);
13329 store.on("add", this.onAdd, this);
13330 store.on("remove", this.onRemove, this);
13331 store.on("update", this.onUpdate, this);
13332 store.on("clear", this.refresh, this);
13333 store.on("beforeload", this.onBeforeLoad, this);
13334 store.on("load", this.onLoad, this);
13335 store.on("loadexception", this.onLoad, this);
13343 * onbeforeLoad - masks the loading area.
13346 onBeforeLoad : function(store,opts)
13348 //Roo.log('onBeforeLoad');
13350 this.el.update("");
13352 this.el.mask(this.mask ? this.mask : "Loading" );
13354 onLoad : function ()
13361 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13362 * @param {HTMLElement} node
13363 * @return {HTMLElement} The template node
13365 findItemFromChild : function(node){
13366 var el = this.dataName ?
13367 this.el.child('.roo-tpl-' + this.dataName,true) :
13370 if(!node || node.parentNode == el){
13373 var p = node.parentNode;
13374 while(p && p != el){
13375 if(p.parentNode == el){
13384 onClick : function(e){
13385 var item = this.findItemFromChild(e.getTarget());
13387 var index = this.indexOf(item);
13388 if(this.onItemClick(item, index, e) !== false){
13389 this.fireEvent("click", this, index, item, e);
13392 this.clearSelections();
13397 onContextMenu : function(e){
13398 var item = this.findItemFromChild(e.getTarget());
13400 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13405 onDblClick : function(e){
13406 var item = this.findItemFromChild(e.getTarget());
13408 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13412 onItemClick : function(item, index, e)
13414 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13417 if (this.toggleSelect) {
13418 var m = this.isSelected(item) ? 'unselect' : 'select';
13421 _t[m](item, true, false);
13424 if(this.multiSelect || this.singleSelect){
13425 if(this.multiSelect && e.shiftKey && this.lastSelection){
13426 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13428 this.select(item, this.multiSelect && e.ctrlKey);
13429 this.lastSelection = item;
13432 if(!this.tickable){
13433 e.preventDefault();
13441 * Get the number of selected nodes.
13444 getSelectionCount : function(){
13445 return this.selections.length;
13449 * Get the currently selected nodes.
13450 * @return {Array} An array of HTMLElements
13452 getSelectedNodes : function(){
13453 return this.selections;
13457 * Get the indexes of the selected nodes.
13460 getSelectedIndexes : function(){
13461 var indexes = [], s = this.selections;
13462 for(var i = 0, len = s.length; i < len; i++){
13463 indexes.push(s[i].nodeIndex);
13469 * Clear all selections
13470 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13472 clearSelections : function(suppressEvent){
13473 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13474 this.cmp.elements = this.selections;
13475 this.cmp.removeClass(this.selectedClass);
13476 this.selections = [];
13477 if(!suppressEvent){
13478 this.fireEvent("selectionchange", this, this.selections);
13484 * Returns true if the passed node is selected
13485 * @param {HTMLElement/Number} node The node or node index
13486 * @return {Boolean}
13488 isSelected : function(node){
13489 var s = this.selections;
13493 node = this.getNode(node);
13494 return s.indexOf(node) !== -1;
13499 * @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
13500 * @param {Boolean} keepExisting (optional) true to keep existing selections
13501 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13503 select : function(nodeInfo, keepExisting, suppressEvent){
13504 if(nodeInfo instanceof Array){
13506 this.clearSelections(true);
13508 for(var i = 0, len = nodeInfo.length; i < len; i++){
13509 this.select(nodeInfo[i], true, true);
13513 var node = this.getNode(nodeInfo);
13514 if(!node || this.isSelected(node)){
13515 return; // already selected.
13518 this.clearSelections(true);
13521 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13522 Roo.fly(node).addClass(this.selectedClass);
13523 this.selections.push(node);
13524 if(!suppressEvent){
13525 this.fireEvent("selectionchange", this, this.selections);
13533 * @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
13534 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13535 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13537 unselect : function(nodeInfo, keepExisting, suppressEvent)
13539 if(nodeInfo instanceof Array){
13540 Roo.each(this.selections, function(s) {
13541 this.unselect(s, nodeInfo);
13545 var node = this.getNode(nodeInfo);
13546 if(!node || !this.isSelected(node)){
13547 //Roo.log("not selected");
13548 return; // not selected.
13552 Roo.each(this.selections, function(s) {
13554 Roo.fly(node).removeClass(this.selectedClass);
13561 this.selections= ns;
13562 this.fireEvent("selectionchange", this, this.selections);
13566 * Gets a template node.
13567 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13568 * @return {HTMLElement} The node or null if it wasn't found
13570 getNode : function(nodeInfo){
13571 if(typeof nodeInfo == "string"){
13572 return document.getElementById(nodeInfo);
13573 }else if(typeof nodeInfo == "number"){
13574 return this.nodes[nodeInfo];
13580 * Gets a range template nodes.
13581 * @param {Number} startIndex
13582 * @param {Number} endIndex
13583 * @return {Array} An array of nodes
13585 getNodes : function(start, end){
13586 var ns = this.nodes;
13587 start = start || 0;
13588 end = typeof end == "undefined" ? ns.length - 1 : end;
13591 for(var i = start; i <= end; i++){
13595 for(var i = start; i >= end; i--){
13603 * Finds the index of the passed node
13604 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13605 * @return {Number} The index of the node or -1
13607 indexOf : function(node){
13608 node = this.getNode(node);
13609 if(typeof node.nodeIndex == "number"){
13610 return node.nodeIndex;
13612 var ns = this.nodes;
13613 for(var i = 0, len = ns.length; i < len; i++){
13624 * based on jquery fullcalendar
13628 Roo.bootstrap = Roo.bootstrap || {};
13630 * @class Roo.bootstrap.Calendar
13631 * @extends Roo.bootstrap.Component
13632 * Bootstrap Calendar class
13633 * @cfg {Boolean} loadMask (true|false) default false
13634 * @cfg {Object} header generate the user specific header of the calendar, default false
13637 * Create a new Container
13638 * @param {Object} config The config object
13643 Roo.bootstrap.Calendar = function(config){
13644 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13648 * Fires when a date is selected
13649 * @param {DatePicker} this
13650 * @param {Date} date The selected date
13654 * @event monthchange
13655 * Fires when the displayed month changes
13656 * @param {DatePicker} this
13657 * @param {Date} date The selected month
13659 'monthchange': true,
13661 * @event evententer
13662 * Fires when mouse over an event
13663 * @param {Calendar} this
13664 * @param {event} Event
13666 'evententer': true,
13668 * @event eventleave
13669 * Fires when the mouse leaves an
13670 * @param {Calendar} this
13673 'eventleave': true,
13675 * @event eventclick
13676 * Fires when the mouse click an
13677 * @param {Calendar} this
13686 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13689 * @cfg {Number} startDay
13690 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13698 getAutoCreate : function(){
13701 var fc_button = function(name, corner, style, content ) {
13702 return Roo.apply({},{
13704 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13706 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13709 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13720 style : 'width:100%',
13727 cls : 'fc-header-left',
13729 fc_button('prev', 'left', 'arrow', '‹' ),
13730 fc_button('next', 'right', 'arrow', '›' ),
13731 { tag: 'span', cls: 'fc-header-space' },
13732 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13740 cls : 'fc-header-center',
13744 cls: 'fc-header-title',
13747 html : 'month / year'
13755 cls : 'fc-header-right',
13757 /* fc_button('month', 'left', '', 'month' ),
13758 fc_button('week', '', '', 'week' ),
13759 fc_button('day', 'right', '', 'day' )
13771 header = this.header;
13774 var cal_heads = function() {
13776 // fixme - handle this.
13778 for (var i =0; i < Date.dayNames.length; i++) {
13779 var d = Date.dayNames[i];
13782 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13783 html : d.substring(0,3)
13787 ret[0].cls += ' fc-first';
13788 ret[6].cls += ' fc-last';
13791 var cal_cell = function(n) {
13794 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13799 cls: 'fc-day-number',
13803 cls: 'fc-day-content',
13807 style: 'position: relative;' // height: 17px;
13819 var cal_rows = function() {
13822 for (var r = 0; r < 6; r++) {
13829 for (var i =0; i < Date.dayNames.length; i++) {
13830 var d = Date.dayNames[i];
13831 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13834 row.cn[0].cls+=' fc-first';
13835 row.cn[0].cn[0].style = 'min-height:90px';
13836 row.cn[6].cls+=' fc-last';
13840 ret[0].cls += ' fc-first';
13841 ret[4].cls += ' fc-prev-last';
13842 ret[5].cls += ' fc-last';
13849 cls: 'fc-border-separate',
13850 style : 'width:100%',
13858 cls : 'fc-first fc-last',
13876 cls : 'fc-content',
13877 style : "position: relative;",
13880 cls : 'fc-view fc-view-month fc-grid',
13881 style : 'position: relative',
13882 unselectable : 'on',
13885 cls : 'fc-event-container',
13886 style : 'position:absolute;z-index:8;top:0;left:0;'
13904 initEvents : function()
13907 throw "can not find store for calendar";
13913 style: "text-align:center",
13917 style: "background-color:white;width:50%;margin:250 auto",
13921 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13932 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13934 var size = this.el.select('.fc-content', true).first().getSize();
13935 this.maskEl.setSize(size.width, size.height);
13936 this.maskEl.enableDisplayMode("block");
13937 if(!this.loadMask){
13938 this.maskEl.hide();
13941 this.store = Roo.factory(this.store, Roo.data);
13942 this.store.on('load', this.onLoad, this);
13943 this.store.on('beforeload', this.onBeforeLoad, this);
13947 this.cells = this.el.select('.fc-day',true);
13948 //Roo.log(this.cells);
13949 this.textNodes = this.el.query('.fc-day-number');
13950 this.cells.addClassOnOver('fc-state-hover');
13952 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13953 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13954 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13955 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13957 this.on('monthchange', this.onMonthChange, this);
13959 this.update(new Date().clearTime());
13962 resize : function() {
13963 var sz = this.el.getSize();
13965 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13966 this.el.select('.fc-day-content div',true).setHeight(34);
13971 showPrevMonth : function(e){
13972 this.update(this.activeDate.add("mo", -1));
13974 showToday : function(e){
13975 this.update(new Date().clearTime());
13978 showNextMonth : function(e){
13979 this.update(this.activeDate.add("mo", 1));
13983 showPrevYear : function(){
13984 this.update(this.activeDate.add("y", -1));
13988 showNextYear : function(){
13989 this.update(this.activeDate.add("y", 1));
13994 update : function(date)
13996 var vd = this.activeDate;
13997 this.activeDate = date;
13998 // if(vd && this.el){
13999 // var t = date.getTime();
14000 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14001 // Roo.log('using add remove');
14003 // this.fireEvent('monthchange', this, date);
14005 // this.cells.removeClass("fc-state-highlight");
14006 // this.cells.each(function(c){
14007 // if(c.dateValue == t){
14008 // c.addClass("fc-state-highlight");
14009 // setTimeout(function(){
14010 // try{c.dom.firstChild.focus();}catch(e){}
14020 var days = date.getDaysInMonth();
14022 var firstOfMonth = date.getFirstDateOfMonth();
14023 var startingPos = firstOfMonth.getDay()-this.startDay;
14025 if(startingPos < this.startDay){
14029 var pm = date.add(Date.MONTH, -1);
14030 var prevStart = pm.getDaysInMonth()-startingPos;
14032 this.cells = this.el.select('.fc-day',true);
14033 this.textNodes = this.el.query('.fc-day-number');
14034 this.cells.addClassOnOver('fc-state-hover');
14036 var cells = this.cells.elements;
14037 var textEls = this.textNodes;
14039 Roo.each(cells, function(cell){
14040 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14043 days += startingPos;
14045 // convert everything to numbers so it's fast
14046 var day = 86400000;
14047 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14050 //Roo.log(prevStart);
14052 var today = new Date().clearTime().getTime();
14053 var sel = date.clearTime().getTime();
14054 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14055 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14056 var ddMatch = this.disabledDatesRE;
14057 var ddText = this.disabledDatesText;
14058 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14059 var ddaysText = this.disabledDaysText;
14060 var format = this.format;
14062 var setCellClass = function(cal, cell){
14066 //Roo.log('set Cell Class');
14068 var t = d.getTime();
14072 cell.dateValue = t;
14074 cell.className += " fc-today";
14075 cell.className += " fc-state-highlight";
14076 cell.title = cal.todayText;
14079 // disable highlight in other month..
14080 //cell.className += " fc-state-highlight";
14085 cell.className = " fc-state-disabled";
14086 cell.title = cal.minText;
14090 cell.className = " fc-state-disabled";
14091 cell.title = cal.maxText;
14095 if(ddays.indexOf(d.getDay()) != -1){
14096 cell.title = ddaysText;
14097 cell.className = " fc-state-disabled";
14100 if(ddMatch && format){
14101 var fvalue = d.dateFormat(format);
14102 if(ddMatch.test(fvalue)){
14103 cell.title = ddText.replace("%0", fvalue);
14104 cell.className = " fc-state-disabled";
14108 if (!cell.initialClassName) {
14109 cell.initialClassName = cell.dom.className;
14112 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14117 for(; i < startingPos; i++) {
14118 textEls[i].innerHTML = (++prevStart);
14119 d.setDate(d.getDate()+1);
14121 cells[i].className = "fc-past fc-other-month";
14122 setCellClass(this, cells[i]);
14127 for(; i < days; i++){
14128 intDay = i - startingPos + 1;
14129 textEls[i].innerHTML = (intDay);
14130 d.setDate(d.getDate()+1);
14132 cells[i].className = ''; // "x-date-active";
14133 setCellClass(this, cells[i]);
14137 for(; i < 42; i++) {
14138 textEls[i].innerHTML = (++extraDays);
14139 d.setDate(d.getDate()+1);
14141 cells[i].className = "fc-future fc-other-month";
14142 setCellClass(this, cells[i]);
14145 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14147 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14149 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14150 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14152 if(totalRows != 6){
14153 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14154 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14157 this.fireEvent('monthchange', this, date);
14161 if(!this.internalRender){
14162 var main = this.el.dom.firstChild;
14163 var w = main.offsetWidth;
14164 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14165 Roo.fly(main).setWidth(w);
14166 this.internalRender = true;
14167 // opera does not respect the auto grow header center column
14168 // then, after it gets a width opera refuses to recalculate
14169 // without a second pass
14170 if(Roo.isOpera && !this.secondPass){
14171 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14172 this.secondPass = true;
14173 this.update.defer(10, this, [date]);
14180 findCell : function(dt) {
14181 dt = dt.clearTime().getTime();
14183 this.cells.each(function(c){
14184 //Roo.log("check " +c.dateValue + '?=' + dt);
14185 if(c.dateValue == dt){
14195 findCells : function(ev) {
14196 var s = ev.start.clone().clearTime().getTime();
14198 var e= ev.end.clone().clearTime().getTime();
14201 this.cells.each(function(c){
14202 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14204 if(c.dateValue > e){
14207 if(c.dateValue < s){
14216 // findBestRow: function(cells)
14220 // for (var i =0 ; i < cells.length;i++) {
14221 // ret = Math.max(cells[i].rows || 0,ret);
14228 addItem : function(ev)
14230 // look for vertical location slot in
14231 var cells = this.findCells(ev);
14233 // ev.row = this.findBestRow(cells);
14235 // work out the location.
14239 for(var i =0; i < cells.length; i++) {
14241 cells[i].row = cells[0].row;
14244 cells[i].row = cells[i].row + 1;
14254 if (crow.start.getY() == cells[i].getY()) {
14256 crow.end = cells[i];
14273 cells[0].events.push(ev);
14275 this.calevents.push(ev);
14278 clearEvents: function() {
14280 if(!this.calevents){
14284 Roo.each(this.cells.elements, function(c){
14290 Roo.each(this.calevents, function(e) {
14291 Roo.each(e.els, function(el) {
14292 el.un('mouseenter' ,this.onEventEnter, this);
14293 el.un('mouseleave' ,this.onEventLeave, this);
14298 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14304 renderEvents: function()
14308 this.cells.each(function(c) {
14317 if(c.row != c.events.length){
14318 r = 4 - (4 - (c.row - c.events.length));
14321 c.events = ev.slice(0, r);
14322 c.more = ev.slice(r);
14324 if(c.more.length && c.more.length == 1){
14325 c.events.push(c.more.pop());
14328 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14332 this.cells.each(function(c) {
14334 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14337 for (var e = 0; e < c.events.length; e++){
14338 var ev = c.events[e];
14339 var rows = ev.rows;
14341 for(var i = 0; i < rows.length; i++) {
14343 // how many rows should it span..
14346 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14347 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14349 unselectable : "on",
14352 cls: 'fc-event-inner',
14356 // cls: 'fc-event-time',
14357 // html : cells.length > 1 ? '' : ev.time
14361 cls: 'fc-event-title',
14362 html : String.format('{0}', ev.title)
14369 cls: 'ui-resizable-handle ui-resizable-e',
14370 html : '  '
14377 cfg.cls += ' fc-event-start';
14379 if ((i+1) == rows.length) {
14380 cfg.cls += ' fc-event-end';
14383 var ctr = _this.el.select('.fc-event-container',true).first();
14384 var cg = ctr.createChild(cfg);
14386 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14387 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14389 var r = (c.more.length) ? 1 : 0;
14390 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14391 cg.setWidth(ebox.right - sbox.x -2);
14393 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14394 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14395 cg.on('click', _this.onEventClick, _this, ev);
14406 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14407 style : 'position: absolute',
14408 unselectable : "on",
14411 cls: 'fc-event-inner',
14415 cls: 'fc-event-title',
14423 cls: 'ui-resizable-handle ui-resizable-e',
14424 html : '  '
14430 var ctr = _this.el.select('.fc-event-container',true).first();
14431 var cg = ctr.createChild(cfg);
14433 var sbox = c.select('.fc-day-content',true).first().getBox();
14434 var ebox = c.select('.fc-day-content',true).first().getBox();
14436 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14437 cg.setWidth(ebox.right - sbox.x -2);
14439 cg.on('click', _this.onMoreEventClick, _this, c.more);
14449 onEventEnter: function (e, el,event,d) {
14450 this.fireEvent('evententer', this, el, event);
14453 onEventLeave: function (e, el,event,d) {
14454 this.fireEvent('eventleave', this, el, event);
14457 onEventClick: function (e, el,event,d) {
14458 this.fireEvent('eventclick', this, el, event);
14461 onMonthChange: function () {
14465 onMoreEventClick: function(e, el, more)
14469 this.calpopover.placement = 'right';
14470 this.calpopover.setTitle('More');
14472 this.calpopover.setContent('');
14474 var ctr = this.calpopover.el.select('.popover-content', true).first();
14476 Roo.each(more, function(m){
14478 cls : 'fc-event-hori fc-event-draggable',
14481 var cg = ctr.createChild(cfg);
14483 cg.on('click', _this.onEventClick, _this, m);
14486 this.calpopover.show(el);
14491 onLoad: function ()
14493 this.calevents = [];
14496 if(this.store.getCount() > 0){
14497 this.store.data.each(function(d){
14500 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14501 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14502 time : d.data.start_time,
14503 title : d.data.title,
14504 description : d.data.description,
14505 venue : d.data.venue
14510 this.renderEvents();
14512 if(this.calevents.length && this.loadMask){
14513 this.maskEl.hide();
14517 onBeforeLoad: function()
14519 this.clearEvents();
14521 this.maskEl.show();
14535 * @class Roo.bootstrap.Popover
14536 * @extends Roo.bootstrap.Component
14537 * Bootstrap Popover class
14538 * @cfg {String} html contents of the popover (or false to use children..)
14539 * @cfg {String} title of popover (or false to hide)
14540 * @cfg {String} placement how it is placed
14541 * @cfg {String} trigger click || hover (or false to trigger manually)
14542 * @cfg {String} over what (parent or false to trigger manually.)
14543 * @cfg {Number} delay - delay before showing
14546 * Create a new Popover
14547 * @param {Object} config The config object
14550 Roo.bootstrap.Popover = function(config){
14551 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14554 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14556 title: 'Fill in a title',
14559 placement : 'right',
14560 trigger : 'hover', // hover
14566 can_build_overlaid : false,
14568 getChildContainer : function()
14570 return this.el.select('.popover-content',true).first();
14573 getAutoCreate : function(){
14574 Roo.log('make popover?');
14576 cls : 'popover roo-dynamic',
14577 style: 'display:block',
14583 cls : 'popover-inner',
14587 cls: 'popover-title',
14591 cls : 'popover-content',
14602 setTitle: function(str)
14604 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14606 setContent: function(str)
14608 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14610 // as it get's added to the bottom of the page.
14611 onRender : function(ct, position)
14613 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14615 var cfg = Roo.apply({}, this.getAutoCreate());
14619 cfg.cls += ' ' + this.cls;
14622 cfg.style = this.style;
14624 Roo.log("adding to ")
14625 this.el = Roo.get(document.body).createChild(cfg, position);
14631 initEvents : function()
14633 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14634 this.el.enableDisplayMode('block');
14636 if (this.over === false) {
14639 if (this.triggers === false) {
14642 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14643 var triggers = this.trigger ? this.trigger.split(' ') : [];
14644 Roo.each(triggers, function(trigger) {
14646 if (trigger == 'click') {
14647 on_el.on('click', this.toggle, this);
14648 } else if (trigger != 'manual') {
14649 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14650 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14652 on_el.on(eventIn ,this.enter, this);
14653 on_el.on(eventOut, this.leave, this);
14664 toggle : function () {
14665 this.hoverState == 'in' ? this.leave() : this.enter();
14668 enter : function () {
14671 clearTimeout(this.timeout);
14673 this.hoverState = 'in';
14675 if (!this.delay || !this.delay.show) {
14680 this.timeout = setTimeout(function () {
14681 if (_t.hoverState == 'in') {
14684 }, this.delay.show)
14686 leave : function() {
14687 clearTimeout(this.timeout);
14689 this.hoverState = 'out';
14691 if (!this.delay || !this.delay.hide) {
14696 this.timeout = setTimeout(function () {
14697 if (_t.hoverState == 'out') {
14700 }, this.delay.hide)
14703 show : function (on_el)
14706 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14709 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14710 if (this.html !== false) {
14711 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14713 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14714 if (!this.title.length) {
14715 this.el.select('.popover-title',true).hide();
14718 var placement = typeof this.placement == 'function' ?
14719 this.placement.call(this, this.el, on_el) :
14722 var autoToken = /\s?auto?\s?/i;
14723 var autoPlace = autoToken.test(placement);
14725 placement = placement.replace(autoToken, '') || 'top';
14729 //this.el.setXY([0,0]);
14731 this.el.dom.style.display='block';
14732 this.el.addClass(placement);
14734 //this.el.appendTo(on_el);
14736 var p = this.getPosition();
14737 var box = this.el.getBox();
14742 var align = Roo.bootstrap.Popover.alignment[placement];
14743 this.el.alignTo(on_el, align[0],align[1]);
14744 //var arrow = this.el.select('.arrow',true).first();
14745 //arrow.set(align[2],
14747 this.el.addClass('in');
14748 this.hoverState = null;
14750 if (this.el.hasClass('fade')) {
14757 this.el.setXY([0,0]);
14758 this.el.removeClass('in');
14765 Roo.bootstrap.Popover.alignment = {
14766 'left' : ['r-l', [-10,0], 'right'],
14767 'right' : ['l-r', [10,0], 'left'],
14768 'bottom' : ['t-b', [0,10], 'top'],
14769 'top' : [ 'b-t', [0,-10], 'bottom']
14780 * @class Roo.bootstrap.Progress
14781 * @extends Roo.bootstrap.Component
14782 * Bootstrap Progress class
14783 * @cfg {Boolean} striped striped of the progress bar
14784 * @cfg {Boolean} active animated of the progress bar
14788 * Create a new Progress
14789 * @param {Object} config The config object
14792 Roo.bootstrap.Progress = function(config){
14793 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14796 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14801 getAutoCreate : function(){
14809 cfg.cls += ' progress-striped';
14813 cfg.cls += ' active';
14832 * @class Roo.bootstrap.ProgressBar
14833 * @extends Roo.bootstrap.Component
14834 * Bootstrap ProgressBar class
14835 * @cfg {Number} aria_valuenow aria-value now
14836 * @cfg {Number} aria_valuemin aria-value min
14837 * @cfg {Number} aria_valuemax aria-value max
14838 * @cfg {String} label label for the progress bar
14839 * @cfg {String} panel (success | info | warning | danger )
14840 * @cfg {String} role role of the progress bar
14841 * @cfg {String} sr_only text
14845 * Create a new ProgressBar
14846 * @param {Object} config The config object
14849 Roo.bootstrap.ProgressBar = function(config){
14850 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14853 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14857 aria_valuemax : 100,
14863 getAutoCreate : function()
14868 cls: 'progress-bar',
14869 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14881 cfg.role = this.role;
14884 if(this.aria_valuenow){
14885 cfg['aria-valuenow'] = this.aria_valuenow;
14888 if(this.aria_valuemin){
14889 cfg['aria-valuemin'] = this.aria_valuemin;
14892 if(this.aria_valuemax){
14893 cfg['aria-valuemax'] = this.aria_valuemax;
14896 if(this.label && !this.sr_only){
14897 cfg.html = this.label;
14901 cfg.cls += ' progress-bar-' + this.panel;
14907 update : function(aria_valuenow)
14909 this.aria_valuenow = aria_valuenow;
14911 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14926 * @class Roo.bootstrap.TabGroup
14927 * @extends Roo.bootstrap.Column
14928 * Bootstrap Column class
14929 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14930 * @cfg {Boolean} carousel true to make the group behave like a carousel
14931 * @cfg {Number} bullets show the panel pointer.. default 0
14932 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14933 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14934 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14937 * Create a new TabGroup
14938 * @param {Object} config The config object
14941 Roo.bootstrap.TabGroup = function(config){
14942 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14944 this.navId = Roo.id();
14947 Roo.bootstrap.TabGroup.register(this);
14951 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14954 transition : false,
14959 slideOnTouch : false,
14961 getAutoCreate : function()
14963 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14965 cfg.cls += ' tab-content';
14967 Roo.log('get auto create...............');
14969 if (this.carousel) {
14970 cfg.cls += ' carousel slide';
14973 cls : 'carousel-inner'
14976 if(this.bullets > 0 && !Roo.isTouch){
14979 cls : 'carousel-bullets',
14983 if(this.bullets_cls){
14984 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14987 for (var i = 0; i < this.bullets; i++){
14989 cls : 'bullet bullet-' + i
14997 cfg.cn[0].cn = bullets;
15004 initEvents: function()
15006 Roo.log('-------- init events on tab group ---------');
15008 if(this.bullets > 0 && !Roo.isTouch){
15014 if(Roo.isTouch && this.slideOnTouch){
15015 this.el.on("touchstart", this.onTouchStart, this);
15018 if(this.autoslide){
15021 this.slideFn = window.setInterval(function() {
15022 _this.showPanelNext();
15028 onTouchStart : function(e, el, o)
15030 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15034 this.showPanelNext();
15037 getChildContainer : function()
15039 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15043 * register a Navigation item
15044 * @param {Roo.bootstrap.NavItem} the navitem to add
15046 register : function(item)
15048 this.tabs.push( item);
15049 item.navId = this.navId; // not really needed..
15053 getActivePanel : function()
15056 Roo.each(this.tabs, function(t) {
15066 getPanelByName : function(n)
15069 Roo.each(this.tabs, function(t) {
15070 if (t.tabId == n) {
15078 indexOfPanel : function(p)
15081 Roo.each(this.tabs, function(t,i) {
15082 if (t.tabId == p.tabId) {
15091 * show a specific panel
15092 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15093 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15095 showPanel : function (pan)
15097 if(this.transition){
15098 Roo.log("waiting for the transitionend");
15102 if (typeof(pan) == 'number') {
15103 pan = this.tabs[pan];
15105 if (typeof(pan) == 'string') {
15106 pan = this.getPanelByName(pan);
15108 if (pan.tabId == this.getActivePanel().tabId) {
15111 var cur = this.getActivePanel();
15113 if (false === cur.fireEvent('beforedeactivate')) {
15117 if(this.bullets > 0 && !Roo.isTouch){
15118 this.setActiveBullet(this.indexOfPanel(pan));
15121 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15123 this.transition = true;
15124 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15125 var lr = dir == 'next' ? 'left' : 'right';
15126 pan.el.addClass(dir); // or prev
15127 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15128 cur.el.addClass(lr); // or right
15129 pan.el.addClass(lr);
15132 cur.el.on('transitionend', function() {
15133 Roo.log("trans end?");
15135 pan.el.removeClass([lr,dir]);
15136 pan.setActive(true);
15138 cur.el.removeClass([lr]);
15139 cur.setActive(false);
15141 _this.transition = false;
15143 }, this, { single: true } );
15148 cur.setActive(false);
15149 pan.setActive(true);
15154 showPanelNext : function()
15156 var i = this.indexOfPanel(this.getActivePanel());
15158 if (i >= this.tabs.length - 1 && !this.autoslide) {
15162 if (i >= this.tabs.length - 1 && this.autoslide) {
15166 this.showPanel(this.tabs[i+1]);
15169 showPanelPrev : function()
15171 var i = this.indexOfPanel(this.getActivePanel());
15173 if (i < 1 && !this.autoslide) {
15177 if (i < 1 && this.autoslide) {
15178 i = this.tabs.length;
15181 this.showPanel(this.tabs[i-1]);
15184 initBullet : function()
15192 for (var i = 0; i < this.bullets; i++){
15193 var bullet = this.el.select('.bullet-' + i, true).first();
15199 bullet.on('click', (function(e, el, o, ii, t){
15201 e.preventDefault();
15203 _this.showPanel(ii);
15205 if(_this.autoslide && _this.slideFn){
15206 clearInterval(_this.slideFn);
15207 _this.slideFn = window.setInterval(function() {
15208 _this.showPanelNext();
15212 }).createDelegate(this, [i, bullet], true));
15216 setActiveBullet : function(i)
15222 Roo.each(this.el.select('.bullet', true).elements, function(el){
15223 el.removeClass('selected');
15226 var bullet = this.el.select('.bullet-' + i, true).first();
15232 bullet.addClass('selected');
15243 Roo.apply(Roo.bootstrap.TabGroup, {
15247 * register a Navigation Group
15248 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15250 register : function(navgrp)
15252 this.groups[navgrp.navId] = navgrp;
15256 * fetch a Navigation Group based on the navigation ID
15257 * if one does not exist , it will get created.
15258 * @param {string} the navgroup to add
15259 * @returns {Roo.bootstrap.NavGroup} the navgroup
15261 get: function(navId) {
15262 if (typeof(this.groups[navId]) == 'undefined') {
15263 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15265 return this.groups[navId] ;
15280 * @class Roo.bootstrap.TabPanel
15281 * @extends Roo.bootstrap.Component
15282 * Bootstrap TabPanel class
15283 * @cfg {Boolean} active panel active
15284 * @cfg {String} html panel content
15285 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15286 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15290 * Create a new TabPanel
15291 * @param {Object} config The config object
15294 Roo.bootstrap.TabPanel = function(config){
15295 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15299 * Fires when the active status changes
15300 * @param {Roo.bootstrap.TabPanel} this
15301 * @param {Boolean} state the new state
15306 * @event beforedeactivate
15307 * Fires before a tab is de-activated - can be used to do validation on a form.
15308 * @param {Roo.bootstrap.TabPanel} this
15309 * @return {Boolean} false if there is an error
15312 'beforedeactivate': true
15315 this.tabId = this.tabId || Roo.id();
15319 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15326 getAutoCreate : function(){
15329 // item is needed for carousel - not sure if it has any effect otherwise
15330 cls: 'tab-pane item',
15331 html: this.html || ''
15335 cfg.cls += ' active';
15339 cfg.tabId = this.tabId;
15346 initEvents: function()
15348 Roo.log('-------- init events on tab panel ---------');
15350 var p = this.parent();
15351 this.navId = this.navId || p.navId;
15353 if (typeof(this.navId) != 'undefined') {
15354 // not really needed.. but just in case.. parent should be a NavGroup.
15355 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15356 Roo.log(['register', tg, this]);
15359 var i = tg.tabs.length - 1;
15361 if(this.active && tg.bullets > 0 && i < tg.bullets){
15362 tg.setActiveBullet(i);
15369 onRender : function(ct, position)
15371 // Roo.log("Call onRender: " + this.xtype);
15373 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15381 setActive: function(state)
15383 Roo.log("panel - set active " + this.tabId + "=" + state);
15385 this.active = state;
15387 this.el.removeClass('active');
15389 } else if (!this.el.hasClass('active')) {
15390 this.el.addClass('active');
15393 this.fireEvent('changed', this, state);
15410 * @class Roo.bootstrap.DateField
15411 * @extends Roo.bootstrap.Input
15412 * Bootstrap DateField class
15413 * @cfg {Number} weekStart default 0
15414 * @cfg {String} viewMode default empty, (months|years)
15415 * @cfg {String} minViewMode default empty, (months|years)
15416 * @cfg {Number} startDate default -Infinity
15417 * @cfg {Number} endDate default Infinity
15418 * @cfg {Boolean} todayHighlight default false
15419 * @cfg {Boolean} todayBtn default false
15420 * @cfg {Boolean} calendarWeeks default false
15421 * @cfg {Object} daysOfWeekDisabled default empty
15422 * @cfg {Boolean} singleMode default false (true | false)
15424 * @cfg {Boolean} keyboardNavigation default true
15425 * @cfg {String} language default en
15428 * Create a new DateField
15429 * @param {Object} config The config object
15432 Roo.bootstrap.DateField = function(config){
15433 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15437 * Fires when this field show.
15438 * @param {Roo.bootstrap.DateField} this
15439 * @param {Mixed} date The date value
15444 * Fires when this field hide.
15445 * @param {Roo.bootstrap.DateField} this
15446 * @param {Mixed} date The date value
15451 * Fires when select a date.
15452 * @param {Roo.bootstrap.DateField} this
15453 * @param {Mixed} date The date value
15459 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15462 * @cfg {String} format
15463 * The default date format string which can be overriden for localization support. The format must be
15464 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15468 * @cfg {String} altFormats
15469 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15470 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15472 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15480 todayHighlight : false,
15486 keyboardNavigation: true,
15488 calendarWeeks: false,
15490 startDate: -Infinity,
15494 daysOfWeekDisabled: [],
15498 singleMode : false,
15500 UTCDate: function()
15502 return new Date(Date.UTC.apply(Date, arguments));
15505 UTCToday: function()
15507 var today = new Date();
15508 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15511 getDate: function() {
15512 var d = this.getUTCDate();
15513 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15516 getUTCDate: function() {
15520 setDate: function(d) {
15521 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15524 setUTCDate: function(d) {
15526 this.setValue(this.formatDate(this.date));
15529 onRender: function(ct, position)
15532 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15534 this.language = this.language || 'en';
15535 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15536 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15538 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15539 this.format = this.format || 'm/d/y';
15540 this.isInline = false;
15541 this.isInput = true;
15542 this.component = this.el.select('.add-on', true).first() || false;
15543 this.component = (this.component && this.component.length === 0) ? false : this.component;
15544 this.hasInput = this.component && this.inputEL().length;
15546 if (typeof(this.minViewMode === 'string')) {
15547 switch (this.minViewMode) {
15549 this.minViewMode = 1;
15552 this.minViewMode = 2;
15555 this.minViewMode = 0;
15560 if (typeof(this.viewMode === 'string')) {
15561 switch (this.viewMode) {
15574 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15576 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15578 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15580 this.picker().on('mousedown', this.onMousedown, this);
15581 this.picker().on('click', this.onClick, this);
15583 this.picker().addClass('datepicker-dropdown');
15585 this.startViewMode = this.viewMode;
15587 if(this.singleMode){
15588 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15589 v.setVisibilityMode(Roo.Element.DISPLAY)
15593 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15594 v.setStyle('width', '189px');
15598 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15599 if(!this.calendarWeeks){
15604 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15605 v.attr('colspan', function(i, val){
15606 return parseInt(val) + 1;
15611 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15613 this.setStartDate(this.startDate);
15614 this.setEndDate(this.endDate);
15616 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15623 if(this.isInline) {
15628 picker : function()
15630 return this.pickerEl;
15631 // return this.el.select('.datepicker', true).first();
15634 fillDow: function()
15636 var dowCnt = this.weekStart;
15645 if(this.calendarWeeks){
15653 while (dowCnt < this.weekStart + 7) {
15657 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15661 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15664 fillMonths: function()
15667 var months = this.picker().select('>.datepicker-months td', true).first();
15669 months.dom.innerHTML = '';
15675 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15678 months.createChild(month);
15685 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;
15687 if (this.date < this.startDate) {
15688 this.viewDate = new Date(this.startDate);
15689 } else if (this.date > this.endDate) {
15690 this.viewDate = new Date(this.endDate);
15692 this.viewDate = new Date(this.date);
15700 var d = new Date(this.viewDate),
15701 year = d.getUTCFullYear(),
15702 month = d.getUTCMonth(),
15703 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15704 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15705 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15706 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15707 currentDate = this.date && this.date.valueOf(),
15708 today = this.UTCToday();
15710 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15712 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15714 // this.picker.select('>tfoot th.today').
15715 // .text(dates[this.language].today)
15716 // .toggle(this.todayBtn !== false);
15718 this.updateNavArrows();
15721 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15723 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15725 prevMonth.setUTCDate(day);
15727 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15729 var nextMonth = new Date(prevMonth);
15731 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15733 nextMonth = nextMonth.valueOf();
15735 var fillMonths = false;
15737 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15739 while(prevMonth.valueOf() < nextMonth) {
15742 if (prevMonth.getUTCDay() === this.weekStart) {
15744 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15752 if(this.calendarWeeks){
15753 // ISO 8601: First week contains first thursday.
15754 // ISO also states week starts on Monday, but we can be more abstract here.
15756 // Start of current week: based on weekstart/current date
15757 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15758 // Thursday of this week
15759 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15760 // First Thursday of year, year from thursday
15761 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15762 // Calendar week: ms between thursdays, div ms per day, div 7 days
15763 calWeek = (th - yth) / 864e5 / 7 + 1;
15765 fillMonths.cn.push({
15773 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15775 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15778 if (this.todayHighlight &&
15779 prevMonth.getUTCFullYear() == today.getFullYear() &&
15780 prevMonth.getUTCMonth() == today.getMonth() &&
15781 prevMonth.getUTCDate() == today.getDate()) {
15782 clsName += ' today';
15785 if (currentDate && prevMonth.valueOf() === currentDate) {
15786 clsName += ' active';
15789 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15790 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15791 clsName += ' disabled';
15794 fillMonths.cn.push({
15796 cls: 'day ' + clsName,
15797 html: prevMonth.getDate()
15800 prevMonth.setDate(prevMonth.getDate()+1);
15803 var currentYear = this.date && this.date.getUTCFullYear();
15804 var currentMonth = this.date && this.date.getUTCMonth();
15806 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15808 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15809 v.removeClass('active');
15811 if(currentYear === year && k === currentMonth){
15812 v.addClass('active');
15815 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15816 v.addClass('disabled');
15822 year = parseInt(year/10, 10) * 10;
15824 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15826 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15829 for (var i = -1; i < 11; i++) {
15830 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15832 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15840 showMode: function(dir)
15843 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15846 Roo.each(this.picker().select('>div',true).elements, function(v){
15847 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15850 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15855 if(this.isInline) return;
15857 this.picker().removeClass(['bottom', 'top']);
15859 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15861 * place to the top of element!
15865 this.picker().addClass('top');
15866 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15871 this.picker().addClass('bottom');
15873 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15876 parseDate : function(value)
15878 if(!value || value instanceof Date){
15881 var v = Date.parseDate(value, this.format);
15882 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15883 v = Date.parseDate(value, 'Y-m-d');
15885 if(!v && this.altFormats){
15886 if(!this.altFormatsArray){
15887 this.altFormatsArray = this.altFormats.split("|");
15889 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15890 v = Date.parseDate(value, this.altFormatsArray[i]);
15896 formatDate : function(date, fmt)
15898 return (!date || !(date instanceof Date)) ?
15899 date : date.dateFormat(fmt || this.format);
15902 onFocus : function()
15904 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15908 onBlur : function()
15910 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15912 var d = this.inputEl().getValue();
15921 this.picker().show();
15925 this.fireEvent('show', this, this.date);
15930 if(this.isInline) return;
15931 this.picker().hide();
15932 this.viewMode = this.startViewMode;
15935 this.fireEvent('hide', this, this.date);
15939 onMousedown: function(e)
15941 e.stopPropagation();
15942 e.preventDefault();
15947 Roo.bootstrap.DateField.superclass.keyup.call(this);
15951 setValue: function(v)
15954 // v can be a string or a date..
15957 var d = new Date(this.parseDate(v) ).clearTime();
15959 if(isNaN(d.getTime())){
15960 this.date = this.viewDate = '';
15961 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15965 v = this.formatDate(d);
15967 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15969 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15973 this.fireEvent('select', this, this.date);
15977 getValue: function()
15979 return this.formatDate(this.date);
15982 fireKey: function(e)
15984 if (!this.picker().isVisible()){
15985 if (e.keyCode == 27) // allow escape to hide and re-show picker
15990 var dateChanged = false,
15992 newDate, newViewDate;
15997 e.preventDefault();
16001 if (!this.keyboardNavigation) break;
16002 dir = e.keyCode == 37 ? -1 : 1;
16005 newDate = this.moveYear(this.date, dir);
16006 newViewDate = this.moveYear(this.viewDate, dir);
16007 } else if (e.shiftKey){
16008 newDate = this.moveMonth(this.date, dir);
16009 newViewDate = this.moveMonth(this.viewDate, dir);
16011 newDate = new Date(this.date);
16012 newDate.setUTCDate(this.date.getUTCDate() + dir);
16013 newViewDate = new Date(this.viewDate);
16014 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16016 if (this.dateWithinRange(newDate)){
16017 this.date = newDate;
16018 this.viewDate = newViewDate;
16019 this.setValue(this.formatDate(this.date));
16021 e.preventDefault();
16022 dateChanged = true;
16027 if (!this.keyboardNavigation) break;
16028 dir = e.keyCode == 38 ? -1 : 1;
16030 newDate = this.moveYear(this.date, dir);
16031 newViewDate = this.moveYear(this.viewDate, dir);
16032 } else if (e.shiftKey){
16033 newDate = this.moveMonth(this.date, dir);
16034 newViewDate = this.moveMonth(this.viewDate, dir);
16036 newDate = new Date(this.date);
16037 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16038 newViewDate = new Date(this.viewDate);
16039 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16041 if (this.dateWithinRange(newDate)){
16042 this.date = newDate;
16043 this.viewDate = newViewDate;
16044 this.setValue(this.formatDate(this.date));
16046 e.preventDefault();
16047 dateChanged = true;
16051 this.setValue(this.formatDate(this.date));
16053 e.preventDefault();
16056 this.setValue(this.formatDate(this.date));
16070 onClick: function(e)
16072 e.stopPropagation();
16073 e.preventDefault();
16075 var target = e.getTarget();
16077 if(target.nodeName.toLowerCase() === 'i'){
16078 target = Roo.get(target).dom.parentNode;
16081 var nodeName = target.nodeName;
16082 var className = target.className;
16083 var html = target.innerHTML;
16084 //Roo.log(nodeName);
16086 switch(nodeName.toLowerCase()) {
16088 switch(className) {
16094 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16095 switch(this.viewMode){
16097 this.viewDate = this.moveMonth(this.viewDate, dir);
16101 this.viewDate = this.moveYear(this.viewDate, dir);
16107 var date = new Date();
16108 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16110 this.setValue(this.formatDate(this.date));
16117 if (className.indexOf('disabled') < 0) {
16118 this.viewDate.setUTCDate(1);
16119 if (className.indexOf('month') > -1) {
16120 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16122 var year = parseInt(html, 10) || 0;
16123 this.viewDate.setUTCFullYear(year);
16127 if(this.singleMode){
16128 this.setValue(this.formatDate(this.viewDate));
16139 //Roo.log(className);
16140 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16141 var day = parseInt(html, 10) || 1;
16142 var year = this.viewDate.getUTCFullYear(),
16143 month = this.viewDate.getUTCMonth();
16145 if (className.indexOf('old') > -1) {
16152 } else if (className.indexOf('new') > -1) {
16160 //Roo.log([year,month,day]);
16161 this.date = this.UTCDate(year, month, day,0,0,0,0);
16162 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16164 //Roo.log(this.formatDate(this.date));
16165 this.setValue(this.formatDate(this.date));
16172 setStartDate: function(startDate)
16174 this.startDate = startDate || -Infinity;
16175 if (this.startDate !== -Infinity) {
16176 this.startDate = this.parseDate(this.startDate);
16179 this.updateNavArrows();
16182 setEndDate: function(endDate)
16184 this.endDate = endDate || Infinity;
16185 if (this.endDate !== Infinity) {
16186 this.endDate = this.parseDate(this.endDate);
16189 this.updateNavArrows();
16192 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16194 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16195 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16196 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16198 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16199 return parseInt(d, 10);
16202 this.updateNavArrows();
16205 updateNavArrows: function()
16207 if(this.singleMode){
16211 var d = new Date(this.viewDate),
16212 year = d.getUTCFullYear(),
16213 month = d.getUTCMonth();
16215 Roo.each(this.picker().select('.prev', true).elements, function(v){
16217 switch (this.viewMode) {
16220 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16226 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16233 Roo.each(this.picker().select('.next', true).elements, function(v){
16235 switch (this.viewMode) {
16238 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16244 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16252 moveMonth: function(date, dir)
16254 if (!dir) return date;
16255 var new_date = new Date(date.valueOf()),
16256 day = new_date.getUTCDate(),
16257 month = new_date.getUTCMonth(),
16258 mag = Math.abs(dir),
16260 dir = dir > 0 ? 1 : -1;
16263 // If going back one month, make sure month is not current month
16264 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16266 return new_date.getUTCMonth() == month;
16268 // If going forward one month, make sure month is as expected
16269 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16271 return new_date.getUTCMonth() != new_month;
16273 new_month = month + dir;
16274 new_date.setUTCMonth(new_month);
16275 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16276 if (new_month < 0 || new_month > 11)
16277 new_month = (new_month + 12) % 12;
16279 // For magnitudes >1, move one month at a time...
16280 for (var i=0; i<mag; i++)
16281 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16282 new_date = this.moveMonth(new_date, dir);
16283 // ...then reset the day, keeping it in the new month
16284 new_month = new_date.getUTCMonth();
16285 new_date.setUTCDate(day);
16287 return new_month != new_date.getUTCMonth();
16290 // Common date-resetting loop -- if date is beyond end of month, make it
16293 new_date.setUTCDate(--day);
16294 new_date.setUTCMonth(new_month);
16299 moveYear: function(date, dir)
16301 return this.moveMonth(date, dir*12);
16304 dateWithinRange: function(date)
16306 return date >= this.startDate && date <= this.endDate;
16312 this.picker().remove();
16317 Roo.apply(Roo.bootstrap.DateField, {
16328 html: '<i class="fa fa-arrow-left"/>'
16338 html: '<i class="fa fa-arrow-right"/>'
16380 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16381 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16382 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16383 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16384 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16397 navFnc: 'FullYear',
16402 navFnc: 'FullYear',
16407 Roo.apply(Roo.bootstrap.DateField, {
16411 cls: 'datepicker dropdown-menu roo-dynamic',
16415 cls: 'datepicker-days',
16419 cls: 'table-condensed',
16421 Roo.bootstrap.DateField.head,
16425 Roo.bootstrap.DateField.footer
16432 cls: 'datepicker-months',
16436 cls: 'table-condensed',
16438 Roo.bootstrap.DateField.head,
16439 Roo.bootstrap.DateField.content,
16440 Roo.bootstrap.DateField.footer
16447 cls: 'datepicker-years',
16451 cls: 'table-condensed',
16453 Roo.bootstrap.DateField.head,
16454 Roo.bootstrap.DateField.content,
16455 Roo.bootstrap.DateField.footer
16474 * @class Roo.bootstrap.TimeField
16475 * @extends Roo.bootstrap.Input
16476 * Bootstrap DateField class
16480 * Create a new TimeField
16481 * @param {Object} config The config object
16484 Roo.bootstrap.TimeField = function(config){
16485 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16489 * Fires when this field show.
16490 * @param {Roo.bootstrap.DateField} thisthis
16491 * @param {Mixed} date The date value
16496 * Fires when this field hide.
16497 * @param {Roo.bootstrap.DateField} this
16498 * @param {Mixed} date The date value
16503 * Fires when select a date.
16504 * @param {Roo.bootstrap.DateField} this
16505 * @param {Mixed} date The date value
16511 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16514 * @cfg {String} format
16515 * The default time format string which can be overriden for localization support. The format must be
16516 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16520 onRender: function(ct, position)
16523 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16525 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16527 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16529 this.pop = this.picker().select('>.datepicker-time',true).first();
16530 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16532 this.picker().on('mousedown', this.onMousedown, this);
16533 this.picker().on('click', this.onClick, this);
16535 this.picker().addClass('datepicker-dropdown');
16540 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16541 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16542 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16543 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16544 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16545 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16549 fireKey: function(e){
16550 if (!this.picker().isVisible()){
16551 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16557 e.preventDefault();
16565 this.onTogglePeriod();
16568 this.onIncrementMinutes();
16571 this.onDecrementMinutes();
16580 onClick: function(e) {
16581 e.stopPropagation();
16582 e.preventDefault();
16585 picker : function()
16587 return this.el.select('.datepicker', true).first();
16590 fillTime: function()
16592 var time = this.pop.select('tbody', true).first();
16594 time.dom.innerHTML = '';
16609 cls: 'hours-up glyphicon glyphicon-chevron-up'
16629 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16650 cls: 'timepicker-hour',
16665 cls: 'timepicker-minute',
16680 cls: 'btn btn-primary period',
16702 cls: 'hours-down glyphicon glyphicon-chevron-down'
16722 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16740 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16747 var hours = this.time.getHours();
16748 var minutes = this.time.getMinutes();
16761 hours = hours - 12;
16765 hours = '0' + hours;
16769 minutes = '0' + minutes;
16772 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16773 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16774 this.pop.select('button', true).first().dom.innerHTML = period;
16780 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16782 var cls = ['bottom'];
16784 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16791 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16796 this.picker().addClass(cls.join('-'));
16800 Roo.each(cls, function(c){
16802 _this.picker().setTop(_this.inputEl().getHeight());
16806 _this.picker().setTop(0 - _this.picker().getHeight());
16811 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16815 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16822 onFocus : function()
16824 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16828 onBlur : function()
16830 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16836 this.picker().show();
16841 this.fireEvent('show', this, this.date);
16846 this.picker().hide();
16849 this.fireEvent('hide', this, this.date);
16852 setTime : function()
16855 this.setValue(this.time.format(this.format));
16857 this.fireEvent('select', this, this.date);
16862 onMousedown: function(e){
16863 e.stopPropagation();
16864 e.preventDefault();
16867 onIncrementHours: function()
16869 Roo.log('onIncrementHours');
16870 this.time = this.time.add(Date.HOUR, 1);
16875 onDecrementHours: function()
16877 Roo.log('onDecrementHours');
16878 this.time = this.time.add(Date.HOUR, -1);
16882 onIncrementMinutes: function()
16884 Roo.log('onIncrementMinutes');
16885 this.time = this.time.add(Date.MINUTE, 1);
16889 onDecrementMinutes: function()
16891 Roo.log('onDecrementMinutes');
16892 this.time = this.time.add(Date.MINUTE, -1);
16896 onTogglePeriod: function()
16898 Roo.log('onTogglePeriod');
16899 this.time = this.time.add(Date.HOUR, 12);
16906 Roo.apply(Roo.bootstrap.TimeField, {
16936 cls: 'btn btn-info ok',
16948 Roo.apply(Roo.bootstrap.TimeField, {
16952 cls: 'datepicker dropdown-menu',
16956 cls: 'datepicker-time',
16960 cls: 'table-condensed',
16962 Roo.bootstrap.TimeField.content,
16963 Roo.bootstrap.TimeField.footer
16982 * @class Roo.bootstrap.MonthField
16983 * @extends Roo.bootstrap.Input
16984 * Bootstrap MonthField class
16986 * @cfg {String} language default en
16989 * Create a new MonthField
16990 * @param {Object} config The config object
16993 Roo.bootstrap.MonthField = function(config){
16994 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16999 * Fires when this field show.
17000 * @param {Roo.bootstrap.MonthField} this
17001 * @param {Mixed} date The date value
17006 * Fires when this field hide.
17007 * @param {Roo.bootstrap.MonthField} this
17008 * @param {Mixed} date The date value
17013 * Fires when select a date.
17014 * @param {Roo.bootstrap.MonthField} this
17015 * @param {String} oldvalue The old value
17016 * @param {String} newvalue The new value
17022 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17024 onRender: function(ct, position)
17027 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17029 this.language = this.language || 'en';
17030 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17031 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17033 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17034 this.isInline = false;
17035 this.isInput = true;
17036 this.component = this.el.select('.add-on', true).first() || false;
17037 this.component = (this.component && this.component.length === 0) ? false : this.component;
17038 this.hasInput = this.component && this.inputEL().length;
17040 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17042 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17044 this.picker().on('mousedown', this.onMousedown, this);
17045 this.picker().on('click', this.onClick, this);
17047 this.picker().addClass('datepicker-dropdown');
17049 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17050 v.setStyle('width', '189px');
17057 if(this.isInline) {
17063 setValue: function(v, suppressEvent)
17065 var o = this.getValue();
17067 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17071 if(suppressEvent !== true){
17072 this.fireEvent('select', this, o, v);
17077 getValue: function()
17082 onClick: function(e)
17084 e.stopPropagation();
17085 e.preventDefault();
17087 var target = e.getTarget();
17089 if(target.nodeName.toLowerCase() === 'i'){
17090 target = Roo.get(target).dom.parentNode;
17093 var nodeName = target.nodeName;
17094 var className = target.className;
17095 var html = target.innerHTML;
17097 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17101 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17103 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17109 picker : function()
17111 return this.pickerEl;
17114 fillMonths: function()
17117 var months = this.picker().select('>.datepicker-months td', true).first();
17119 months.dom.innerHTML = '';
17125 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17128 months.createChild(month);
17137 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17138 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17141 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17142 e.removeClass('active');
17144 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17145 e.addClass('active');
17152 if(this.isInline) return;
17154 this.picker().removeClass(['bottom', 'top']);
17156 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17158 * place to the top of element!
17162 this.picker().addClass('top');
17163 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17168 this.picker().addClass('bottom');
17170 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17173 onFocus : function()
17175 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17179 onBlur : function()
17181 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17183 var d = this.inputEl().getValue();
17192 this.picker().show();
17193 this.picker().select('>.datepicker-months', true).first().show();
17197 this.fireEvent('show', this, this.date);
17202 if(this.isInline) return;
17203 this.picker().hide();
17204 this.fireEvent('hide', this, this.date);
17208 onMousedown: function(e)
17210 e.stopPropagation();
17211 e.preventDefault();
17216 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17220 fireKey: function(e)
17222 if (!this.picker().isVisible()){
17223 if (e.keyCode == 27) // allow escape to hide and re-show picker
17233 e.preventDefault();
17237 dir = e.keyCode == 37 ? -1 : 1;
17239 this.vIndex = this.vIndex + dir;
17241 if(this.vIndex < 0){
17245 if(this.vIndex > 11){
17249 if(isNaN(this.vIndex)){
17253 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17259 dir = e.keyCode == 38 ? -1 : 1;
17261 this.vIndex = this.vIndex + dir * 4;
17263 if(this.vIndex < 0){
17267 if(this.vIndex > 11){
17271 if(isNaN(this.vIndex)){
17275 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17280 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17281 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17285 e.preventDefault();
17288 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17289 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17305 this.picker().remove();
17310 Roo.apply(Roo.bootstrap.MonthField, {
17329 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17330 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17335 Roo.apply(Roo.bootstrap.MonthField, {
17339 cls: 'datepicker dropdown-menu roo-dynamic',
17343 cls: 'datepicker-months',
17347 cls: 'table-condensed',
17349 Roo.bootstrap.DateField.content
17369 * @class Roo.bootstrap.CheckBox
17370 * @extends Roo.bootstrap.Input
17371 * Bootstrap CheckBox class
17373 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17374 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17375 * @cfg {String} boxLabel The text that appears beside the checkbox
17376 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17377 * @cfg {Boolean} checked initnal the element
17378 * @cfg {Boolean} inline inline the element (default false)
17379 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17382 * Create a new CheckBox
17383 * @param {Object} config The config object
17386 Roo.bootstrap.CheckBox = function(config){
17387 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17392 * Fires when the element is checked or unchecked.
17393 * @param {Roo.bootstrap.CheckBox} this This input
17394 * @param {Boolean} checked The new checked value
17401 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17403 inputType: 'checkbox',
17411 getAutoCreate : function()
17413 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17419 cfg.cls = 'form-group ' + this.inputType; //input-group
17422 cfg.cls += ' ' + this.inputType + '-inline';
17428 type : this.inputType,
17429 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17430 cls : 'roo-' + this.inputType, //'form-box',
17431 placeholder : this.placeholder || ''
17435 if (this.weight) { // Validity check?
17436 cfg.cls += " " + this.inputType + "-" + this.weight;
17439 if (this.disabled) {
17440 input.disabled=true;
17444 input.checked = this.checked;
17448 input.name = this.name;
17452 input.cls += ' input-' + this.size;
17457 ['xs','sm','md','lg'].map(function(size){
17458 if (settings[size]) {
17459 cfg.cls += ' col-' + size + '-' + settings[size];
17463 var inputblock = input;
17465 if (this.before || this.after) {
17468 cls : 'input-group',
17473 inputblock.cn.push({
17475 cls : 'input-group-addon',
17480 inputblock.cn.push(input);
17483 inputblock.cn.push({
17485 cls : 'input-group-addon',
17492 if (align ==='left' && this.fieldLabel.length) {
17493 Roo.log("left and has label");
17499 cls : 'control-label col-md-' + this.labelWidth,
17500 html : this.fieldLabel
17504 cls : "col-md-" + (12 - this.labelWidth),
17511 } else if ( this.fieldLabel.length) {
17516 tag: this.boxLabel ? 'span' : 'label',
17518 cls: 'control-label box-input-label',
17519 //cls : 'input-group-addon',
17520 html : this.fieldLabel
17530 Roo.log(" no label && no align");
17531 cfg.cn = [ inputblock ] ;
17536 var boxLabelCfg = {
17538 //'for': id, // box label is handled by onclick - so no for...
17540 html: this.boxLabel
17544 boxLabelCfg.tooltip = this.tooltip;
17547 cfg.cn.push(boxLabelCfg);
17557 * return the real input element.
17559 inputEl: function ()
17561 return this.el.select('input.roo-' + this.inputType,true).first();
17564 labelEl: function()
17566 return this.el.select('label.control-label',true).first();
17568 /* depricated... */
17572 return this.labelEl();
17575 initEvents : function()
17577 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17579 this.inputEl().on('click', this.onClick, this);
17581 if (this.boxLabel) {
17582 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17585 this.startValue = this.getValue();
17588 Roo.bootstrap.CheckBox.register(this);
17592 onClick : function()
17594 this.setChecked(!this.checked);
17597 setChecked : function(state,suppressEvent)
17599 this.startValue = this.getValue();
17601 if(this.inputType == 'radio'){
17603 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17604 e.dom.checked = false;
17607 this.inputEl().dom.checked = true;
17609 this.inputEl().dom.value = this.inputValue;
17611 if(suppressEvent !== true){
17612 this.fireEvent('check', this, true);
17620 this.checked = state;
17622 this.inputEl().dom.checked = state;
17624 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17626 if(suppressEvent !== true){
17627 this.fireEvent('check', this, state);
17633 getValue : function()
17635 if(this.inputType == 'radio'){
17636 return this.getGroupValue();
17639 return this.inputEl().getValue();
17643 getGroupValue : function()
17645 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17649 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17652 setValue : function(v,suppressEvent)
17654 if(this.inputType == 'radio'){
17655 this.setGroupValue(v, suppressEvent);
17659 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17664 setGroupValue : function(v, suppressEvent)
17666 this.startValue = this.getValue();
17668 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17669 e.dom.checked = false;
17671 if(e.dom.value == v){
17672 e.dom.checked = true;
17676 if(suppressEvent !== true){
17677 this.fireEvent('check', this, true);
17685 validate : function()
17689 (this.inputType == 'radio' && this.validateRadio()) ||
17690 (this.inputType == 'checkbox' && this.validateCheckbox())
17696 this.markInvalid();
17700 validateRadio : function()
17704 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17705 if(!e.dom.checked){
17717 validateCheckbox : function()
17720 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17723 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17731 for(var i in group){
17736 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17743 * Mark this field as valid
17745 markValid : function()
17747 if(this.allowBlank){
17753 this.fireEvent('valid', this);
17755 if(this.inputType == 'radio'){
17756 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17757 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17758 e.findParent('.form-group', false, true).addClass(_this.validClass);
17765 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17766 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17770 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17776 for(var i in group){
17777 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17778 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17783 * Mark this field as invalid
17784 * @param {String} msg The validation message
17786 markInvalid : function(msg)
17788 if(this.allowBlank){
17794 this.fireEvent('invalid', this, msg);
17796 if(this.inputType == 'radio'){
17797 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17798 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17799 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17806 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17807 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17811 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17817 for(var i in group){
17818 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17819 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17826 Roo.apply(Roo.bootstrap.CheckBox, {
17831 * register a CheckBox Group
17832 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17834 register : function(checkbox)
17836 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17837 this.groups[checkbox.groupId] = {};
17840 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17844 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17848 * fetch a CheckBox Group based on the group ID
17849 * @param {string} the group ID
17850 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17852 get: function(groupId) {
17853 if (typeof(this.groups[groupId]) == 'undefined') {
17857 return this.groups[groupId] ;
17869 *<div class="radio">
17871 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17872 Option one is this and that—be sure to include why it's great
17879 *<label class="radio-inline">fieldLabel</label>
17880 *<label class="radio-inline">
17881 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17889 * @class Roo.bootstrap.Radio
17890 * @extends Roo.bootstrap.CheckBox
17891 * Bootstrap Radio class
17894 * Create a new Radio
17895 * @param {Object} config The config object
17898 Roo.bootstrap.Radio = function(config){
17899 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17903 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17905 inputType: 'radio',
17909 getAutoCreate : function()
17911 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17912 align = align || 'left'; // default...
17919 tag : this.inline ? 'span' : 'div',
17924 var inline = this.inline ? ' radio-inline' : '';
17928 // does not need for, as we wrap the input with it..
17930 cls : 'control-label box-label' + inline,
17933 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17937 //cls : 'control-label' + inline,
17938 html : this.fieldLabel,
17939 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17948 type : this.inputType,
17949 //value : (!this.checked) ? this.valueOff : this.inputValue,
17950 value : this.inputValue,
17952 placeholder : this.placeholder || '' // ?? needed????
17955 if (this.weight) { // Validity check?
17956 input.cls += " radio-" + this.weight;
17958 if (this.disabled) {
17959 input.disabled=true;
17963 input.checked = this.checked;
17967 input.name = this.name;
17971 input.cls += ' input-' + this.size;
17974 //?? can span's inline have a width??
17977 ['xs','sm','md','lg'].map(function(size){
17978 if (settings[size]) {
17979 cfg.cls += ' col-' + size + '-' + settings[size];
17983 var inputblock = input;
17985 if (this.before || this.after) {
17988 cls : 'input-group',
17993 inputblock.cn.push({
17995 cls : 'input-group-addon',
17999 inputblock.cn.push(input);
18001 inputblock.cn.push({
18003 cls : 'input-group-addon',
18011 if (this.fieldLabel && this.fieldLabel.length) {
18012 cfg.cn.push(fieldLabel);
18015 // normal bootstrap puts the input inside the label.
18016 // however with our styled version - it has to go after the input.
18018 //lbl.cn.push(inputblock);
18022 cls: 'radio' + inline,
18029 cfg.cn.push( lblwrap);
18034 html: this.boxLabel
18043 initEvents : function()
18045 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18047 this.inputEl().on('click', this.onClick, this);
18048 if (this.boxLabel) {
18049 Roo.log('find label')
18050 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18055 inputEl: function ()
18057 return this.el.select('input.roo-radio',true).first();
18059 onClick : function()
18062 this.setChecked(true);
18065 setChecked : function(state,suppressEvent)
18068 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18069 v.dom.checked = false;
18072 Roo.log(this.inputEl().dom);
18073 this.checked = state;
18074 this.inputEl().dom.checked = state;
18076 if(suppressEvent !== true){
18077 this.fireEvent('check', this, state);
18080 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18084 getGroupValue : function()
18087 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18088 if(v.dom.checked == true){
18089 value = v.dom.value;
18097 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18098 * @return {Mixed} value The field value
18100 getValue : function(){
18101 return this.getGroupValue();
18107 //<script type="text/javascript">
18110 * Based Ext JS Library 1.1.1
18111 * Copyright(c) 2006-2007, Ext JS, LLC.
18117 * @class Roo.HtmlEditorCore
18118 * @extends Roo.Component
18119 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18121 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18124 Roo.HtmlEditorCore = function(config){
18127 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18132 * @event initialize
18133 * Fires when the editor is fully initialized (including the iframe)
18134 * @param {Roo.HtmlEditorCore} this
18139 * Fires when the editor is first receives the focus. Any insertion must wait
18140 * until after this event.
18141 * @param {Roo.HtmlEditorCore} this
18145 * @event beforesync
18146 * Fires before the textarea is updated with content from the editor iframe. Return false
18147 * to cancel the sync.
18148 * @param {Roo.HtmlEditorCore} this
18149 * @param {String} html
18153 * @event beforepush
18154 * Fires before the iframe editor is updated with content from the textarea. Return false
18155 * to cancel the push.
18156 * @param {Roo.HtmlEditorCore} this
18157 * @param {String} html
18162 * Fires when the textarea is updated with content from the editor iframe.
18163 * @param {Roo.HtmlEditorCore} this
18164 * @param {String} html
18169 * Fires when the iframe editor is updated with content from the textarea.
18170 * @param {Roo.HtmlEditorCore} this
18171 * @param {String} html
18176 * @event editorevent
18177 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18178 * @param {Roo.HtmlEditorCore} this
18184 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18186 // defaults : white / black...
18187 this.applyBlacklists();
18194 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18198 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18204 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18209 * @cfg {Number} height (in pixels)
18213 * @cfg {Number} width (in pixels)
18218 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18221 stylesheets: false,
18226 // private properties
18227 validationEvent : false,
18229 initialized : false,
18231 sourceEditMode : false,
18232 onFocus : Roo.emptyFn,
18234 hideMode:'offsets',
18238 // blacklist + whitelisted elements..
18245 * Protected method that will not generally be called directly. It
18246 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18247 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18249 getDocMarkup : function(){
18253 // inherit styels from page...??
18254 if (this.stylesheets === false) {
18256 Roo.get(document.head).select('style').each(function(node) {
18257 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18260 Roo.get(document.head).select('link').each(function(node) {
18261 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18264 } else if (!this.stylesheets.length) {
18266 st = '<style type="text/css">' +
18267 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18273 st += '<style type="text/css">' +
18274 'IMG { cursor: pointer } ' +
18278 return '<html><head>' + st +
18279 //<style type="text/css">' +
18280 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18282 ' </head><body class="roo-htmleditor-body"></body></html>';
18286 onRender : function(ct, position)
18289 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18290 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18293 this.el.dom.style.border = '0 none';
18294 this.el.dom.setAttribute('tabIndex', -1);
18295 this.el.addClass('x-hidden hide');
18299 if(Roo.isIE){ // fix IE 1px bogus margin
18300 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18304 this.frameId = Roo.id();
18308 var iframe = this.owner.wrap.createChild({
18310 cls: 'form-control', // bootstrap..
18312 name: this.frameId,
18313 frameBorder : 'no',
18314 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18319 this.iframe = iframe.dom;
18321 this.assignDocWin();
18323 this.doc.designMode = 'on';
18326 this.doc.write(this.getDocMarkup());
18330 var task = { // must defer to wait for browser to be ready
18332 //console.log("run task?" + this.doc.readyState);
18333 this.assignDocWin();
18334 if(this.doc.body || this.doc.readyState == 'complete'){
18336 this.doc.designMode="on";
18340 Roo.TaskMgr.stop(task);
18341 this.initEditor.defer(10, this);
18348 Roo.TaskMgr.start(task);
18353 onResize : function(w, h)
18355 Roo.log('resize: ' +w + ',' + h );
18356 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18360 if(typeof w == 'number'){
18362 this.iframe.style.width = w + 'px';
18364 if(typeof h == 'number'){
18366 this.iframe.style.height = h + 'px';
18368 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18375 * Toggles the editor between standard and source edit mode.
18376 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18378 toggleSourceEdit : function(sourceEditMode){
18380 this.sourceEditMode = sourceEditMode === true;
18382 if(this.sourceEditMode){
18384 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18387 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18388 //this.iframe.className = '';
18391 //this.setSize(this.owner.wrap.getSize());
18392 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18399 * Protected method that will not generally be called directly. If you need/want
18400 * custom HTML cleanup, this is the method you should override.
18401 * @param {String} html The HTML to be cleaned
18402 * return {String} The cleaned HTML
18404 cleanHtml : function(html){
18405 html = String(html);
18406 if(html.length > 5){
18407 if(Roo.isSafari){ // strip safari nonsense
18408 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18411 if(html == ' '){
18418 * HTML Editor -> Textarea
18419 * Protected method that will not generally be called directly. Syncs the contents
18420 * of the editor iframe with the textarea.
18422 syncValue : function(){
18423 if(this.initialized){
18424 var bd = (this.doc.body || this.doc.documentElement);
18425 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18426 var html = bd.innerHTML;
18428 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18429 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18431 html = '<div style="'+m[0]+'">' + html + '</div>';
18434 html = this.cleanHtml(html);
18435 // fix up the special chars.. normaly like back quotes in word...
18436 // however we do not want to do this with chinese..
18437 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18438 var cc = b.charCodeAt();
18440 (cc >= 0x4E00 && cc < 0xA000 ) ||
18441 (cc >= 0x3400 && cc < 0x4E00 ) ||
18442 (cc >= 0xf900 && cc < 0xfb00 )
18448 if(this.owner.fireEvent('beforesync', this, html) !== false){
18449 this.el.dom.value = html;
18450 this.owner.fireEvent('sync', this, html);
18456 * Protected method that will not generally be called directly. Pushes the value of the textarea
18457 * into the iframe editor.
18459 pushValue : function(){
18460 if(this.initialized){
18461 var v = this.el.dom.value.trim();
18463 // if(v.length < 1){
18467 if(this.owner.fireEvent('beforepush', this, v) !== false){
18468 var d = (this.doc.body || this.doc.documentElement);
18470 this.cleanUpPaste();
18471 this.el.dom.value = d.innerHTML;
18472 this.owner.fireEvent('push', this, v);
18478 deferFocus : function(){
18479 this.focus.defer(10, this);
18483 focus : function(){
18484 if(this.win && !this.sourceEditMode){
18491 assignDocWin: function()
18493 var iframe = this.iframe;
18496 this.doc = iframe.contentWindow.document;
18497 this.win = iframe.contentWindow;
18499 // if (!Roo.get(this.frameId)) {
18502 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18503 // this.win = Roo.get(this.frameId).dom.contentWindow;
18505 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18509 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18510 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18515 initEditor : function(){
18516 //console.log("INIT EDITOR");
18517 this.assignDocWin();
18521 this.doc.designMode="on";
18523 this.doc.write(this.getDocMarkup());
18526 var dbody = (this.doc.body || this.doc.documentElement);
18527 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18528 // this copies styles from the containing element into thsi one..
18529 // not sure why we need all of this..
18530 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18532 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18533 //ss['background-attachment'] = 'fixed'; // w3c
18534 dbody.bgProperties = 'fixed'; // ie
18535 //Roo.DomHelper.applyStyles(dbody, ss);
18536 Roo.EventManager.on(this.doc, {
18537 //'mousedown': this.onEditorEvent,
18538 'mouseup': this.onEditorEvent,
18539 'dblclick': this.onEditorEvent,
18540 'click': this.onEditorEvent,
18541 'keyup': this.onEditorEvent,
18546 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18548 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18549 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18551 this.initialized = true;
18553 this.owner.fireEvent('initialize', this);
18558 onDestroy : function(){
18564 //for (var i =0; i < this.toolbars.length;i++) {
18565 // // fixme - ask toolbars for heights?
18566 // this.toolbars[i].onDestroy();
18569 //this.wrap.dom.innerHTML = '';
18570 //this.wrap.remove();
18575 onFirstFocus : function(){
18577 this.assignDocWin();
18580 this.activated = true;
18583 if(Roo.isGecko){ // prevent silly gecko errors
18585 var s = this.win.getSelection();
18586 if(!s.focusNode || s.focusNode.nodeType != 3){
18587 var r = s.getRangeAt(0);
18588 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18593 this.execCmd('useCSS', true);
18594 this.execCmd('styleWithCSS', false);
18597 this.owner.fireEvent('activate', this);
18601 adjustFont: function(btn){
18602 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18603 //if(Roo.isSafari){ // safari
18606 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18607 if(Roo.isSafari){ // safari
18608 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18609 v = (v < 10) ? 10 : v;
18610 v = (v > 48) ? 48 : v;
18611 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18616 v = Math.max(1, v+adjust);
18618 this.execCmd('FontSize', v );
18621 onEditorEvent : function(e)
18623 this.owner.fireEvent('editorevent', this, e);
18624 // this.updateToolbar();
18625 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18628 insertTag : function(tg)
18630 // could be a bit smarter... -> wrap the current selected tRoo..
18631 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18633 range = this.createRange(this.getSelection());
18634 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18635 wrappingNode.appendChild(range.extractContents());
18636 range.insertNode(wrappingNode);
18643 this.execCmd("formatblock", tg);
18647 insertText : function(txt)
18651 var range = this.createRange();
18652 range.deleteContents();
18653 //alert(Sender.getAttribute('label'));
18655 range.insertNode(this.doc.createTextNode(txt));
18661 * Executes a Midas editor command on the editor document and performs necessary focus and
18662 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18663 * @param {String} cmd The Midas command
18664 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18666 relayCmd : function(cmd, value){
18668 this.execCmd(cmd, value);
18669 this.owner.fireEvent('editorevent', this);
18670 //this.updateToolbar();
18671 this.owner.deferFocus();
18675 * Executes a Midas editor command directly on the editor document.
18676 * For visual commands, you should use {@link #relayCmd} instead.
18677 * <b>This should only be called after the editor is initialized.</b>
18678 * @param {String} cmd The Midas command
18679 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18681 execCmd : function(cmd, value){
18682 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18689 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18691 * @param {String} text | dom node..
18693 insertAtCursor : function(text)
18698 if(!this.activated){
18704 var r = this.doc.selection.createRange();
18715 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18719 // from jquery ui (MIT licenced)
18721 var win = this.win;
18723 if (win.getSelection && win.getSelection().getRangeAt) {
18724 range = win.getSelection().getRangeAt(0);
18725 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18726 range.insertNode(node);
18727 } else if (win.document.selection && win.document.selection.createRange) {
18728 // no firefox support
18729 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18730 win.document.selection.createRange().pasteHTML(txt);
18732 // no firefox support
18733 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18734 this.execCmd('InsertHTML', txt);
18743 mozKeyPress : function(e){
18745 var c = e.getCharCode(), cmd;
18748 c = String.fromCharCode(c).toLowerCase();
18762 this.cleanUpPaste.defer(100, this);
18770 e.preventDefault();
18778 fixKeys : function(){ // load time branching for fastest keydown performance
18780 return function(e){
18781 var k = e.getKey(), r;
18784 r = this.doc.selection.createRange();
18787 r.pasteHTML('    ');
18794 r = this.doc.selection.createRange();
18796 var target = r.parentElement();
18797 if(!target || target.tagName.toLowerCase() != 'li'){
18799 r.pasteHTML('<br />');
18805 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18806 this.cleanUpPaste.defer(100, this);
18812 }else if(Roo.isOpera){
18813 return function(e){
18814 var k = e.getKey();
18818 this.execCmd('InsertHTML','    ');
18821 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18822 this.cleanUpPaste.defer(100, this);
18827 }else if(Roo.isSafari){
18828 return function(e){
18829 var k = e.getKey();
18833 this.execCmd('InsertText','\t');
18837 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18838 this.cleanUpPaste.defer(100, this);
18846 getAllAncestors: function()
18848 var p = this.getSelectedNode();
18851 a.push(p); // push blank onto stack..
18852 p = this.getParentElement();
18856 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18860 a.push(this.doc.body);
18864 lastSelNode : false,
18867 getSelection : function()
18869 this.assignDocWin();
18870 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18873 getSelectedNode: function()
18875 // this may only work on Gecko!!!
18877 // should we cache this!!!!
18882 var range = this.createRange(this.getSelection()).cloneRange();
18885 var parent = range.parentElement();
18887 var testRange = range.duplicate();
18888 testRange.moveToElementText(parent);
18889 if (testRange.inRange(range)) {
18892 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18895 parent = parent.parentElement;
18900 // is ancestor a text element.
18901 var ac = range.commonAncestorContainer;
18902 if (ac.nodeType == 3) {
18903 ac = ac.parentNode;
18906 var ar = ac.childNodes;
18909 var other_nodes = [];
18910 var has_other_nodes = false;
18911 for (var i=0;i<ar.length;i++) {
18912 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18915 // fullly contained node.
18917 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18922 // probably selected..
18923 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18924 other_nodes.push(ar[i]);
18928 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18933 has_other_nodes = true;
18935 if (!nodes.length && other_nodes.length) {
18936 nodes= other_nodes;
18938 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18944 createRange: function(sel)
18946 // this has strange effects when using with
18947 // top toolbar - not sure if it's a great idea.
18948 //this.editor.contentWindow.focus();
18949 if (typeof sel != "undefined") {
18951 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18953 return this.doc.createRange();
18956 return this.doc.createRange();
18959 getParentElement: function()
18962 this.assignDocWin();
18963 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18965 var range = this.createRange(sel);
18968 var p = range.commonAncestorContainer;
18969 while (p.nodeType == 3) { // text node
18980 * Range intersection.. the hard stuff...
18984 * [ -- selected range --- ]
18988 * if end is before start or hits it. fail.
18989 * if start is after end or hits it fail.
18991 * if either hits (but other is outside. - then it's not
18997 // @see http://www.thismuchiknow.co.uk/?p=64.
18998 rangeIntersectsNode : function(range, node)
19000 var nodeRange = node.ownerDocument.createRange();
19002 nodeRange.selectNode(node);
19004 nodeRange.selectNodeContents(node);
19007 var rangeStartRange = range.cloneRange();
19008 rangeStartRange.collapse(true);
19010 var rangeEndRange = range.cloneRange();
19011 rangeEndRange.collapse(false);
19013 var nodeStartRange = nodeRange.cloneRange();
19014 nodeStartRange.collapse(true);
19016 var nodeEndRange = nodeRange.cloneRange();
19017 nodeEndRange.collapse(false);
19019 return rangeStartRange.compareBoundaryPoints(
19020 Range.START_TO_START, nodeEndRange) == -1 &&
19021 rangeEndRange.compareBoundaryPoints(
19022 Range.START_TO_START, nodeStartRange) == 1;
19026 rangeCompareNode : function(range, node)
19028 var nodeRange = node.ownerDocument.createRange();
19030 nodeRange.selectNode(node);
19032 nodeRange.selectNodeContents(node);
19036 range.collapse(true);
19038 nodeRange.collapse(true);
19040 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19041 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19043 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19045 var nodeIsBefore = ss == 1;
19046 var nodeIsAfter = ee == -1;
19048 if (nodeIsBefore && nodeIsAfter)
19050 if (!nodeIsBefore && nodeIsAfter)
19051 return 1; //right trailed.
19053 if (nodeIsBefore && !nodeIsAfter)
19054 return 2; // left trailed.
19059 // private? - in a new class?
19060 cleanUpPaste : function()
19062 // cleans up the whole document..
19063 Roo.log('cleanuppaste');
19065 this.cleanUpChildren(this.doc.body);
19066 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19067 if (clean != this.doc.body.innerHTML) {
19068 this.doc.body.innerHTML = clean;
19073 cleanWordChars : function(input) {// change the chars to hex code
19074 var he = Roo.HtmlEditorCore;
19076 var output = input;
19077 Roo.each(he.swapCodes, function(sw) {
19078 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19080 output = output.replace(swapper, sw[1]);
19087 cleanUpChildren : function (n)
19089 if (!n.childNodes.length) {
19092 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19093 this.cleanUpChild(n.childNodes[i]);
19100 cleanUpChild : function (node)
19103 //console.log(node);
19104 if (node.nodeName == "#text") {
19105 // clean up silly Windows -- stuff?
19108 if (node.nodeName == "#comment") {
19109 node.parentNode.removeChild(node);
19110 // clean up silly Windows -- stuff?
19113 var lcname = node.tagName.toLowerCase();
19114 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19115 // whitelist of tags..
19117 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19119 node.parentNode.removeChild(node);
19124 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19126 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19127 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19129 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19130 // remove_keep_children = true;
19133 if (remove_keep_children) {
19134 this.cleanUpChildren(node);
19135 // inserts everything just before this node...
19136 while (node.childNodes.length) {
19137 var cn = node.childNodes[0];
19138 node.removeChild(cn);
19139 node.parentNode.insertBefore(cn, node);
19141 node.parentNode.removeChild(node);
19145 if (!node.attributes || !node.attributes.length) {
19146 this.cleanUpChildren(node);
19150 function cleanAttr(n,v)
19153 if (v.match(/^\./) || v.match(/^\//)) {
19156 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19159 if (v.match(/^#/)) {
19162 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19163 node.removeAttribute(n);
19167 var cwhite = this.cwhite;
19168 var cblack = this.cblack;
19170 function cleanStyle(n,v)
19172 if (v.match(/expression/)) { //XSS?? should we even bother..
19173 node.removeAttribute(n);
19177 var parts = v.split(/;/);
19180 Roo.each(parts, function(p) {
19181 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19185 var l = p.split(':').shift().replace(/\s+/g,'');
19186 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19188 if ( cwhite.length && cblack.indexOf(l) > -1) {
19189 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19190 //node.removeAttribute(n);
19194 // only allow 'c whitelisted system attributes'
19195 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19196 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19197 //node.removeAttribute(n);
19207 if (clean.length) {
19208 node.setAttribute(n, clean.join(';'));
19210 node.removeAttribute(n);
19216 for (var i = node.attributes.length-1; i > -1 ; i--) {
19217 var a = node.attributes[i];
19220 if (a.name.toLowerCase().substr(0,2)=='on') {
19221 node.removeAttribute(a.name);
19224 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19225 node.removeAttribute(a.name);
19228 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19229 cleanAttr(a.name,a.value); // fixme..
19232 if (a.name == 'style') {
19233 cleanStyle(a.name,a.value);
19236 /// clean up MS crap..
19237 // tecnically this should be a list of valid class'es..
19240 if (a.name == 'class') {
19241 if (a.value.match(/^Mso/)) {
19242 node.className = '';
19245 if (a.value.match(/body/)) {
19246 node.className = '';
19257 this.cleanUpChildren(node);
19263 * Clean up MS wordisms...
19265 cleanWord : function(node)
19270 this.cleanWord(this.doc.body);
19273 if (node.nodeName == "#text") {
19274 // clean up silly Windows -- stuff?
19277 if (node.nodeName == "#comment") {
19278 node.parentNode.removeChild(node);
19279 // clean up silly Windows -- stuff?
19283 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19284 node.parentNode.removeChild(node);
19288 // remove - but keep children..
19289 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19290 while (node.childNodes.length) {
19291 var cn = node.childNodes[0];
19292 node.removeChild(cn);
19293 node.parentNode.insertBefore(cn, node);
19295 node.parentNode.removeChild(node);
19296 this.iterateChildren(node, this.cleanWord);
19300 if (node.className.length) {
19302 var cn = node.className.split(/\W+/);
19304 Roo.each(cn, function(cls) {
19305 if (cls.match(/Mso[a-zA-Z]+/)) {
19310 node.className = cna.length ? cna.join(' ') : '';
19312 node.removeAttribute("class");
19316 if (node.hasAttribute("lang")) {
19317 node.removeAttribute("lang");
19320 if (node.hasAttribute("style")) {
19322 var styles = node.getAttribute("style").split(";");
19324 Roo.each(styles, function(s) {
19325 if (!s.match(/:/)) {
19328 var kv = s.split(":");
19329 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19332 // what ever is left... we allow.
19335 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19336 if (!nstyle.length) {
19337 node.removeAttribute('style');
19340 this.iterateChildren(node, this.cleanWord);
19346 * iterateChildren of a Node, calling fn each time, using this as the scole..
19347 * @param {DomNode} node node to iterate children of.
19348 * @param {Function} fn method of this class to call on each item.
19350 iterateChildren : function(node, fn)
19352 if (!node.childNodes.length) {
19355 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19356 fn.call(this, node.childNodes[i])
19362 * cleanTableWidths.
19364 * Quite often pasting from word etc.. results in tables with column and widths.
19365 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19368 cleanTableWidths : function(node)
19373 this.cleanTableWidths(this.doc.body);
19378 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19381 Roo.log(node.tagName);
19382 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19383 this.iterateChildren(node, this.cleanTableWidths);
19386 if (node.hasAttribute('width')) {
19387 node.removeAttribute('width');
19391 if (node.hasAttribute("style")) {
19394 var styles = node.getAttribute("style").split(";");
19396 Roo.each(styles, function(s) {
19397 if (!s.match(/:/)) {
19400 var kv = s.split(":");
19401 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
19404 // what ever is left... we allow.
19407 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19408 if (!nstyle.length) {
19409 node.removeAttribute('style');
19413 this.iterateChildren(node, this.cleanTableWidths);
19421 domToHTML : function(currentElement, depth, nopadtext) {
19423 depth = depth || 0;
19424 nopadtext = nopadtext || false;
19426 if (!currentElement) {
19427 return this.domToHTML(this.doc.body);
19430 //Roo.log(currentElement);
19432 var allText = false;
19433 var nodeName = currentElement.nodeName;
19434 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19436 if (nodeName == '#text') {
19438 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19443 if (nodeName != 'BODY') {
19446 // Prints the node tagName, such as <A>, <IMG>, etc
19449 for(i = 0; i < currentElement.attributes.length;i++) {
19451 var aname = currentElement.attributes.item(i).name;
19452 if (!currentElement.attributes.item(i).value.length) {
19455 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19458 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19467 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19470 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19475 // Traverse the tree
19477 var currentElementChild = currentElement.childNodes.item(i);
19478 var allText = true;
19479 var innerHTML = '';
19481 while (currentElementChild) {
19482 // Formatting code (indent the tree so it looks nice on the screen)
19483 var nopad = nopadtext;
19484 if (lastnode == 'SPAN') {
19488 if (currentElementChild.nodeName == '#text') {
19489 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19490 toadd = nopadtext ? toadd : toadd.trim();
19491 if (!nopad && toadd.length > 80) {
19492 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19494 innerHTML += toadd;
19497 currentElementChild = currentElement.childNodes.item(i);
19503 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19505 // Recursively traverse the tree structure of the child node
19506 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19507 lastnode = currentElementChild.nodeName;
19509 currentElementChild=currentElement.childNodes.item(i);
19515 // The remaining code is mostly for formatting the tree
19516 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19521 ret+= "</"+tagName+">";
19527 applyBlacklists : function()
19529 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19530 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19534 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19535 if (b.indexOf(tag) > -1) {
19538 this.white.push(tag);
19542 Roo.each(w, function(tag) {
19543 if (b.indexOf(tag) > -1) {
19546 if (this.white.indexOf(tag) > -1) {
19549 this.white.push(tag);
19554 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19555 if (w.indexOf(tag) > -1) {
19558 this.black.push(tag);
19562 Roo.each(b, function(tag) {
19563 if (w.indexOf(tag) > -1) {
19566 if (this.black.indexOf(tag) > -1) {
19569 this.black.push(tag);
19574 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19575 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19579 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19580 if (b.indexOf(tag) > -1) {
19583 this.cwhite.push(tag);
19587 Roo.each(w, function(tag) {
19588 if (b.indexOf(tag) > -1) {
19591 if (this.cwhite.indexOf(tag) > -1) {
19594 this.cwhite.push(tag);
19599 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19600 if (w.indexOf(tag) > -1) {
19603 this.cblack.push(tag);
19607 Roo.each(b, function(tag) {
19608 if (w.indexOf(tag) > -1) {
19611 if (this.cblack.indexOf(tag) > -1) {
19614 this.cblack.push(tag);
19619 setStylesheets : function(stylesheets)
19621 if(typeof(stylesheets) == 'string'){
19622 Roo.get(this.iframe.contentDocument.head).createChild({
19624 rel : 'stylesheet',
19633 Roo.each(stylesheets, function(s) {
19638 Roo.get(_this.iframe.contentDocument.head).createChild({
19640 rel : 'stylesheet',
19649 removeStylesheets : function()
19653 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19658 // hide stuff that is not compatible
19672 * @event specialkey
19676 * @cfg {String} fieldClass @hide
19679 * @cfg {String} focusClass @hide
19682 * @cfg {String} autoCreate @hide
19685 * @cfg {String} inputType @hide
19688 * @cfg {String} invalidClass @hide
19691 * @cfg {String} invalidText @hide
19694 * @cfg {String} msgFx @hide
19697 * @cfg {String} validateOnBlur @hide
19701 Roo.HtmlEditorCore.white = [
19702 'area', 'br', 'img', 'input', 'hr', 'wbr',
19704 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19705 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19706 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19707 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19708 'table', 'ul', 'xmp',
19710 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19713 'dir', 'menu', 'ol', 'ul', 'dl',
19719 Roo.HtmlEditorCore.black = [
19720 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19722 'base', 'basefont', 'bgsound', 'blink', 'body',
19723 'frame', 'frameset', 'head', 'html', 'ilayer',
19724 'iframe', 'layer', 'link', 'meta', 'object',
19725 'script', 'style' ,'title', 'xml' // clean later..
19727 Roo.HtmlEditorCore.clean = [
19728 'script', 'style', 'title', 'xml'
19730 Roo.HtmlEditorCore.remove = [
19735 Roo.HtmlEditorCore.ablack = [
19739 Roo.HtmlEditorCore.aclean = [
19740 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19744 Roo.HtmlEditorCore.pwhite= [
19745 'http', 'https', 'mailto'
19748 // white listed style attributes.
19749 Roo.HtmlEditorCore.cwhite= [
19750 // 'text-align', /// default is to allow most things..
19756 // black listed style attributes.
19757 Roo.HtmlEditorCore.cblack= [
19758 // 'font-size' -- this can be set by the project
19762 Roo.HtmlEditorCore.swapCodes =[
19781 * @class Roo.bootstrap.HtmlEditor
19782 * @extends Roo.bootstrap.TextArea
19783 * Bootstrap HtmlEditor class
19786 * Create a new HtmlEditor
19787 * @param {Object} config The config object
19790 Roo.bootstrap.HtmlEditor = function(config){
19791 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19792 if (!this.toolbars) {
19793 this.toolbars = [];
19795 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19798 * @event initialize
19799 * Fires when the editor is fully initialized (including the iframe)
19800 * @param {HtmlEditor} this
19805 * Fires when the editor is first receives the focus. Any insertion must wait
19806 * until after this event.
19807 * @param {HtmlEditor} this
19811 * @event beforesync
19812 * Fires before the textarea is updated with content from the editor iframe. Return false
19813 * to cancel the sync.
19814 * @param {HtmlEditor} this
19815 * @param {String} html
19819 * @event beforepush
19820 * Fires before the iframe editor is updated with content from the textarea. Return false
19821 * to cancel the push.
19822 * @param {HtmlEditor} this
19823 * @param {String} html
19828 * Fires when the textarea is updated with content from the editor iframe.
19829 * @param {HtmlEditor} this
19830 * @param {String} html
19835 * Fires when the iframe editor is updated with content from the textarea.
19836 * @param {HtmlEditor} this
19837 * @param {String} html
19841 * @event editmodechange
19842 * Fires when the editor switches edit modes
19843 * @param {HtmlEditor} this
19844 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19846 editmodechange: true,
19848 * @event editorevent
19849 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19850 * @param {HtmlEditor} this
19854 * @event firstfocus
19855 * Fires when on first focus - needed by toolbars..
19856 * @param {HtmlEditor} this
19861 * Auto save the htmlEditor value as a file into Events
19862 * @param {HtmlEditor} this
19866 * @event savedpreview
19867 * preview the saved version of htmlEditor
19868 * @param {HtmlEditor} this
19875 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19879 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19884 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19889 * @cfg {Number} height (in pixels)
19893 * @cfg {Number} width (in pixels)
19898 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19901 stylesheets: false,
19906 // private properties
19907 validationEvent : false,
19909 initialized : false,
19912 onFocus : Roo.emptyFn,
19914 hideMode:'offsets',
19917 tbContainer : false,
19919 toolbarContainer :function() {
19920 return this.wrap.select('.x-html-editor-tb',true).first();
19924 * Protected method that will not generally be called directly. It
19925 * is called when the editor creates its toolbar. Override this method if you need to
19926 * add custom toolbar buttons.
19927 * @param {HtmlEditor} editor
19929 createToolbar : function(){
19931 Roo.log("create toolbars");
19933 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19934 this.toolbars[0].render(this.toolbarContainer());
19938 // if (!editor.toolbars || !editor.toolbars.length) {
19939 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19942 // for (var i =0 ; i < editor.toolbars.length;i++) {
19943 // editor.toolbars[i] = Roo.factory(
19944 // typeof(editor.toolbars[i]) == 'string' ?
19945 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19946 // Roo.bootstrap.HtmlEditor);
19947 // editor.toolbars[i].init(editor);
19953 onRender : function(ct, position)
19955 // Roo.log("Call onRender: " + this.xtype);
19957 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19959 this.wrap = this.inputEl().wrap({
19960 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19963 this.editorcore.onRender(ct, position);
19965 if (this.resizable) {
19966 this.resizeEl = new Roo.Resizable(this.wrap, {
19970 minHeight : this.height,
19971 height: this.height,
19972 handles : this.resizable,
19975 resize : function(r, w, h) {
19976 _t.onResize(w,h); // -something
19982 this.createToolbar(this);
19985 if(!this.width && this.resizable){
19986 this.setSize(this.wrap.getSize());
19988 if (this.resizeEl) {
19989 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19990 // should trigger onReize..
19996 onResize : function(w, h)
19998 Roo.log('resize: ' +w + ',' + h );
19999 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20003 if(this.inputEl() ){
20004 if(typeof w == 'number'){
20005 var aw = w - this.wrap.getFrameWidth('lr');
20006 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20009 if(typeof h == 'number'){
20010 var tbh = -11; // fixme it needs to tool bar size!
20011 for (var i =0; i < this.toolbars.length;i++) {
20012 // fixme - ask toolbars for heights?
20013 tbh += this.toolbars[i].el.getHeight();
20014 //if (this.toolbars[i].footer) {
20015 // tbh += this.toolbars[i].footer.el.getHeight();
20023 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20024 ah -= 5; // knock a few pixes off for look..
20025 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20029 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20030 this.editorcore.onResize(ew,eh);
20035 * Toggles the editor between standard and source edit mode.
20036 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20038 toggleSourceEdit : function(sourceEditMode)
20040 this.editorcore.toggleSourceEdit(sourceEditMode);
20042 if(this.editorcore.sourceEditMode){
20043 Roo.log('editor - showing textarea');
20046 // Roo.log(this.syncValue());
20048 this.inputEl().removeClass(['hide', 'x-hidden']);
20049 this.inputEl().dom.removeAttribute('tabIndex');
20050 this.inputEl().focus();
20052 Roo.log('editor - hiding textarea');
20054 // Roo.log(this.pushValue());
20057 this.inputEl().addClass(['hide', 'x-hidden']);
20058 this.inputEl().dom.setAttribute('tabIndex', -1);
20059 //this.deferFocus();
20062 if(this.resizable){
20063 this.setSize(this.wrap.getSize());
20066 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20069 // private (for BoxComponent)
20070 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20072 // private (for BoxComponent)
20073 getResizeEl : function(){
20077 // private (for BoxComponent)
20078 getPositionEl : function(){
20083 initEvents : function(){
20084 this.originalValue = this.getValue();
20088 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20091 // markInvalid : Roo.emptyFn,
20093 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20096 // clearInvalid : Roo.emptyFn,
20098 setValue : function(v){
20099 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20100 this.editorcore.pushValue();
20105 deferFocus : function(){
20106 this.focus.defer(10, this);
20110 focus : function(){
20111 this.editorcore.focus();
20117 onDestroy : function(){
20123 for (var i =0; i < this.toolbars.length;i++) {
20124 // fixme - ask toolbars for heights?
20125 this.toolbars[i].onDestroy();
20128 this.wrap.dom.innerHTML = '';
20129 this.wrap.remove();
20134 onFirstFocus : function(){
20135 //Roo.log("onFirstFocus");
20136 this.editorcore.onFirstFocus();
20137 for (var i =0; i < this.toolbars.length;i++) {
20138 this.toolbars[i].onFirstFocus();
20144 syncValue : function()
20146 this.editorcore.syncValue();
20149 pushValue : function()
20151 this.editorcore.pushValue();
20155 // hide stuff that is not compatible
20169 * @event specialkey
20173 * @cfg {String} fieldClass @hide
20176 * @cfg {String} focusClass @hide
20179 * @cfg {String} autoCreate @hide
20182 * @cfg {String} inputType @hide
20185 * @cfg {String} invalidClass @hide
20188 * @cfg {String} invalidText @hide
20191 * @cfg {String} msgFx @hide
20194 * @cfg {String} validateOnBlur @hide
20203 Roo.namespace('Roo.bootstrap.htmleditor');
20205 * @class Roo.bootstrap.HtmlEditorToolbar1
20210 new Roo.bootstrap.HtmlEditor({
20213 new Roo.bootstrap.HtmlEditorToolbar1({
20214 disable : { fonts: 1 , format: 1, ..., ... , ...],
20220 * @cfg {Object} disable List of elements to disable..
20221 * @cfg {Array} btns List of additional buttons.
20225 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20228 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20231 Roo.apply(this, config);
20233 // default disabled, based on 'good practice'..
20234 this.disable = this.disable || {};
20235 Roo.applyIf(this.disable, {
20238 specialElements : true
20240 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20242 this.editor = config.editor;
20243 this.editorcore = config.editor.editorcore;
20245 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20247 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20248 // dont call parent... till later.
20250 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20255 editorcore : false,
20260 "h1","h2","h3","h4","h5","h6",
20262 "abbr", "acronym", "address", "cite", "samp", "var",
20266 onRender : function(ct, position)
20268 // Roo.log("Call onRender: " + this.xtype);
20270 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20272 this.el.dom.style.marginBottom = '0';
20274 var editorcore = this.editorcore;
20275 var editor= this.editor;
20278 var btn = function(id,cmd , toggle, handler){
20280 var event = toggle ? 'toggle' : 'click';
20285 xns: Roo.bootstrap,
20288 enableToggle:toggle !== false,
20290 pressed : toggle ? false : null,
20293 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20294 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20303 xns: Roo.bootstrap,
20304 glyphicon : 'font',
20308 xns: Roo.bootstrap,
20312 Roo.each(this.formats, function(f) {
20313 style.menu.items.push({
20315 xns: Roo.bootstrap,
20316 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20321 editorcore.insertTag(this.tagname);
20328 children.push(style);
20331 btn('bold',false,true);
20332 btn('italic',false,true);
20333 btn('align-left', 'justifyleft',true);
20334 btn('align-center', 'justifycenter',true);
20335 btn('align-right' , 'justifyright',true);
20336 btn('link', false, false, function(btn) {
20337 //Roo.log("create link?");
20338 var url = prompt(this.createLinkText, this.defaultLinkValue);
20339 if(url && url != 'http:/'+'/'){
20340 this.editorcore.relayCmd('createlink', url);
20343 btn('list','insertunorderedlist',true);
20344 btn('pencil', false,true, function(btn){
20347 this.toggleSourceEdit(btn.pressed);
20353 xns: Roo.bootstrap,
20358 xns: Roo.bootstrap,
20363 cog.menu.items.push({
20365 xns: Roo.bootstrap,
20366 html : Clean styles,
20371 editorcore.insertTag(this.tagname);
20380 this.xtype = 'NavSimplebar';
20382 for(var i=0;i< children.length;i++) {
20384 this.buttons.add(this.addxtypeChild(children[i]));
20388 editor.on('editorevent', this.updateToolbar, this);
20390 onBtnClick : function(id)
20392 this.editorcore.relayCmd(id);
20393 this.editorcore.focus();
20397 * Protected method that will not generally be called directly. It triggers
20398 * a toolbar update by reading the markup state of the current selection in the editor.
20400 updateToolbar: function(){
20402 if(!this.editorcore.activated){
20403 this.editor.onFirstFocus(); // is this neeed?
20407 var btns = this.buttons;
20408 var doc = this.editorcore.doc;
20409 btns.get('bold').setActive(doc.queryCommandState('bold'));
20410 btns.get('italic').setActive(doc.queryCommandState('italic'));
20411 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20413 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20414 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20415 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20417 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20418 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20421 var ans = this.editorcore.getAllAncestors();
20422 if (this.formatCombo) {
20425 var store = this.formatCombo.store;
20426 this.formatCombo.setValue("");
20427 for (var i =0; i < ans.length;i++) {
20428 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20430 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20438 // hides menus... - so this cant be on a menu...
20439 Roo.bootstrap.MenuMgr.hideAll();
20441 Roo.bootstrap.MenuMgr.hideAll();
20442 //this.editorsyncValue();
20444 onFirstFocus: function() {
20445 this.buttons.each(function(item){
20449 toggleSourceEdit : function(sourceEditMode){
20452 if(sourceEditMode){
20453 Roo.log("disabling buttons");
20454 this.buttons.each( function(item){
20455 if(item.cmd != 'pencil'){
20461 Roo.log("enabling buttons");
20462 if(this.editorcore.initialized){
20463 this.buttons.each( function(item){
20469 Roo.log("calling toggole on editor");
20470 // tell the editor that it's been pressed..
20471 this.editor.toggleSourceEdit(sourceEditMode);
20481 * @class Roo.bootstrap.Table.AbstractSelectionModel
20482 * @extends Roo.util.Observable
20483 * Abstract base class for grid SelectionModels. It provides the interface that should be
20484 * implemented by descendant classes. This class should not be directly instantiated.
20487 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20488 this.locked = false;
20489 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20493 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20494 /** @ignore Called by the grid automatically. Do not call directly. */
20495 init : function(grid){
20501 * Locks the selections.
20504 this.locked = true;
20508 * Unlocks the selections.
20510 unlock : function(){
20511 this.locked = false;
20515 * Returns true if the selections are locked.
20516 * @return {Boolean}
20518 isLocked : function(){
20519 return this.locked;
20523 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20524 * @class Roo.bootstrap.Table.RowSelectionModel
20525 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20526 * It supports multiple selections and keyboard selection/navigation.
20528 * @param {Object} config
20531 Roo.bootstrap.Table.RowSelectionModel = function(config){
20532 Roo.apply(this, config);
20533 this.selections = new Roo.util.MixedCollection(false, function(o){
20538 this.lastActive = false;
20542 * @event selectionchange
20543 * Fires when the selection changes
20544 * @param {SelectionModel} this
20546 "selectionchange" : true,
20548 * @event afterselectionchange
20549 * Fires after the selection changes (eg. by key press or clicking)
20550 * @param {SelectionModel} this
20552 "afterselectionchange" : true,
20554 * @event beforerowselect
20555 * Fires when a row is selected being selected, return false to cancel.
20556 * @param {SelectionModel} this
20557 * @param {Number} rowIndex The selected index
20558 * @param {Boolean} keepExisting False if other selections will be cleared
20560 "beforerowselect" : true,
20563 * Fires when a row is selected.
20564 * @param {SelectionModel} this
20565 * @param {Number} rowIndex The selected index
20566 * @param {Roo.data.Record} r The record
20568 "rowselect" : true,
20570 * @event rowdeselect
20571 * Fires when a row is deselected.
20572 * @param {SelectionModel} this
20573 * @param {Number} rowIndex The selected index
20575 "rowdeselect" : true
20577 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20578 this.locked = false;
20581 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20583 * @cfg {Boolean} singleSelect
20584 * True to allow selection of only one row at a time (defaults to false)
20586 singleSelect : false,
20589 initEvents : function(){
20591 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20592 this.grid.on("mousedown", this.handleMouseDown, this);
20593 }else{ // allow click to work like normal
20594 this.grid.on("rowclick", this.handleDragableRowClick, this);
20597 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20598 "up" : function(e){
20600 this.selectPrevious(e.shiftKey);
20601 }else if(this.last !== false && this.lastActive !== false){
20602 var last = this.last;
20603 this.selectRange(this.last, this.lastActive-1);
20604 this.grid.getView().focusRow(this.lastActive);
20605 if(last !== false){
20609 this.selectFirstRow();
20611 this.fireEvent("afterselectionchange", this);
20613 "down" : function(e){
20615 this.selectNext(e.shiftKey);
20616 }else if(this.last !== false && this.lastActive !== false){
20617 var last = this.last;
20618 this.selectRange(this.last, this.lastActive+1);
20619 this.grid.getView().focusRow(this.lastActive);
20620 if(last !== false){
20624 this.selectFirstRow();
20626 this.fireEvent("afterselectionchange", this);
20631 var view = this.grid.view;
20632 view.on("refresh", this.onRefresh, this);
20633 view.on("rowupdated", this.onRowUpdated, this);
20634 view.on("rowremoved", this.onRemove, this);
20638 onRefresh : function(){
20639 var ds = this.grid.dataSource, i, v = this.grid.view;
20640 var s = this.selections;
20641 s.each(function(r){
20642 if((i = ds.indexOfId(r.id)) != -1){
20651 onRemove : function(v, index, r){
20652 this.selections.remove(r);
20656 onRowUpdated : function(v, index, r){
20657 if(this.isSelected(r)){
20658 v.onRowSelect(index);
20664 * @param {Array} records The records to select
20665 * @param {Boolean} keepExisting (optional) True to keep existing selections
20667 selectRecords : function(records, keepExisting){
20669 this.clearSelections();
20671 var ds = this.grid.dataSource;
20672 for(var i = 0, len = records.length; i < len; i++){
20673 this.selectRow(ds.indexOf(records[i]), true);
20678 * Gets the number of selected rows.
20681 getCount : function(){
20682 return this.selections.length;
20686 * Selects the first row in the grid.
20688 selectFirstRow : function(){
20693 * Select the last row.
20694 * @param {Boolean} keepExisting (optional) True to keep existing selections
20696 selectLastRow : function(keepExisting){
20697 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20701 * Selects the row immediately following the last selected row.
20702 * @param {Boolean} keepExisting (optional) True to keep existing selections
20704 selectNext : function(keepExisting){
20705 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20706 this.selectRow(this.last+1, keepExisting);
20707 this.grid.getView().focusRow(this.last);
20712 * Selects the row that precedes the last selected row.
20713 * @param {Boolean} keepExisting (optional) True to keep existing selections
20715 selectPrevious : function(keepExisting){
20717 this.selectRow(this.last-1, keepExisting);
20718 this.grid.getView().focusRow(this.last);
20723 * Returns the selected records
20724 * @return {Array} Array of selected records
20726 getSelections : function(){
20727 return [].concat(this.selections.items);
20731 * Returns the first selected record.
20734 getSelected : function(){
20735 return this.selections.itemAt(0);
20740 * Clears all selections.
20742 clearSelections : function(fast){
20743 if(this.locked) return;
20745 var ds = this.grid.dataSource;
20746 var s = this.selections;
20747 s.each(function(r){
20748 this.deselectRow(ds.indexOfId(r.id));
20752 this.selections.clear();
20759 * Selects all rows.
20761 selectAll : function(){
20762 if(this.locked) return;
20763 this.selections.clear();
20764 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20765 this.selectRow(i, true);
20770 * Returns True if there is a selection.
20771 * @return {Boolean}
20773 hasSelection : function(){
20774 return this.selections.length > 0;
20778 * Returns True if the specified row is selected.
20779 * @param {Number/Record} record The record or index of the record to check
20780 * @return {Boolean}
20782 isSelected : function(index){
20783 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20784 return (r && this.selections.key(r.id) ? true : false);
20788 * Returns True if the specified record id is selected.
20789 * @param {String} id The id of record to check
20790 * @return {Boolean}
20792 isIdSelected : function(id){
20793 return (this.selections.key(id) ? true : false);
20797 handleMouseDown : function(e, t){
20798 var view = this.grid.getView(), rowIndex;
20799 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20802 if(e.shiftKey && this.last !== false){
20803 var last = this.last;
20804 this.selectRange(last, rowIndex, e.ctrlKey);
20805 this.last = last; // reset the last
20806 view.focusRow(rowIndex);
20808 var isSelected = this.isSelected(rowIndex);
20809 if(e.button !== 0 && isSelected){
20810 view.focusRow(rowIndex);
20811 }else if(e.ctrlKey && isSelected){
20812 this.deselectRow(rowIndex);
20813 }else if(!isSelected){
20814 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20815 view.focusRow(rowIndex);
20818 this.fireEvent("afterselectionchange", this);
20821 handleDragableRowClick : function(grid, rowIndex, e)
20823 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20824 this.selectRow(rowIndex, false);
20825 grid.view.focusRow(rowIndex);
20826 this.fireEvent("afterselectionchange", this);
20831 * Selects multiple rows.
20832 * @param {Array} rows Array of the indexes of the row to select
20833 * @param {Boolean} keepExisting (optional) True to keep existing selections
20835 selectRows : function(rows, keepExisting){
20837 this.clearSelections();
20839 for(var i = 0, len = rows.length; i < len; i++){
20840 this.selectRow(rows[i], true);
20845 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20846 * @param {Number} startRow The index of the first row in the range
20847 * @param {Number} endRow The index of the last row in the range
20848 * @param {Boolean} keepExisting (optional) True to retain existing selections
20850 selectRange : function(startRow, endRow, keepExisting){
20851 if(this.locked) return;
20853 this.clearSelections();
20855 if(startRow <= endRow){
20856 for(var i = startRow; i <= endRow; i++){
20857 this.selectRow(i, true);
20860 for(var i = startRow; i >= endRow; i--){
20861 this.selectRow(i, true);
20867 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20868 * @param {Number} startRow The index of the first row in the range
20869 * @param {Number} endRow The index of the last row in the range
20871 deselectRange : function(startRow, endRow, preventViewNotify){
20872 if(this.locked) return;
20873 for(var i = startRow; i <= endRow; i++){
20874 this.deselectRow(i, preventViewNotify);
20880 * @param {Number} row The index of the row to select
20881 * @param {Boolean} keepExisting (optional) True to keep existing selections
20883 selectRow : function(index, keepExisting, preventViewNotify){
20884 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20885 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20886 if(!keepExisting || this.singleSelect){
20887 this.clearSelections();
20889 var r = this.grid.dataSource.getAt(index);
20890 this.selections.add(r);
20891 this.last = this.lastActive = index;
20892 if(!preventViewNotify){
20893 this.grid.getView().onRowSelect(index);
20895 this.fireEvent("rowselect", this, index, r);
20896 this.fireEvent("selectionchange", this);
20902 * @param {Number} row The index of the row to deselect
20904 deselectRow : function(index, preventViewNotify){
20905 if(this.locked) return;
20906 if(this.last == index){
20909 if(this.lastActive == index){
20910 this.lastActive = false;
20912 var r = this.grid.dataSource.getAt(index);
20913 this.selections.remove(r);
20914 if(!preventViewNotify){
20915 this.grid.getView().onRowDeselect(index);
20917 this.fireEvent("rowdeselect", this, index);
20918 this.fireEvent("selectionchange", this);
20922 restoreLast : function(){
20924 this.last = this._last;
20929 acceptsNav : function(row, col, cm){
20930 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20934 onEditorKey : function(field, e){
20935 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20940 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20942 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20944 }else if(k == e.ENTER && !e.ctrlKey){
20948 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20950 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20952 }else if(k == e.ESC){
20956 g.startEditing(newCell[0], newCell[1]);
20961 * Ext JS Library 1.1.1
20962 * Copyright(c) 2006-2007, Ext JS, LLC.
20964 * Originally Released Under LGPL - original licence link has changed is not relivant.
20967 * <script type="text/javascript">
20971 * @class Roo.bootstrap.PagingToolbar
20973 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20975 * Create a new PagingToolbar
20976 * @param {Object} config The config object
20978 Roo.bootstrap.PagingToolbar = function(config)
20980 // old args format still supported... - xtype is prefered..
20981 // created from xtype...
20982 var ds = config.dataSource;
20983 this.toolbarItems = [];
20984 if (config.items) {
20985 this.toolbarItems = config.items;
20986 // config.items = [];
20989 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20996 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21000 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21002 * @cfg {Roo.data.Store} dataSource
21003 * The underlying data store providing the paged data
21006 * @cfg {String/HTMLElement/Element} container
21007 * container The id or element that will contain the toolbar
21010 * @cfg {Boolean} displayInfo
21011 * True to display the displayMsg (defaults to false)
21014 * @cfg {Number} pageSize
21015 * The number of records to display per page (defaults to 20)
21019 * @cfg {String} displayMsg
21020 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21022 displayMsg : 'Displaying {0} - {1} of {2}',
21024 * @cfg {String} emptyMsg
21025 * The message to display when no records are found (defaults to "No data to display")
21027 emptyMsg : 'No data to display',
21029 * Customizable piece of the default paging text (defaults to "Page")
21032 beforePageText : "Page",
21034 * Customizable piece of the default paging text (defaults to "of %0")
21037 afterPageText : "of {0}",
21039 * Customizable piece of the default paging text (defaults to "First Page")
21042 firstText : "First Page",
21044 * Customizable piece of the default paging text (defaults to "Previous Page")
21047 prevText : "Previous Page",
21049 * Customizable piece of the default paging text (defaults to "Next Page")
21052 nextText : "Next Page",
21054 * Customizable piece of the default paging text (defaults to "Last Page")
21057 lastText : "Last Page",
21059 * Customizable piece of the default paging text (defaults to "Refresh")
21062 refreshText : "Refresh",
21066 onRender : function(ct, position)
21068 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21069 this.navgroup.parentId = this.id;
21070 this.navgroup.onRender(this.el, null);
21071 // add the buttons to the navgroup
21073 if(this.displayInfo){
21074 Roo.log(this.el.select('ul.navbar-nav',true).first());
21075 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21076 this.displayEl = this.el.select('.x-paging-info', true).first();
21077 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21078 // this.displayEl = navel.el.select('span',true).first();
21084 Roo.each(_this.buttons, function(e){
21085 Roo.factory(e).onRender(_this.el, null);
21089 Roo.each(_this.toolbarItems, function(e) {
21090 _this.navgroup.addItem(e);
21094 this.first = this.navgroup.addItem({
21095 tooltip: this.firstText,
21097 icon : 'fa fa-backward',
21099 preventDefault: true,
21100 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21103 this.prev = this.navgroup.addItem({
21104 tooltip: this.prevText,
21106 icon : 'fa fa-step-backward',
21108 preventDefault: true,
21109 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21111 //this.addSeparator();
21114 var field = this.navgroup.addItem( {
21116 cls : 'x-paging-position',
21118 html : this.beforePageText +
21119 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21120 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21123 this.field = field.el.select('input', true).first();
21124 this.field.on("keydown", this.onPagingKeydown, this);
21125 this.field.on("focus", function(){this.dom.select();});
21128 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21129 //this.field.setHeight(18);
21130 //this.addSeparator();
21131 this.next = this.navgroup.addItem({
21132 tooltip: this.nextText,
21134 html : ' <i class="fa fa-step-forward">',
21136 preventDefault: true,
21137 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21139 this.last = this.navgroup.addItem({
21140 tooltip: this.lastText,
21141 icon : 'fa fa-forward',
21144 preventDefault: true,
21145 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21147 //this.addSeparator();
21148 this.loading = this.navgroup.addItem({
21149 tooltip: this.refreshText,
21150 icon: 'fa fa-refresh',
21151 preventDefault: true,
21152 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21158 updateInfo : function(){
21159 if(this.displayEl){
21160 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21161 var msg = count == 0 ?
21165 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21167 this.displayEl.update(msg);
21172 onLoad : function(ds, r, o){
21173 this.cursor = o.params ? o.params.start : 0;
21174 var d = this.getPageData(),
21178 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21179 this.field.dom.value = ap;
21180 this.first.setDisabled(ap == 1);
21181 this.prev.setDisabled(ap == 1);
21182 this.next.setDisabled(ap == ps);
21183 this.last.setDisabled(ap == ps);
21184 this.loading.enable();
21189 getPageData : function(){
21190 var total = this.ds.getTotalCount();
21193 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21194 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21199 onLoadError : function(){
21200 this.loading.enable();
21204 onPagingKeydown : function(e){
21205 var k = e.getKey();
21206 var d = this.getPageData();
21208 var v = this.field.dom.value, pageNum;
21209 if(!v || isNaN(pageNum = parseInt(v, 10))){
21210 this.field.dom.value = d.activePage;
21213 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21214 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21217 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))
21219 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21220 this.field.dom.value = pageNum;
21221 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21224 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21226 var v = this.field.dom.value, pageNum;
21227 var increment = (e.shiftKey) ? 10 : 1;
21228 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21230 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21231 this.field.dom.value = d.activePage;
21234 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21236 this.field.dom.value = parseInt(v, 10) + increment;
21237 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21238 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21245 beforeLoad : function(){
21247 this.loading.disable();
21252 onClick : function(which){
21261 ds.load({params:{start: 0, limit: this.pageSize}});
21264 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21267 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21270 var total = ds.getTotalCount();
21271 var extra = total % this.pageSize;
21272 var lastStart = extra ? (total - extra) : total-this.pageSize;
21273 ds.load({params:{start: lastStart, limit: this.pageSize}});
21276 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21282 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21283 * @param {Roo.data.Store} store The data store to unbind
21285 unbind : function(ds){
21286 ds.un("beforeload", this.beforeLoad, this);
21287 ds.un("load", this.onLoad, this);
21288 ds.un("loadexception", this.onLoadError, this);
21289 ds.un("remove", this.updateInfo, this);
21290 ds.un("add", this.updateInfo, this);
21291 this.ds = undefined;
21295 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21296 * @param {Roo.data.Store} store The data store to bind
21298 bind : function(ds){
21299 ds.on("beforeload", this.beforeLoad, this);
21300 ds.on("load", this.onLoad, this);
21301 ds.on("loadexception", this.onLoadError, this);
21302 ds.on("remove", this.updateInfo, this);
21303 ds.on("add", this.updateInfo, this);
21314 * @class Roo.bootstrap.MessageBar
21315 * @extends Roo.bootstrap.Component
21316 * Bootstrap MessageBar class
21317 * @cfg {String} html contents of the MessageBar
21318 * @cfg {String} weight (info | success | warning | danger) default info
21319 * @cfg {String} beforeClass insert the bar before the given class
21320 * @cfg {Boolean} closable (true | false) default false
21321 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21324 * Create a new Element
21325 * @param {Object} config The config object
21328 Roo.bootstrap.MessageBar = function(config){
21329 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21332 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21338 beforeClass: 'bootstrap-sticky-wrap',
21340 getAutoCreate : function(){
21344 cls: 'alert alert-dismissable alert-' + this.weight,
21349 html: this.html || ''
21355 cfg.cls += ' alert-messages-fixed';
21369 onRender : function(ct, position)
21371 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21374 var cfg = Roo.apply({}, this.getAutoCreate());
21378 cfg.cls += ' ' + this.cls;
21381 cfg.style = this.style;
21383 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21385 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21388 this.el.select('>button.close').on('click', this.hide, this);
21394 if (!this.rendered) {
21400 this.fireEvent('show', this);
21406 if (!this.rendered) {
21412 this.fireEvent('hide', this);
21415 update : function()
21417 // var e = this.el.dom.firstChild;
21419 // if(this.closable){
21420 // e = e.nextSibling;
21423 // e.data = this.html || '';
21425 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21441 * @class Roo.bootstrap.Graph
21442 * @extends Roo.bootstrap.Component
21443 * Bootstrap Graph class
21447 @cfg {String} graphtype bar | vbar | pie
21448 @cfg {number} g_x coodinator | centre x (pie)
21449 @cfg {number} g_y coodinator | centre y (pie)
21450 @cfg {number} g_r radius (pie)
21451 @cfg {number} g_height height of the chart (respected by all elements in the set)
21452 @cfg {number} g_width width of the chart (respected by all elements in the set)
21453 @cfg {Object} title The title of the chart
21456 -opts (object) options for the chart
21458 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21459 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21461 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.
21462 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21464 o stretch (boolean)
21466 -opts (object) options for the pie
21469 o startAngle (number)
21470 o endAngle (number)
21474 * Create a new Input
21475 * @param {Object} config The config object
21478 Roo.bootstrap.Graph = function(config){
21479 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21485 * The img click event for the img.
21486 * @param {Roo.EventObject} e
21492 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21503 //g_colors: this.colors,
21510 getAutoCreate : function(){
21521 onRender : function(ct,position){
21522 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21523 this.raphael = Raphael(this.el.dom);
21525 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21526 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21527 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21528 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21530 r.text(160, 10, "Single Series Chart").attr(txtattr);
21531 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21532 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21533 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21535 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21536 r.barchart(330, 10, 300, 220, data1);
21537 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21538 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21541 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21542 // r.barchart(30, 30, 560, 250, xdata, {
21543 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21544 // axis : "0 0 1 1",
21545 // axisxlabels : xdata
21546 // //yvalues : cols,
21549 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21551 // this.load(null,xdata,{
21552 // axis : "0 0 1 1",
21553 // axisxlabels : xdata
21558 load : function(graphtype,xdata,opts){
21559 this.raphael.clear();
21561 graphtype = this.graphtype;
21566 var r = this.raphael,
21567 fin = function () {
21568 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21570 fout = function () {
21571 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21573 pfin = function() {
21574 this.sector.stop();
21575 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21578 this.label[0].stop();
21579 this.label[0].attr({ r: 7.5 });
21580 this.label[1].attr({ "font-weight": 800 });
21583 pfout = function() {
21584 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21587 this.label[0].animate({ r: 5 }, 500, "bounce");
21588 this.label[1].attr({ "font-weight": 400 });
21594 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21597 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21600 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21601 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21603 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21610 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21615 setTitle: function(o)
21620 initEvents: function() {
21623 this.el.on('click', this.onClick, this);
21627 onClick : function(e)
21629 Roo.log('img onclick');
21630 this.fireEvent('click', this, e);
21642 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21645 * @class Roo.bootstrap.dash.NumberBox
21646 * @extends Roo.bootstrap.Component
21647 * Bootstrap NumberBox class
21648 * @cfg {String} headline Box headline
21649 * @cfg {String} content Box content
21650 * @cfg {String} icon Box icon
21651 * @cfg {String} footer Footer text
21652 * @cfg {String} fhref Footer href
21655 * Create a new NumberBox
21656 * @param {Object} config The config object
21660 Roo.bootstrap.dash.NumberBox = function(config){
21661 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21665 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21674 getAutoCreate : function(){
21678 cls : 'small-box ',
21686 cls : 'roo-headline',
21687 html : this.headline
21691 cls : 'roo-content',
21692 html : this.content
21706 cls : 'ion ' + this.icon
21715 cls : 'small-box-footer',
21716 href : this.fhref || '#',
21720 cfg.cn.push(footer);
21727 onRender : function(ct,position){
21728 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21735 setHeadline: function (value)
21737 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21740 setFooter: function (value, href)
21742 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21745 this.el.select('a.small-box-footer',true).first().attr('href', href);
21750 setContent: function (value)
21752 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21755 initEvents: function()
21769 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21772 * @class Roo.bootstrap.dash.TabBox
21773 * @extends Roo.bootstrap.Component
21774 * Bootstrap TabBox class
21775 * @cfg {String} title Title of the TabBox
21776 * @cfg {String} icon Icon of the TabBox
21777 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21778 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21781 * Create a new TabBox
21782 * @param {Object} config The config object
21786 Roo.bootstrap.dash.TabBox = function(config){
21787 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21792 * When a pane is added
21793 * @param {Roo.bootstrap.dash.TabPane} pane
21797 * @event activatepane
21798 * When a pane is activated
21799 * @param {Roo.bootstrap.dash.TabPane} pane
21801 "activatepane" : true
21809 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21814 tabScrollable : false,
21816 getChildContainer : function()
21818 return this.el.select('.tab-content', true).first();
21821 getAutoCreate : function(){
21825 cls: 'pull-left header',
21833 cls: 'fa ' + this.icon
21839 cls: 'nav nav-tabs pull-right',
21845 if(this.tabScrollable){
21852 cls: 'nav nav-tabs pull-right',
21863 cls: 'nav-tabs-custom',
21868 cls: 'tab-content no-padding',
21876 initEvents : function()
21878 //Roo.log('add add pane handler');
21879 this.on('addpane', this.onAddPane, this);
21882 * Updates the box title
21883 * @param {String} html to set the title to.
21885 setTitle : function(value)
21887 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21889 onAddPane : function(pane)
21891 this.panes.push(pane);
21892 //Roo.log('addpane');
21894 // tabs are rendere left to right..
21895 if(!this.showtabs){
21899 var ctr = this.el.select('.nav-tabs', true).first();
21902 var existing = ctr.select('.nav-tab',true);
21903 var qty = existing.getCount();;
21906 var tab = ctr.createChild({
21908 cls : 'nav-tab' + (qty ? '' : ' active'),
21916 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21919 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21921 pane.el.addClass('active');
21926 onTabClick : function(ev,un,ob,pane)
21928 //Roo.log('tab - prev default');
21929 ev.preventDefault();
21932 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21933 pane.tab.addClass('active');
21934 //Roo.log(pane.title);
21935 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21936 // technically we should have a deactivate event.. but maybe add later.
21937 // and it should not de-activate the selected tab...
21938 this.fireEvent('activatepane', pane);
21939 pane.el.addClass('active');
21940 pane.fireEvent('activate');
21945 getActivePane : function()
21948 Roo.each(this.panes, function(p) {
21949 if(p.el.hasClass('active')){
21970 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21972 * @class Roo.bootstrap.TabPane
21973 * @extends Roo.bootstrap.Component
21974 * Bootstrap TabPane class
21975 * @cfg {Boolean} active (false | true) Default false
21976 * @cfg {String} title title of panel
21980 * Create a new TabPane
21981 * @param {Object} config The config object
21984 Roo.bootstrap.dash.TabPane = function(config){
21985 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21991 * When a pane is activated
21992 * @param {Roo.bootstrap.dash.TabPane} pane
21999 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22004 // the tabBox that this is attached to.
22007 getAutoCreate : function()
22015 cfg.cls += ' active';
22020 initEvents : function()
22022 //Roo.log('trigger add pane handler');
22023 this.parent().fireEvent('addpane', this)
22027 * Updates the tab title
22028 * @param {String} html to set the title to.
22030 setTitle: function(str)
22036 this.tab.select('a', true).first().dom.innerHTML = str;
22053 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22056 * @class Roo.bootstrap.menu.Menu
22057 * @extends Roo.bootstrap.Component
22058 * Bootstrap Menu class - container for Menu
22059 * @cfg {String} html Text of the menu
22060 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22061 * @cfg {String} icon Font awesome icon
22062 * @cfg {String} pos Menu align to (top | bottom) default bottom
22066 * Create a new Menu
22067 * @param {Object} config The config object
22071 Roo.bootstrap.menu.Menu = function(config){
22072 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22076 * @event beforeshow
22077 * Fires before this menu is displayed
22078 * @param {Roo.bootstrap.menu.Menu} this
22082 * @event beforehide
22083 * Fires before this menu is hidden
22084 * @param {Roo.bootstrap.menu.Menu} this
22089 * Fires after this menu is displayed
22090 * @param {Roo.bootstrap.menu.Menu} this
22095 * Fires after this menu is hidden
22096 * @param {Roo.bootstrap.menu.Menu} this
22101 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22102 * @param {Roo.bootstrap.menu.Menu} this
22103 * @param {Roo.EventObject} e
22110 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22114 weight : 'default',
22119 getChildContainer : function() {
22120 if(this.isSubMenu){
22124 return this.el.select('ul.dropdown-menu', true).first();
22127 getAutoCreate : function()
22132 cls : 'roo-menu-text',
22140 cls : 'fa ' + this.icon
22151 cls : 'dropdown-button btn btn-' + this.weight,
22156 cls : 'dropdown-toggle btn btn-' + this.weight,
22166 cls : 'dropdown-menu'
22172 if(this.pos == 'top'){
22173 cfg.cls += ' dropup';
22176 if(this.isSubMenu){
22179 cls : 'dropdown-menu'
22186 onRender : function(ct, position)
22188 this.isSubMenu = ct.hasClass('dropdown-submenu');
22190 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22193 initEvents : function()
22195 if(this.isSubMenu){
22199 this.hidden = true;
22201 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22202 this.triggerEl.on('click', this.onTriggerPress, this);
22204 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22205 this.buttonEl.on('click', this.onClick, this);
22211 if(this.isSubMenu){
22215 return this.el.select('ul.dropdown-menu', true).first();
22218 onClick : function(e)
22220 this.fireEvent("click", this, e);
22223 onTriggerPress : function(e)
22225 if (this.isVisible()) {
22232 isVisible : function(){
22233 return !this.hidden;
22238 this.fireEvent("beforeshow", this);
22240 this.hidden = false;
22241 this.el.addClass('open');
22243 Roo.get(document).on("mouseup", this.onMouseUp, this);
22245 this.fireEvent("show", this);
22252 this.fireEvent("beforehide", this);
22254 this.hidden = true;
22255 this.el.removeClass('open');
22257 Roo.get(document).un("mouseup", this.onMouseUp);
22259 this.fireEvent("hide", this);
22262 onMouseUp : function()
22276 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22279 * @class Roo.bootstrap.menu.Item
22280 * @extends Roo.bootstrap.Component
22281 * Bootstrap MenuItem class
22282 * @cfg {Boolean} submenu (true | false) default false
22283 * @cfg {String} html text of the item
22284 * @cfg {String} href the link
22285 * @cfg {Boolean} disable (true | false) default false
22286 * @cfg {Boolean} preventDefault (true | false) default true
22287 * @cfg {String} icon Font awesome icon
22288 * @cfg {String} pos Submenu align to (left | right) default right
22292 * Create a new Item
22293 * @param {Object} config The config object
22297 Roo.bootstrap.menu.Item = function(config){
22298 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22302 * Fires when the mouse is hovering over this menu
22303 * @param {Roo.bootstrap.menu.Item} this
22304 * @param {Roo.EventObject} e
22309 * Fires when the mouse exits this menu
22310 * @param {Roo.bootstrap.menu.Item} this
22311 * @param {Roo.EventObject} e
22317 * The raw click event for the entire grid.
22318 * @param {Roo.EventObject} e
22324 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22329 preventDefault: true,
22334 getAutoCreate : function()
22339 cls : 'roo-menu-item-text',
22347 cls : 'fa ' + this.icon
22356 href : this.href || '#',
22363 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22367 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22369 if(this.pos == 'left'){
22370 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22377 initEvents : function()
22379 this.el.on('mouseover', this.onMouseOver, this);
22380 this.el.on('mouseout', this.onMouseOut, this);
22382 this.el.select('a', true).first().on('click', this.onClick, this);
22386 onClick : function(e)
22388 if(this.preventDefault){
22389 e.preventDefault();
22392 this.fireEvent("click", this, e);
22395 onMouseOver : function(e)
22397 if(this.submenu && this.pos == 'left'){
22398 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22401 this.fireEvent("mouseover", this, e);
22404 onMouseOut : function(e)
22406 this.fireEvent("mouseout", this, e);
22418 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22421 * @class Roo.bootstrap.menu.Separator
22422 * @extends Roo.bootstrap.Component
22423 * Bootstrap Separator class
22426 * Create a new Separator
22427 * @param {Object} config The config object
22431 Roo.bootstrap.menu.Separator = function(config){
22432 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22435 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22437 getAutoCreate : function(){
22458 * @class Roo.bootstrap.Tooltip
22459 * Bootstrap Tooltip class
22460 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22461 * to determine which dom element triggers the tooltip.
22463 * It needs to add support for additional attributes like tooltip-position
22466 * Create a new Toolti
22467 * @param {Object} config The config object
22470 Roo.bootstrap.Tooltip = function(config){
22471 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22474 Roo.apply(Roo.bootstrap.Tooltip, {
22476 * @function init initialize tooltip monitoring.
22480 currentTip : false,
22481 currentRegion : false,
22487 Roo.get(document).on('mouseover', this.enter ,this);
22488 Roo.get(document).on('mouseout', this.leave, this);
22491 this.currentTip = new Roo.bootstrap.Tooltip();
22494 enter : function(ev)
22496 var dom = ev.getTarget();
22498 //Roo.log(['enter',dom]);
22499 var el = Roo.fly(dom);
22500 if (this.currentEl) {
22502 //Roo.log(this.currentEl);
22503 //Roo.log(this.currentEl.contains(dom));
22504 if (this.currentEl == el) {
22507 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22515 if (this.currentTip.el) {
22516 this.currentTip.el.hide(); // force hiding...
22521 // you can not look for children, as if el is the body.. then everythign is the child..
22522 if (!el.attr('tooltip')) { //
22523 if (!el.select("[tooltip]").elements.length) {
22526 // is the mouse over this child...?
22527 bindEl = el.select("[tooltip]").first();
22528 var xy = ev.getXY();
22529 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22530 //Roo.log("not in region.");
22533 //Roo.log("child element over..");
22536 this.currentEl = bindEl;
22537 this.currentTip.bind(bindEl);
22538 this.currentRegion = Roo.lib.Region.getRegion(dom);
22539 this.currentTip.enter();
22542 leave : function(ev)
22544 var dom = ev.getTarget();
22545 //Roo.log(['leave',dom]);
22546 if (!this.currentEl) {
22551 if (dom != this.currentEl.dom) {
22554 var xy = ev.getXY();
22555 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22558 // only activate leave if mouse cursor is outside... bounding box..
22563 if (this.currentTip) {
22564 this.currentTip.leave();
22566 //Roo.log('clear currentEl');
22567 this.currentEl = false;
22572 'left' : ['r-l', [-2,0], 'right'],
22573 'right' : ['l-r', [2,0], 'left'],
22574 'bottom' : ['t-b', [0,2], 'top'],
22575 'top' : [ 'b-t', [0,-2], 'bottom']
22581 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22586 delay : null, // can be { show : 300 , hide: 500}
22590 hoverState : null, //???
22592 placement : 'bottom',
22594 getAutoCreate : function(){
22601 cls : 'tooltip-arrow'
22604 cls : 'tooltip-inner'
22611 bind : function(el)
22617 enter : function () {
22619 if (this.timeout != null) {
22620 clearTimeout(this.timeout);
22623 this.hoverState = 'in';
22624 //Roo.log("enter - show");
22625 if (!this.delay || !this.delay.show) {
22630 this.timeout = setTimeout(function () {
22631 if (_t.hoverState == 'in') {
22634 }, this.delay.show);
22638 clearTimeout(this.timeout);
22640 this.hoverState = 'out';
22641 if (!this.delay || !this.delay.hide) {
22647 this.timeout = setTimeout(function () {
22648 //Roo.log("leave - timeout");
22650 if (_t.hoverState == 'out') {
22652 Roo.bootstrap.Tooltip.currentEl = false;
22660 this.render(document.body);
22663 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22665 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22667 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22669 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22671 var placement = typeof this.placement == 'function' ?
22672 this.placement.call(this, this.el, on_el) :
22675 var autoToken = /\s?auto?\s?/i;
22676 var autoPlace = autoToken.test(placement);
22678 placement = placement.replace(autoToken, '') || 'top';
22682 //this.el.setXY([0,0]);
22684 //this.el.dom.style.display='block';
22685 this.el.addClass(placement);
22687 //this.el.appendTo(on_el);
22689 var p = this.getPosition();
22690 var box = this.el.getBox();
22695 var align = Roo.bootstrap.Tooltip.alignment[placement];
22696 this.el.alignTo(this.bindEl, align[0],align[1]);
22697 //var arrow = this.el.select('.arrow',true).first();
22698 //arrow.set(align[2],
22700 this.el.addClass('in fade');
22701 this.hoverState = null;
22703 if (this.el.hasClass('fade')) {
22714 //this.el.setXY([0,0]);
22715 this.el.removeClass('in');
22731 * @class Roo.bootstrap.LocationPicker
22732 * @extends Roo.bootstrap.Component
22733 * Bootstrap LocationPicker class
22734 * @cfg {Number} latitude Position when init default 0
22735 * @cfg {Number} longitude Position when init default 0
22736 * @cfg {Number} zoom default 15
22737 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22738 * @cfg {Boolean} mapTypeControl default false
22739 * @cfg {Boolean} disableDoubleClickZoom default false
22740 * @cfg {Boolean} scrollwheel default true
22741 * @cfg {Boolean} streetViewControl default false
22742 * @cfg {Number} radius default 0
22743 * @cfg {String} locationName
22744 * @cfg {Boolean} draggable default true
22745 * @cfg {Boolean} enableAutocomplete default false
22746 * @cfg {Boolean} enableReverseGeocode default true
22747 * @cfg {String} markerTitle
22750 * Create a new LocationPicker
22751 * @param {Object} config The config object
22755 Roo.bootstrap.LocationPicker = function(config){
22757 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22762 * Fires when the picker initialized.
22763 * @param {Roo.bootstrap.LocationPicker} this
22764 * @param {Google Location} location
22768 * @event positionchanged
22769 * Fires when the picker position changed.
22770 * @param {Roo.bootstrap.LocationPicker} this
22771 * @param {Google Location} location
22773 positionchanged : true,
22776 * Fires when the map resize.
22777 * @param {Roo.bootstrap.LocationPicker} this
22782 * Fires when the map show.
22783 * @param {Roo.bootstrap.LocationPicker} this
22788 * Fires when the map hide.
22789 * @param {Roo.bootstrap.LocationPicker} this
22794 * Fires when click the map.
22795 * @param {Roo.bootstrap.LocationPicker} this
22796 * @param {Map event} e
22800 * @event mapRightClick
22801 * Fires when right click the map.
22802 * @param {Roo.bootstrap.LocationPicker} this
22803 * @param {Map event} e
22805 mapRightClick : true,
22807 * @event markerClick
22808 * Fires when click the marker.
22809 * @param {Roo.bootstrap.LocationPicker} this
22810 * @param {Map event} e
22812 markerClick : true,
22814 * @event markerRightClick
22815 * Fires when right click the marker.
22816 * @param {Roo.bootstrap.LocationPicker} this
22817 * @param {Map event} e
22819 markerRightClick : true,
22821 * @event OverlayViewDraw
22822 * Fires when OverlayView Draw
22823 * @param {Roo.bootstrap.LocationPicker} this
22825 OverlayViewDraw : true,
22827 * @event OverlayViewOnAdd
22828 * Fires when OverlayView Draw
22829 * @param {Roo.bootstrap.LocationPicker} this
22831 OverlayViewOnAdd : true,
22833 * @event OverlayViewOnRemove
22834 * Fires when OverlayView Draw
22835 * @param {Roo.bootstrap.LocationPicker} this
22837 OverlayViewOnRemove : true,
22839 * @event OverlayViewShow
22840 * Fires when OverlayView Draw
22841 * @param {Roo.bootstrap.LocationPicker} this
22842 * @param {Pixel} cpx
22844 OverlayViewShow : true,
22846 * @event OverlayViewHide
22847 * Fires when OverlayView Draw
22848 * @param {Roo.bootstrap.LocationPicker} this
22850 OverlayViewHide : true
22855 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22857 gMapContext: false,
22863 mapTypeControl: false,
22864 disableDoubleClickZoom: false,
22866 streetViewControl: false,
22870 enableAutocomplete: false,
22871 enableReverseGeocode: true,
22874 getAutoCreate: function()
22879 cls: 'roo-location-picker'
22885 initEvents: function(ct, position)
22887 if(!this.el.getWidth() || this.isApplied()){
22891 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22896 initial: function()
22898 if(!this.mapTypeId){
22899 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22902 this.gMapContext = this.GMapContext();
22904 this.initOverlayView();
22906 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22910 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22911 _this.setPosition(_this.gMapContext.marker.position);
22914 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22915 _this.fireEvent('mapClick', this, event);
22919 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22920 _this.fireEvent('mapRightClick', this, event);
22924 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22925 _this.fireEvent('markerClick', this, event);
22929 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22930 _this.fireEvent('markerRightClick', this, event);
22934 this.setPosition(this.gMapContext.location);
22936 this.fireEvent('initial', this, this.gMapContext.location);
22939 initOverlayView: function()
22943 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22947 _this.fireEvent('OverlayViewDraw', _this);
22952 _this.fireEvent('OverlayViewOnAdd', _this);
22955 onRemove: function()
22957 _this.fireEvent('OverlayViewOnRemove', _this);
22960 show: function(cpx)
22962 _this.fireEvent('OverlayViewShow', _this, cpx);
22967 _this.fireEvent('OverlayViewHide', _this);
22973 fromLatLngToContainerPixel: function(event)
22975 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22978 isApplied: function()
22980 return this.getGmapContext() == false ? false : true;
22983 getGmapContext: function()
22985 return this.gMapContext
22988 GMapContext: function()
22990 var position = new google.maps.LatLng(this.latitude, this.longitude);
22992 var _map = new google.maps.Map(this.el.dom, {
22995 mapTypeId: this.mapTypeId,
22996 mapTypeControl: this.mapTypeControl,
22997 disableDoubleClickZoom: this.disableDoubleClickZoom,
22998 scrollwheel: this.scrollwheel,
22999 streetViewControl: this.streetViewControl,
23000 locationName: this.locationName,
23001 draggable: this.draggable,
23002 enableAutocomplete: this.enableAutocomplete,
23003 enableReverseGeocode: this.enableReverseGeocode
23006 var _marker = new google.maps.Marker({
23007 position: position,
23009 title: this.markerTitle,
23010 draggable: this.draggable
23017 location: position,
23018 radius: this.radius,
23019 locationName: this.locationName,
23020 addressComponents: {
23021 formatted_address: null,
23022 addressLine1: null,
23023 addressLine2: null,
23025 streetNumber: null,
23029 stateOrProvince: null
23032 domContainer: this.el.dom,
23033 geodecoder: new google.maps.Geocoder()
23037 drawCircle: function(center, radius, options)
23039 if (this.gMapContext.circle != null) {
23040 this.gMapContext.circle.setMap(null);
23044 options = Roo.apply({}, options, {
23045 strokeColor: "#0000FF",
23046 strokeOpacity: .35,
23048 fillColor: "#0000FF",
23052 options.map = this.gMapContext.map;
23053 options.radius = radius;
23054 options.center = center;
23055 this.gMapContext.circle = new google.maps.Circle(options);
23056 return this.gMapContext.circle;
23062 setPosition: function(location)
23064 this.gMapContext.location = location;
23065 this.gMapContext.marker.setPosition(location);
23066 this.gMapContext.map.panTo(location);
23067 this.drawCircle(location, this.gMapContext.radius, {});
23071 if (this.gMapContext.settings.enableReverseGeocode) {
23072 this.gMapContext.geodecoder.geocode({
23073 latLng: this.gMapContext.location
23074 }, function(results, status) {
23076 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23077 _this.gMapContext.locationName = results[0].formatted_address;
23078 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23080 _this.fireEvent('positionchanged', this, location);
23087 this.fireEvent('positionchanged', this, location);
23092 google.maps.event.trigger(this.gMapContext.map, "resize");
23094 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23096 this.fireEvent('resize', this);
23099 setPositionByLatLng: function(latitude, longitude)
23101 this.setPosition(new google.maps.LatLng(latitude, longitude));
23104 getCurrentPosition: function()
23107 latitude: this.gMapContext.location.lat(),
23108 longitude: this.gMapContext.location.lng()
23112 getAddressName: function()
23114 return this.gMapContext.locationName;
23117 getAddressComponents: function()
23119 return this.gMapContext.addressComponents;
23122 address_component_from_google_geocode: function(address_components)
23126 for (var i = 0; i < address_components.length; i++) {
23127 var component = address_components[i];
23128 if (component.types.indexOf("postal_code") >= 0) {
23129 result.postalCode = component.short_name;
23130 } else if (component.types.indexOf("street_number") >= 0) {
23131 result.streetNumber = component.short_name;
23132 } else if (component.types.indexOf("route") >= 0) {
23133 result.streetName = component.short_name;
23134 } else if (component.types.indexOf("neighborhood") >= 0) {
23135 result.city = component.short_name;
23136 } else if (component.types.indexOf("locality") >= 0) {
23137 result.city = component.short_name;
23138 } else if (component.types.indexOf("sublocality") >= 0) {
23139 result.district = component.short_name;
23140 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23141 result.stateOrProvince = component.short_name;
23142 } else if (component.types.indexOf("country") >= 0) {
23143 result.country = component.short_name;
23147 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23148 result.addressLine2 = "";
23152 setZoomLevel: function(zoom)
23154 this.gMapContext.map.setZoom(zoom);
23167 this.fireEvent('show', this);
23178 this.fireEvent('hide', this);
23183 Roo.apply(Roo.bootstrap.LocationPicker, {
23185 OverlayView : function(map, options)
23187 options = options || {};
23201 * @class Roo.bootstrap.Alert
23202 * @extends Roo.bootstrap.Component
23203 * Bootstrap Alert class
23204 * @cfg {String} title The title of alert
23205 * @cfg {String} html The content of alert
23206 * @cfg {String} weight ( success | info | warning | danger )
23207 * @cfg {String} faicon font-awesomeicon
23210 * Create a new alert
23211 * @param {Object} config The config object
23215 Roo.bootstrap.Alert = function(config){
23216 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23220 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23227 getAutoCreate : function()
23236 cls : 'roo-alert-icon'
23241 cls : 'roo-alert-title',
23246 cls : 'roo-alert-text',
23253 cfg.cn[0].cls += ' fa ' + this.faicon;
23257 cfg.cls += ' alert-' + this.weight;
23263 initEvents: function()
23265 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23268 setTitle : function(str)
23270 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23273 setText : function(str)
23275 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23278 setWeight : function(weight)
23281 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23284 this.weight = weight;
23286 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23289 setIcon : function(icon)
23292 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23297 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);