4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
104 cfg.id = this.id || Roo.id();
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
129 this.el = ct.createChild(cfg, position);
132 this.tooltipEl().attr('tooltip', this.tooltip);
135 if(this.tabIndex !== undefined){
136 this.el.dom.setAttribute('tabIndex', this.tabIndex);
143 * Fetch the element to add children to
144 * @return {Roo.Element} defaults to this.el
146 getChildContainer : function()
151 * Fetch the element to display the tooltip on.
152 * @return {Roo.Element} defaults to this.el
154 tooltipEl : function()
159 addxtype : function(tree,cntr)
163 cn = Roo.factory(tree);
165 cn.parentType = this.xtype; //??
166 cn.parentId = this.id;
168 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
169 if (typeof(cn.container_method) == 'string') {
170 cntr = cn.container_method;
174 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
176 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
178 var build_from_html = Roo.XComponent.build_from_html;
180 var is_body = (tree.xtype == 'Body') ;
182 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
184 var self_cntr_el = Roo.get(this[cntr](false));
186 // do not try and build conditional elements
187 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
192 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
193 return this.addxtypeChild(tree,cntr);
196 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202 Roo.log('skipping render');
208 if (!build_from_html) {
212 // this i think handles overlaying multiple children of the same type
213 // with the sam eelement.. - which might be buggy..
215 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
221 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
230 addxtypeChild : function (tree, cntr)
232 Roo.debug && Roo.log('addxtypeChild:' + cntr);
234 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
238 (typeof(tree['flexy:foreach']) != 'undefined');
242 skip_children = false;
243 // render the element if it's not BODY.
244 if (tree.xtype != 'Body') {
246 cn = Roo.factory(tree);
248 cn.parentType = this.xtype; //??
249 cn.parentId = this.id;
251 var build_from_html = Roo.XComponent.build_from_html;
254 // does the container contain child eleemnts with 'xtype' attributes.
255 // that match this xtype..
256 // note - when we render we create these as well..
257 // so we should check to see if body has xtype set.
258 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
260 var self_cntr_el = Roo.get(this[cntr](false));
261 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
263 //Roo.log(Roo.XComponent.build_from_html);
264 //Roo.log("got echild:");
267 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
268 // and are not displayed -this causes this to use up the wrong element when matching.
269 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
273 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
279 //echild.dom.removeAttribute('xtype');
281 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
282 Roo.debug && Roo.log(self_cntr_el);
283 Roo.debug && Roo.log(echild);
284 Roo.debug && Roo.log(cn);
290 // if object has flexy:if - then it may or may not be rendered.
291 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
292 // skip a flexy if element.
293 Roo.debug && Roo.log('skipping render');
294 Roo.debug && Roo.log(tree);
296 Roo.debug && Roo.log('skipping all children');
297 skip_children = true;
302 // actually if flexy:foreach is found, we really want to create
303 // multiple copies here...
305 //Roo.log(this[cntr]());
306 cn.render(this[cntr](true));
308 // then add the element..
316 if (typeof (tree.menu) != 'undefined') {
317 tree.menu.parentType = cn.xtype;
318 tree.menu.triggerEl = cn.el;
319 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
323 if (!tree.items || !tree.items.length) {
327 var items = tree.items;
330 //Roo.log(items.length);
332 if (!skip_children) {
333 for(var i =0;i < items.length;i++) {
334 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
340 this.fireEvent('childrenrendered', this);
345 * Show a component - removes 'hidden' class
350 this.el.removeClass('hidden');
354 * Hide a component - adds 'hidden' class
358 if (this.el && !this.el.hasClass('hidden')) {
359 this.el.addClass('hidden');
373 * @class Roo.bootstrap.Body
374 * @extends Roo.bootstrap.Component
375 * Bootstrap Body class
379 * @param {Object} config The config object
382 Roo.bootstrap.Body = function(config){
383 Roo.bootstrap.Body.superclass.constructor.call(this, config);
384 this.el = Roo.get(document.body);
385 if (this.cls && this.cls.length) {
386 Roo.get(document.body).addClass(this.cls);
390 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
395 onRender : function(ct, position)
397 /* Roo.log("Roo.bootstrap.Body - onRender");
398 if (this.cls && this.cls.length) {
399 Roo.get(document.body).addClass(this.cls);
419 * @class Roo.bootstrap.ButtonGroup
420 * @extends Roo.bootstrap.Component
421 * Bootstrap ButtonGroup class
422 * @cfg {String} size lg | sm | xs (default empty normal)
423 * @cfg {String} align vertical | justified (default none)
424 * @cfg {String} direction up | down (default down)
425 * @cfg {Boolean} toolbar false | true
426 * @cfg {Boolean} btn true | false
431 * @param {Object} config The config object
434 Roo.bootstrap.ButtonGroup = function(config){
435 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
438 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
446 getAutoCreate : function(){
452 cfg.html = this.html || cfg.html;
463 if (['vertical','justified'].indexOf(this.align)!==-1) {
464 cfg.cls = 'btn-group-' + this.align;
466 if (this.align == 'justified') {
467 console.log(this.items);
471 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
472 cfg.cls += ' btn-group-' + this.size;
475 if (this.direction == 'up') {
476 cfg.cls += ' dropup' ;
492 * @class Roo.bootstrap.Button
493 * @extends Roo.bootstrap.Component
494 * Bootstrap Button class
495 * @cfg {String} html The button content
496 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
497 * @cfg {String} size ( lg | sm | xs)
498 * @cfg {String} tag ( a | input | submit)
499 * @cfg {String} href empty or href
500 * @cfg {Boolean} disabled default false;
501 * @cfg {Boolean} isClose default false;
502 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
503 * @cfg {String} badge text for badge
504 * @cfg {String} theme default
505 * @cfg {Boolean} inverse
506 * @cfg {Boolean} toggle
507 * @cfg {String} ontext text for on toggle state
508 * @cfg {String} offtext text for off toggle state
509 * @cfg {Boolean} defaulton
510 * @cfg {Boolean} preventDefault default true
511 * @cfg {Boolean} removeClass remove the standard class..
512 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
515 * Create a new button
516 * @param {Object} config The config object
520 Roo.bootstrap.Button = function(config){
521 Roo.bootstrap.Button.superclass.constructor.call(this, config);
526 * When a butotn is pressed
527 * @param {Roo.bootstrap.Button} this
528 * @param {Roo.EventObject} e
533 * After the button has been toggles
534 * @param {Roo.EventObject} e
535 * @param {boolean} pressed (also available as button.pressed)
541 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
559 preventDefault: true,
568 getAutoCreate : function(){
576 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
577 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
582 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
584 if (this.toggle == true) {
587 cls: 'slider-frame roo-button',
592 'data-off-text':'OFF',
593 cls: 'slider-button',
599 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
600 cfg.cls += ' '+this.weight;
609 cfg["aria-hidden"] = true;
611 cfg.html = "×";
617 if (this.theme==='default') {
618 cfg.cls = 'btn roo-button';
620 //if (this.parentType != 'Navbar') {
621 this.weight = this.weight.length ? this.weight : 'default';
623 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
625 cfg.cls += ' btn-' + this.weight;
627 } else if (this.theme==='glow') {
630 cfg.cls = 'btn-glow roo-button';
632 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
634 cfg.cls += ' ' + this.weight;
640 this.cls += ' inverse';
645 cfg.cls += ' active';
649 cfg.disabled = 'disabled';
653 Roo.log('changing to ul' );
655 this.glyphicon = 'caret';
658 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
660 //gsRoo.log(this.parentType);
661 if (this.parentType === 'Navbar' && !this.parent().bar) {
662 Roo.log('changing to li?');
671 href : this.href || '#'
674 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
675 cfg.cls += ' dropdown';
682 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
684 if (this.glyphicon) {
685 cfg.html = ' ' + cfg.html;
690 cls: 'glyphicon glyphicon-' + this.glyphicon
700 // cfg.cls='btn roo-button';
704 var value = cfg.html;
709 cls: 'glyphicon glyphicon-' + this.glyphicon,
728 cfg.cls += ' dropdown';
729 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
732 if (cfg.tag !== 'a' && this.href !== '') {
733 throw "Tag must be a to set href.";
734 } else if (this.href.length > 0) {
735 cfg.href = this.href;
738 if(this.removeClass){
743 cfg.target = this.target;
748 initEvents: function() {
749 // Roo.log('init events?');
750 // Roo.log(this.el.dom);
753 if (typeof (this.menu) != 'undefined') {
754 this.menu.parentType = this.xtype;
755 this.menu.triggerEl = this.el;
756 this.addxtype(Roo.apply({}, this.menu));
760 if (this.el.hasClass('roo-button')) {
761 this.el.on('click', this.onClick, this);
763 this.el.select('.roo-button').on('click', this.onClick, this);
766 if(this.removeClass){
767 this.el.on('click', this.onClick, this);
770 this.el.enableDisplayMode();
773 onClick : function(e)
780 Roo.log('button on click ');
781 if(this.preventDefault){
784 if (this.pressed === true || this.pressed === false) {
785 this.pressed = !this.pressed;
786 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
787 this.fireEvent('toggle', this, e, this.pressed);
791 this.fireEvent('click', this, e);
795 * Enables this button
799 this.disabled = false;
800 this.el.removeClass('disabled');
804 * Disable this button
808 this.disabled = true;
809 this.el.addClass('disabled');
812 * sets the active state on/off,
813 * @param {Boolean} state (optional) Force a particular state
815 setActive : function(v) {
817 this.el[v ? 'addClass' : 'removeClass']('active');
820 * toggles the current active state
822 toggleActive : function()
824 var active = this.el.hasClass('active');
825 this.setActive(!active);
829 setText : function(str)
831 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
835 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
858 * @class Roo.bootstrap.Column
859 * @extends Roo.bootstrap.Component
860 * Bootstrap Column class
861 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
862 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
863 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
864 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
865 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
866 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
867 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
868 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
871 * @cfg {Boolean} hidden (true|false) hide the element
872 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
873 * @cfg {String} fa (ban|check|...) font awesome icon
874 * @cfg {Number} fasize (1|2|....) font awsome size
876 * @cfg {String} icon (info-sign|check|...) glyphicon name
878 * @cfg {String} html content of column.
881 * Create a new Column
882 * @param {Object} config The config object
885 Roo.bootstrap.Column = function(config){
886 Roo.bootstrap.Column.superclass.constructor.call(this, config);
889 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
907 getAutoCreate : function(){
908 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
916 ['xs','sm','md','lg'].map(function(size){
917 //Roo.log( size + ':' + settings[size]);
919 if (settings[size+'off'] !== false) {
920 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
923 if (settings[size] === false) {
926 Roo.log(settings[size]);
927 if (!settings[size]) { // 0 = hidden
928 cfg.cls += ' hidden-' + size;
931 cfg.cls += ' col-' + size + '-' + settings[size];
936 cfg.cls += ' hidden';
939 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
940 cfg.cls +=' alert alert-' + this.alert;
944 if (this.html.length) {
945 cfg.html = this.html;
949 if (this.fasize > 1) {
950 fasize = ' fa-' + this.fasize + 'x';
952 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
957 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
976 * @class Roo.bootstrap.Container
977 * @extends Roo.bootstrap.Component
978 * Bootstrap Container class
979 * @cfg {Boolean} jumbotron is it a jumbotron element
980 * @cfg {String} html content of element
981 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
982 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
983 * @cfg {String} header content of header (for panel)
984 * @cfg {String} footer content of footer (for panel)
985 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
986 * @cfg {String} tag (header|aside|section) type of HTML tag.
987 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
988 * @cfg {String} fa (ban|check|...) font awesome icon
989 * @cfg {String} icon (info-sign|check|...) glyphicon name
990 * @cfg {Boolean} hidden (true|false) hide the element
991 * @cfg {Boolean} expandable (true|false) default false
992 * @cfg {String} rheader contet on the right of header
996 * Create a new Container
997 * @param {Object} config The config object
1000 Roo.bootstrap.Container = function(config){
1001 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1007 * After the panel has been expand
1009 * @param {Roo.bootstrap.Container} this
1014 * After the panel has been collapsed
1016 * @param {Roo.bootstrap.Container} this
1022 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1039 getChildContainer : function() {
1045 if (this.panel.length) {
1046 return this.el.select('.panel-body',true).first();
1053 getAutoCreate : function(){
1056 tag : this.tag || 'div',
1060 if (this.jumbotron) {
1061 cfg.cls = 'jumbotron';
1066 // - this is applied by the parent..
1068 // cfg.cls = this.cls + '';
1071 if (this.sticky.length) {
1073 var bd = Roo.get(document.body);
1074 if (!bd.hasClass('bootstrap-sticky')) {
1075 bd.addClass('bootstrap-sticky');
1076 Roo.select('html',true).setStyle('height', '100%');
1079 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1083 if (this.well.length) {
1084 switch (this.well) {
1087 cfg.cls +=' well well-' +this.well;
1096 cfg.cls += ' hidden';
1100 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1101 cfg.cls +=' alert alert-' + this.alert;
1106 if (this.panel.length) {
1107 cfg.cls += ' panel panel-' + this.panel;
1109 if (this.header.length) {
1113 if(this.expandable){
1115 cfg.cls = cfg.cls + ' expandable';
1126 cls : 'panel-title',
1131 cls: 'panel-header-right',
1137 cls : 'panel-heading',
1150 if (this.footer.length) {
1152 cls : 'panel-footer',
1161 body.html = this.html || cfg.html;
1162 // prefix with the icons..
1164 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1167 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1172 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1173 cfg.cls = 'container';
1179 initEvents: function()
1181 if(!this.expandable){
1185 var headerEl = this.headerEl();
1191 headerEl.on('click', this.onToggleClick, this);
1195 onToggleClick : function()
1197 var headerEl = this.headerEl();
1213 if(this.fireEvent('expand', this)) {
1215 this.expanded = true;
1217 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1219 var toggleEl = this.toggleEl();
1225 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1230 collapse : function()
1232 if(this.fireEvent('collapse', this)) {
1234 this.expanded = false;
1236 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1238 var toggleEl = this.toggleEl();
1244 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1248 toggleEl : function()
1250 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1254 return this.el.select('.panel-heading .fa',true).first();
1257 headerEl : function()
1259 if(!this.el || !this.panel.length || !this.header.length){
1263 return this.el.select('.panel-heading',true).first()
1266 titleEl : function()
1268 if(!this.el || !this.panel.length || !this.header.length){
1272 return this.el.select('.panel-title',true).first();
1275 setTitle : function(v)
1277 var titleEl = this.titleEl();
1283 titleEl.dom.innerHTML = v;
1286 getTitle : function()
1289 var titleEl = this.titleEl();
1295 return titleEl.dom.innerHTML;
1298 setRightTitle : function(v)
1300 var t = this.el.select('.panel-header-right',true).first();
1306 t.dom.innerHTML = v;
1320 * @class Roo.bootstrap.Img
1321 * @extends Roo.bootstrap.Component
1322 * Bootstrap Img class
1323 * @cfg {Boolean} imgResponsive false | true
1324 * @cfg {String} border rounded | circle | thumbnail
1325 * @cfg {String} src image source
1326 * @cfg {String} alt image alternative text
1327 * @cfg {String} href a tag href
1328 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1329 * @cfg {String} xsUrl xs image source
1330 * @cfg {String} smUrl sm image source
1331 * @cfg {String} mdUrl md image source
1332 * @cfg {String} lgUrl lg image source
1335 * Create a new Input
1336 * @param {Object} config The config object
1339 Roo.bootstrap.Img = function(config){
1340 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1346 * The img click event for the img.
1347 * @param {Roo.EventObject} e
1353 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1355 imgResponsive: true,
1365 getAutoCreate : function()
1367 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1368 return this.createSingleImg();
1373 cls: 'roo-image-responsive-group',
1378 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1380 if(!_this[size + 'Url']){
1386 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1387 html: _this.html || cfg.html,
1388 src: _this[size + 'Url']
1391 img.cls += ' roo-image-responsive-' + size;
1393 var s = ['xs', 'sm', 'md', 'lg'];
1395 s.splice(s.indexOf(size), 1);
1397 Roo.each(s, function(ss){
1398 img.cls += ' hidden-' + ss;
1401 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1402 cfg.cls += ' img-' + _this.border;
1406 cfg.alt = _this.alt;
1419 a.target = _this.target;
1423 cfg.cn.push((_this.href) ? a : img);
1430 createSingleImg : function()
1434 cls: (this.imgResponsive) ? 'img-responsive' : '',
1438 cfg.html = this.html || cfg.html;
1440 cfg.src = this.src || cfg.src;
1442 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1443 cfg.cls += ' img-' + this.border;
1460 a.target = this.target;
1465 return (this.href) ? a : cfg;
1468 initEvents: function()
1471 this.el.on('click', this.onClick, this);
1476 onClick : function(e)
1478 Roo.log('img onclick');
1479 this.fireEvent('click', this, e);
1493 * @class Roo.bootstrap.Link
1494 * @extends Roo.bootstrap.Component
1495 * Bootstrap Link Class
1496 * @cfg {String} alt image alternative text
1497 * @cfg {String} href a tag href
1498 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1499 * @cfg {String} html the content of the link.
1500 * @cfg {String} anchor name for the anchor link
1502 * @cfg {Boolean} preventDefault (true | false) default false
1506 * Create a new Input
1507 * @param {Object} config The config object
1510 Roo.bootstrap.Link = function(config){
1511 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1517 * The img click event for the img.
1518 * @param {Roo.EventObject} e
1524 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1528 preventDefault: false,
1532 getAutoCreate : function()
1538 // anchor's do not require html/href...
1539 if (this.anchor === false) {
1540 cfg.html = this.html || '';
1541 cfg.href = this.href || '#';
1543 cfg.name = this.anchor;
1544 if (this.html !== false) {
1545 cfg.html = this.html;
1547 if (this.href !== false) {
1548 cfg.href = this.href;
1552 if(this.alt !== false){
1557 if(this.target !== false) {
1558 cfg.target = this.target;
1564 initEvents: function() {
1566 if(!this.href || this.preventDefault){
1567 this.el.on('click', this.onClick, this);
1571 onClick : function(e)
1573 if(this.preventDefault){
1576 //Roo.log('img onclick');
1577 this.fireEvent('click', this, e);
1590 * @class Roo.bootstrap.Header
1591 * @extends Roo.bootstrap.Component
1592 * Bootstrap Header class
1593 * @cfg {String} html content of header
1594 * @cfg {Number} level (1|2|3|4|5|6) default 1
1597 * Create a new Header
1598 * @param {Object} config The config object
1602 Roo.bootstrap.Header = function(config){
1603 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1606 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1614 getAutoCreate : function(){
1619 tag: 'h' + (1 *this.level),
1620 html: this.html || ''
1632 * Ext JS Library 1.1.1
1633 * Copyright(c) 2006-2007, Ext JS, LLC.
1635 * Originally Released Under LGPL - original licence link has changed is not relivant.
1638 * <script type="text/javascript">
1642 * @class Roo.bootstrap.MenuMgr
1643 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1646 Roo.bootstrap.MenuMgr = function(){
1647 var menus, active, groups = {}, attached = false, lastShow = new Date();
1649 // private - called when first menu is created
1652 active = new Roo.util.MixedCollection();
1653 Roo.get(document).addKeyListener(27, function(){
1654 if(active.length > 0){
1662 if(active && active.length > 0){
1663 var c = active.clone();
1673 if(active.length < 1){
1674 Roo.get(document).un("mouseup", onMouseDown);
1682 var last = active.last();
1683 lastShow = new Date();
1686 Roo.get(document).on("mouseup", onMouseDown);
1691 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1692 m.parentMenu.activeChild = m;
1693 }else if(last && last.isVisible()){
1694 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1699 function onBeforeHide(m){
1701 m.activeChild.hide();
1703 if(m.autoHideTimer){
1704 clearTimeout(m.autoHideTimer);
1705 delete m.autoHideTimer;
1710 function onBeforeShow(m){
1711 var pm = m.parentMenu;
1712 if(!pm && !m.allowOtherMenus){
1714 }else if(pm && pm.activeChild && active != m){
1715 pm.activeChild.hide();
1719 // private this should really trigger on mouseup..
1720 function onMouseDown(e){
1721 Roo.log("on Mouse Up");
1722 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1732 function onBeforeCheck(mi, state){
1734 var g = groups[mi.group];
1735 for(var i = 0, l = g.length; i < l; i++){
1737 g[i].setChecked(false);
1746 * Hides all menus that are currently visible
1748 hideAll : function(){
1753 register : function(menu){
1757 menus[menu.id] = menu;
1758 menu.on("beforehide", onBeforeHide);
1759 menu.on("hide", onHide);
1760 menu.on("beforeshow", onBeforeShow);
1761 menu.on("show", onShow);
1763 if(g && menu.events["checkchange"]){
1767 groups[g].push(menu);
1768 menu.on("checkchange", onCheck);
1773 * Returns a {@link Roo.menu.Menu} object
1774 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1775 * be used to generate and return a new Menu instance.
1777 get : function(menu){
1778 if(typeof menu == "string"){ // menu id
1780 }else if(menu.events){ // menu instance
1783 /*else if(typeof menu.length == 'number'){ // array of menu items?
1784 return new Roo.bootstrap.Menu({items:menu});
1785 }else{ // otherwise, must be a config
1786 return new Roo.bootstrap.Menu(menu);
1793 unregister : function(menu){
1794 delete menus[menu.id];
1795 menu.un("beforehide", onBeforeHide);
1796 menu.un("hide", onHide);
1797 menu.un("beforeshow", onBeforeShow);
1798 menu.un("show", onShow);
1800 if(g && menu.events["checkchange"]){
1801 groups[g].remove(menu);
1802 menu.un("checkchange", onCheck);
1807 registerCheckable : function(menuItem){
1808 var g = menuItem.group;
1813 groups[g].push(menuItem);
1814 menuItem.on("beforecheckchange", onBeforeCheck);
1819 unregisterCheckable : function(menuItem){
1820 var g = menuItem.group;
1822 groups[g].remove(menuItem);
1823 menuItem.un("beforecheckchange", onBeforeCheck);
1835 * @class Roo.bootstrap.Menu
1836 * @extends Roo.bootstrap.Component
1837 * Bootstrap Menu class - container for MenuItems
1838 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1842 * @param {Object} config The config object
1846 Roo.bootstrap.Menu = function(config){
1847 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1848 if (this.registerMenu) {
1849 Roo.bootstrap.MenuMgr.register(this);
1854 * Fires before this menu is displayed
1855 * @param {Roo.menu.Menu} this
1860 * Fires before this menu is hidden
1861 * @param {Roo.menu.Menu} this
1866 * Fires after this menu is displayed
1867 * @param {Roo.menu.Menu} this
1872 * Fires after this menu is hidden
1873 * @param {Roo.menu.Menu} this
1878 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1879 * @param {Roo.menu.Menu} this
1880 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1881 * @param {Roo.EventObject} e
1886 * Fires when the mouse is hovering over this menu
1887 * @param {Roo.menu.Menu} this
1888 * @param {Roo.EventObject} e
1889 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1894 * Fires when the mouse exits this menu
1895 * @param {Roo.menu.Menu} this
1896 * @param {Roo.EventObject} e
1897 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1902 * Fires when a menu item contained in this menu is clicked
1903 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1904 * @param {Roo.EventObject} e
1908 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1911 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1915 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1918 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1920 registerMenu : true,
1922 menuItems :false, // stores the menu items..
1928 getChildContainer : function() {
1932 getAutoCreate : function(){
1934 //if (['right'].indexOf(this.align)!==-1) {
1935 // cfg.cn[1].cls += ' pull-right'
1941 cls : 'dropdown-menu' ,
1942 style : 'z-index:1000'
1946 if (this.type === 'submenu') {
1947 cfg.cls = 'submenu active';
1949 if (this.type === 'treeview') {
1950 cfg.cls = 'treeview-menu';
1955 initEvents : function() {
1957 // Roo.log("ADD event");
1958 // Roo.log(this.triggerEl.dom);
1959 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1961 this.triggerEl.addClass('dropdown-toggle');
1962 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1964 this.el.on("mouseover", this.onMouseOver, this);
1965 this.el.on("mouseout", this.onMouseOut, this);
1969 findTargetItem : function(e){
1970 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1974 //Roo.log(t); Roo.log(t.id);
1976 //Roo.log(this.menuitems);
1977 return this.menuitems.get(t.id);
1979 //return this.items.get(t.menuItemId);
1984 onClick : function(e){
1985 Roo.log("menu.onClick");
1986 var t = this.findTargetItem(e);
1987 if(!t || t.isContainer){
1992 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1993 if(t == this.activeItem && t.shouldDeactivate(e)){
1994 this.activeItem.deactivate();
1995 delete this.activeItem;
1999 this.setActiveItem(t, true);
2007 Roo.log('pass click event');
2011 this.fireEvent("click", this, t, e);
2015 onMouseOver : function(e){
2016 var t = this.findTargetItem(e);
2019 // if(t.canActivate && !t.disabled){
2020 // this.setActiveItem(t, true);
2024 this.fireEvent("mouseover", this, e, t);
2026 isVisible : function(){
2027 return !this.hidden;
2029 onMouseOut : function(e){
2030 var t = this.findTargetItem(e);
2033 // if(t == this.activeItem && t.shouldDeactivate(e)){
2034 // this.activeItem.deactivate();
2035 // delete this.activeItem;
2038 this.fireEvent("mouseout", this, e, t);
2043 * Displays this menu relative to another element
2044 * @param {String/HTMLElement/Roo.Element} element The element to align to
2045 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2046 * the element (defaults to this.defaultAlign)
2047 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2049 show : function(el, pos, parentMenu){
2050 this.parentMenu = parentMenu;
2054 this.fireEvent("beforeshow", this);
2055 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2058 * Displays this menu at a specific xy position
2059 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2060 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2062 showAt : function(xy, parentMenu, /* private: */_e){
2063 this.parentMenu = parentMenu;
2068 this.fireEvent("beforeshow", this);
2069 //xy = this.el.adjustForConstraints(xy);
2073 this.hideMenuItems();
2074 this.hidden = false;
2075 this.triggerEl.addClass('open');
2077 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2078 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2083 this.fireEvent("show", this);
2089 this.doFocus.defer(50, this);
2093 doFocus : function(){
2095 this.focusEl.focus();
2100 * Hides this menu and optionally all parent menus
2101 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2103 hide : function(deep){
2105 this.hideMenuItems();
2106 if(this.el && this.isVisible()){
2107 this.fireEvent("beforehide", this);
2108 if(this.activeItem){
2109 this.activeItem.deactivate();
2110 this.activeItem = null;
2112 this.triggerEl.removeClass('open');;
2114 this.fireEvent("hide", this);
2116 if(deep === true && this.parentMenu){
2117 this.parentMenu.hide(true);
2121 onTriggerPress : function(e)
2124 Roo.log('trigger press');
2125 //Roo.log(e.getTarget());
2126 // Roo.log(this.triggerEl.dom);
2127 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2131 if (this.isVisible()) {
2136 this.show(this.triggerEl, false, false);
2145 hideMenuItems : function()
2147 //$(backdrop).remove()
2148 Roo.select('.open',true).each(function(aa) {
2150 aa.removeClass('open');
2151 //var parent = getParent($(this))
2152 //var relatedTarget = { relatedTarget: this }
2154 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2155 //if (e.isDefaultPrevented()) return
2156 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2159 addxtypeChild : function (tree, cntr) {
2160 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2162 this.menuitems.add(comp);
2183 * @class Roo.bootstrap.MenuItem
2184 * @extends Roo.bootstrap.Component
2185 * Bootstrap MenuItem class
2186 * @cfg {String} html the menu label
2187 * @cfg {String} href the link
2188 * @cfg {Boolean} preventDefault (true | false) default true
2189 * @cfg {Boolean} isContainer (true | false) default false
2193 * Create a new MenuItem
2194 * @param {Object} config The config object
2198 Roo.bootstrap.MenuItem = function(config){
2199 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2204 * The raw click event for the entire grid.
2205 * @param {Roo.bootstrap.MenuItem} this
2206 * @param {Roo.EventObject} e
2212 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2216 preventDefault: true,
2217 isContainer : false,
2219 getAutoCreate : function(){
2221 if(this.isContainer){
2224 cls: 'dropdown-menu-item'
2230 cls: 'dropdown-menu-item',
2239 if (this.parent().type == 'treeview') {
2240 cfg.cls = 'treeview-menu';
2243 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2244 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2248 initEvents: function() {
2250 //this.el.select('a').on('click', this.onClick, this);
2253 onClick : function(e)
2255 Roo.log('item on click ');
2256 //if(this.preventDefault){
2257 // e.preventDefault();
2259 //this.parent().hideMenuItems();
2261 this.fireEvent('click', this, e);
2280 * @class Roo.bootstrap.MenuSeparator
2281 * @extends Roo.bootstrap.Component
2282 * Bootstrap MenuSeparator class
2285 * Create a new MenuItem
2286 * @param {Object} config The config object
2290 Roo.bootstrap.MenuSeparator = function(config){
2291 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2294 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2296 getAutoCreate : function(){
2315 * @class Roo.bootstrap.Modal
2316 * @extends Roo.bootstrap.Component
2317 * Bootstrap Modal class
2318 * @cfg {String} title Title of dialog
2319 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2320 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2321 * @cfg {Boolean} specificTitle default false
2322 * @cfg {Array} buttons Array of buttons or standard button set..
2323 * @cfg {String} buttonPosition (left|right|center) default right
2324 * @cfg {Boolean} animate default true
2325 * @cfg {Boolean} allow_close default true
2328 * Create a new Modal Dialog
2329 * @param {Object} config The config object
2332 Roo.bootstrap.Modal = function(config){
2333 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2338 * The raw btnclick event for the button
2339 * @param {Roo.EventObject} e
2343 this.buttons = this.buttons || [];
2346 this.tmpl = Roo.factory(this.tmpl);
2351 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2353 title : 'test dialog',
2363 specificTitle: false,
2365 buttonPosition: 'right',
2379 onRender : function(ct, position)
2381 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2384 var cfg = Roo.apply({}, this.getAutoCreate());
2387 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2389 //if (!cfg.name.length) {
2393 cfg.cls += ' ' + this.cls;
2396 cfg.style = this.style;
2398 this.el = Roo.get(document.body).createChild(cfg, position);
2400 //var type = this.el.dom.type;
2405 if(this.tabIndex !== undefined){
2406 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2410 this.bodyEl = this.el.select('.modal-body',true).first();
2411 this.closeEl = this.el.select('.modal-header .close', true).first();
2412 this.footerEl = this.el.select('.modal-footer',true).first();
2413 this.titleEl = this.el.select('.modal-title',true).first();
2417 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2418 this.maskEl.enableDisplayMode("block");
2420 //this.el.addClass("x-dlg-modal");
2422 if (this.buttons.length) {
2423 Roo.each(this.buttons, function(bb) {
2424 b = Roo.apply({}, bb);
2425 b.xns = b.xns || Roo.bootstrap;
2426 b.xtype = b.xtype || 'Button';
2427 if (typeof(b.listeners) == 'undefined') {
2428 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2431 var btn = Roo.factory(b);
2433 btn.onRender(this.el.select('.modal-footer div').first());
2437 // render the children.
2440 if(typeof(this.items) != 'undefined'){
2441 var items = this.items;
2444 for(var i =0;i < items.length;i++) {
2445 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2449 this.items = nitems;
2451 // where are these used - they used to be body/close/footer
2455 //this.el.addClass([this.fieldClass, this.cls]);
2458 getAutoCreate : function(){
2463 html : this.html || ''
2468 cls : 'modal-title',
2472 if(this.specificTitle){
2478 if (this.allow_close) {
2489 style : 'display: none',
2492 cls: "modal-dialog",
2495 cls : "modal-content",
2498 cls : 'modal-header',
2503 cls : 'modal-footer',
2507 cls: 'btn-' + this.buttonPosition
2524 modal.cls += ' fade';
2530 getChildContainer : function() {
2535 getButtonContainer : function() {
2536 return this.el.select('.modal-footer div',true).first();
2539 initEvents : function()
2541 if (this.allow_close) {
2542 this.closeEl.on('click', this.hide, this);
2548 if (!this.rendered) {
2552 this.el.setStyle('display', 'block');
2556 (function(){ _this.el.addClass('in'); }).defer(50);
2558 this.el.addClass('in');
2561 // not sure how we can show data in here..
2563 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2566 Roo.get(document.body).addClass("x-body-masked");
2567 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2569 this.el.setStyle('zIndex', '10001');
2571 this.fireEvent('show', this);
2578 Roo.get(document.body).removeClass("x-body-masked");
2579 this.el.removeClass('in');
2583 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2585 this.el.setStyle('display', 'none');
2588 this.fireEvent('hide', this);
2591 addButton : function(str, cb)
2595 var b = Roo.apply({}, { html : str } );
2596 b.xns = b.xns || Roo.bootstrap;
2597 b.xtype = b.xtype || 'Button';
2598 if (typeof(b.listeners) == 'undefined') {
2599 b.listeners = { click : cb.createDelegate(this) };
2602 var btn = Roo.factory(b);
2604 btn.onRender(this.el.select('.modal-footer div').first());
2610 setDefaultButton : function(btn)
2612 //this.el.select('.modal-footer').()
2614 resizeTo: function(w,h)
2618 setContentSize : function(w, h)
2622 onButtonClick: function(btn,e)
2625 this.fireEvent('btnclick', btn.name, e);
2628 * Set the title of the Dialog
2629 * @param {String} str new Title
2631 setTitle: function(str) {
2632 this.titleEl.dom.innerHTML = str;
2635 * Set the body of the Dialog
2636 * @param {String} str new Title
2638 setBody: function(str) {
2639 this.bodyEl.dom.innerHTML = str;
2642 * Set the body of the Dialog using the template
2643 * @param {Obj} data - apply this data to the template and replace the body contents.
2645 applyBody: function(obj)
2648 Roo.log("Error - using apply Body without a template");
2651 this.tmpl.overwrite(this.bodyEl, obj);
2657 Roo.apply(Roo.bootstrap.Modal, {
2659 * Button config that displays a single OK button
2668 * Button config that displays Yes and No buttons
2684 * Button config that displays OK and Cancel buttons
2699 * Button config that displays Yes, No and Cancel buttons
2722 * messagebox - can be used as a replace
2726 * @class Roo.MessageBox
2727 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2731 Roo.Msg.alert('Status', 'Changes saved successfully.');
2733 // Prompt for user data:
2734 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2736 // process text value...
2740 // Show a dialog using config options:
2742 title:'Save Changes?',
2743 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2744 buttons: Roo.Msg.YESNOCANCEL,
2751 Roo.bootstrap.MessageBox = function(){
2752 var dlg, opt, mask, waitTimer;
2753 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2754 var buttons, activeTextEl, bwidth;
2758 var handleButton = function(button){
2760 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2764 var handleHide = function(){
2766 dlg.el.removeClass(opt.cls);
2769 // Roo.TaskMgr.stop(waitTimer);
2770 // waitTimer = null;
2775 var updateButtons = function(b){
2778 buttons["ok"].hide();
2779 buttons["cancel"].hide();
2780 buttons["yes"].hide();
2781 buttons["no"].hide();
2782 //dlg.footer.dom.style.display = 'none';
2785 dlg.footerEl.dom.style.display = '';
2786 for(var k in buttons){
2787 if(typeof buttons[k] != "function"){
2790 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2791 width += buttons[k].el.getWidth()+15;
2801 var handleEsc = function(d, k, e){
2802 if(opt && opt.closable !== false){
2812 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2813 * @return {Roo.BasicDialog} The BasicDialog element
2815 getDialog : function(){
2817 dlg = new Roo.bootstrap.Modal( {
2820 //constraintoviewport:false,
2822 //collapsible : false,
2827 //buttonAlign:"center",
2828 closeClick : function(){
2829 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2832 handleButton("cancel");
2837 dlg.on("hide", handleHide);
2839 //dlg.addKeyListener(27, handleEsc);
2841 this.buttons = buttons;
2842 var bt = this.buttonText;
2843 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2844 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2845 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2846 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2848 bodyEl = dlg.bodyEl.createChild({
2850 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2851 '<textarea class="roo-mb-textarea"></textarea>' +
2852 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2854 msgEl = bodyEl.dom.firstChild;
2855 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2856 textboxEl.enableDisplayMode();
2857 textboxEl.addKeyListener([10,13], function(){
2858 if(dlg.isVisible() && opt && opt.buttons){
2861 }else if(opt.buttons.yes){
2862 handleButton("yes");
2866 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2867 textareaEl.enableDisplayMode();
2868 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2869 progressEl.enableDisplayMode();
2870 var pf = progressEl.dom.firstChild;
2872 pp = Roo.get(pf.firstChild);
2873 pp.setHeight(pf.offsetHeight);
2881 * Updates the message box body text
2882 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2883 * the XHTML-compliant non-breaking space character '&#160;')
2884 * @return {Roo.MessageBox} This message box
2886 updateText : function(text){
2887 if(!dlg.isVisible() && !opt.width){
2888 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2890 msgEl.innerHTML = text || ' ';
2892 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2893 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2895 Math.min(opt.width || cw , this.maxWidth),
2896 Math.max(opt.minWidth || this.minWidth, bwidth)
2899 activeTextEl.setWidth(w);
2901 if(dlg.isVisible()){
2902 dlg.fixedcenter = false;
2904 // to big, make it scroll. = But as usual stupid IE does not support
2907 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2908 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2909 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2911 bodyEl.dom.style.height = '';
2912 bodyEl.dom.style.overflowY = '';
2915 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2917 bodyEl.dom.style.overflowX = '';
2920 dlg.setContentSize(w, bodyEl.getHeight());
2921 if(dlg.isVisible()){
2922 dlg.fixedcenter = true;
2928 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2929 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2930 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2931 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2932 * @return {Roo.MessageBox} This message box
2934 updateProgress : function(value, text){
2936 this.updateText(text);
2938 if (pp) { // weird bug on my firefox - for some reason this is not defined
2939 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2945 * Returns true if the message box is currently displayed
2946 * @return {Boolean} True if the message box is visible, else false
2948 isVisible : function(){
2949 return dlg && dlg.isVisible();
2953 * Hides the message box if it is displayed
2956 if(this.isVisible()){
2962 * Displays a new message box, or reinitializes an existing message box, based on the config options
2963 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2964 * The following config object properties are supported:
2966 Property Type Description
2967 ---------- --------------- ------------------------------------------------------------------------------------
2968 animEl String/Element An id or Element from which the message box should animate as it opens and
2969 closes (defaults to undefined)
2970 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2971 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2972 closable Boolean False to hide the top-right close button (defaults to true). Note that
2973 progress and wait dialogs will ignore this property and always hide the
2974 close button as they can only be closed programmatically.
2975 cls String A custom CSS class to apply to the message box element
2976 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2977 displayed (defaults to 75)
2978 fn Function A callback function to execute after closing the dialog. The arguments to the
2979 function will be btn (the name of the button that was clicked, if applicable,
2980 e.g. "ok"), and text (the value of the active text field, if applicable).
2981 Progress and wait dialogs will ignore this option since they do not respond to
2982 user actions and can only be closed programmatically, so any required function
2983 should be called by the same code after it closes the dialog.
2984 icon String A CSS class that provides a background image to be used as an icon for
2985 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2986 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2987 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2988 modal Boolean False to allow user interaction with the page while the message box is
2989 displayed (defaults to true)
2990 msg String A string that will replace the existing message box body text (defaults
2991 to the XHTML-compliant non-breaking space character ' ')
2992 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2993 progress Boolean True to display a progress bar (defaults to false)
2994 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2995 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2996 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2997 title String The title text
2998 value String The string value to set into the active textbox element if displayed
2999 wait Boolean True to display a progress bar (defaults to false)
3000 width Number The width of the dialog in pixels
3007 msg: 'Please enter your address:',
3009 buttons: Roo.MessageBox.OKCANCEL,
3012 animEl: 'addAddressBtn'
3015 * @param {Object} config Configuration options
3016 * @return {Roo.MessageBox} This message box
3018 show : function(options)
3021 // this causes nightmares if you show one dialog after another
3022 // especially on callbacks..
3024 if(this.isVisible()){
3027 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3028 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3029 Roo.log("New Dialog Message:" + options.msg )
3030 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3031 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3034 var d = this.getDialog();
3036 d.setTitle(opt.title || " ");
3037 d.closeEl.setDisplayed(opt.closable !== false);
3038 activeTextEl = textboxEl;
3039 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3044 textareaEl.setHeight(typeof opt.multiline == "number" ?
3045 opt.multiline : this.defaultTextHeight);
3046 activeTextEl = textareaEl;
3055 progressEl.setDisplayed(opt.progress === true);
3056 this.updateProgress(0);
3057 activeTextEl.dom.value = opt.value || "";
3059 dlg.setDefaultButton(activeTextEl);
3061 var bs = opt.buttons;
3065 }else if(bs && bs.yes){
3066 db = buttons["yes"];
3068 dlg.setDefaultButton(db);
3070 bwidth = updateButtons(opt.buttons);
3071 this.updateText(opt.msg);
3073 d.el.addClass(opt.cls);
3075 d.proxyDrag = opt.proxyDrag === true;
3076 d.modal = opt.modal !== false;
3077 d.mask = opt.modal !== false ? mask : false;
3079 // force it to the end of the z-index stack so it gets a cursor in FF
3080 document.body.appendChild(dlg.el.dom);
3081 d.animateTarget = null;
3082 d.show(options.animEl);
3088 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3089 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3090 * and closing the message box when the process is complete.
3091 * @param {String} title The title bar text
3092 * @param {String} msg The message box body text
3093 * @return {Roo.MessageBox} This message box
3095 progress : function(title, msg){
3102 minWidth: this.minProgressWidth,
3109 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3110 * If a callback function is passed it will be called after the user clicks the button, and the
3111 * id of the button that was clicked will be passed as the only parameter to the callback
3112 * (could also be the top-right close button).
3113 * @param {String} title The title bar text
3114 * @param {String} msg The message box body text
3115 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3116 * @param {Object} scope (optional) The scope of the callback function
3117 * @return {Roo.MessageBox} This message box
3119 alert : function(title, msg, fn, scope){
3132 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3133 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3134 * You are responsible for closing the message box when the process is complete.
3135 * @param {String} msg The message box body text
3136 * @param {String} title (optional) The title bar text
3137 * @return {Roo.MessageBox} This message box
3139 wait : function(msg, title){
3150 waitTimer = Roo.TaskMgr.start({
3152 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3160 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3161 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3162 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3163 * @param {String} title The title bar text
3164 * @param {String} msg The message box body text
3165 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3166 * @param {Object} scope (optional) The scope of the callback function
3167 * @return {Roo.MessageBox} This message box
3169 confirm : function(title, msg, fn, scope){
3173 buttons: this.YESNO,
3182 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3183 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3184 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3185 * (could also be the top-right close button) and the text that was entered will be passed as the two
3186 * parameters to the callback.
3187 * @param {String} title The title bar text
3188 * @param {String} msg The message box body text
3189 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3190 * @param {Object} scope (optional) The scope of the callback function
3191 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3192 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3193 * @return {Roo.MessageBox} This message box
3195 prompt : function(title, msg, fn, scope, multiline){
3199 buttons: this.OKCANCEL,
3204 multiline: multiline,
3211 * Button config that displays a single OK button
3216 * Button config that displays Yes and No buttons
3219 YESNO : {yes:true, no:true},
3221 * Button config that displays OK and Cancel buttons
3224 OKCANCEL : {ok:true, cancel:true},
3226 * Button config that displays Yes, No and Cancel buttons
3229 YESNOCANCEL : {yes:true, no:true, cancel:true},
3232 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3235 defaultTextHeight : 75,
3237 * The maximum width in pixels of the message box (defaults to 600)
3242 * The minimum width in pixels of the message box (defaults to 100)
3247 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3248 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3251 minProgressWidth : 250,
3253 * An object containing the default button text strings that can be overriden for localized language support.
3254 * Supported properties are: ok, cancel, yes and no.
3255 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3268 * Shorthand for {@link Roo.MessageBox}
3270 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3271 Roo.Msg = Roo.Msg || Roo.MessageBox;
3280 * @class Roo.bootstrap.Navbar
3281 * @extends Roo.bootstrap.Component
3282 * Bootstrap Navbar class
3285 * Create a new Navbar
3286 * @param {Object} config The config object
3290 Roo.bootstrap.Navbar = function(config){
3291 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3295 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3304 getAutoCreate : function(){
3307 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3311 initEvents :function ()
3313 //Roo.log(this.el.select('.navbar-toggle',true));
3314 this.el.select('.navbar-toggle',true).on('click', function() {
3315 // Roo.log('click');
3316 this.el.select('.navbar-collapse',true).toggleClass('in');
3324 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3326 var size = this.el.getSize();
3327 this.maskEl.setSize(size.width, size.height);
3328 this.maskEl.enableDisplayMode("block");
3337 getChildContainer : function()
3339 if (this.el.select('.collapse').getCount()) {
3340 return this.el.select('.collapse',true).first();
3373 * @class Roo.bootstrap.NavSimplebar
3374 * @extends Roo.bootstrap.Navbar
3375 * Bootstrap Sidebar class
3377 * @cfg {Boolean} inverse is inverted color
3379 * @cfg {String} type (nav | pills | tabs)
3380 * @cfg {Boolean} arrangement stacked | justified
3381 * @cfg {String} align (left | right) alignment
3383 * @cfg {Boolean} main (true|false) main nav bar? default false
3384 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3386 * @cfg {String} tag (header|footer|nav|div) default is nav
3392 * Create a new Sidebar
3393 * @param {Object} config The config object
3397 Roo.bootstrap.NavSimplebar = function(config){
3398 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3401 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3417 getAutoCreate : function(){
3421 tag : this.tag || 'div',
3434 this.type = this.type || 'nav';
3435 if (['tabs','pills'].indexOf(this.type)!==-1) {
3436 cfg.cn[0].cls += ' nav-' + this.type
3440 if (this.type!=='nav') {
3441 Roo.log('nav type must be nav/tabs/pills')
3443 cfg.cn[0].cls += ' navbar-nav'
3449 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3450 cfg.cn[0].cls += ' nav-' + this.arrangement;
3454 if (this.align === 'right') {
3455 cfg.cn[0].cls += ' navbar-right';
3459 cfg.cls += ' navbar-inverse';
3486 * @class Roo.bootstrap.NavHeaderbar
3487 * @extends Roo.bootstrap.NavSimplebar
3488 * Bootstrap Sidebar class
3490 * @cfg {String} brand what is brand
3491 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3492 * @cfg {String} brand_href href of the brand
3493 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3494 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3495 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3496 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3499 * Create a new Sidebar
3500 * @param {Object} config The config object
3504 Roo.bootstrap.NavHeaderbar = function(config){
3505 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3509 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3516 desktopCenter : false,
3519 getAutoCreate : function(){
3522 tag: this.nav || 'nav',
3529 if (this.desktopCenter) {
3530 cn.push({cls : 'container', cn : []});
3537 cls: 'navbar-header',
3542 cls: 'navbar-toggle',
3543 'data-toggle': 'collapse',
3548 html: 'Toggle navigation'
3570 cls: 'collapse navbar-collapse',
3574 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3576 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3577 cfg.cls += ' navbar-' + this.position;
3579 // tag can override this..
3581 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3584 if (this.brand !== '') {
3587 href: this.brand_href ? this.brand_href : '#',
3588 cls: 'navbar-brand',
3596 cfg.cls += ' main-nav';
3604 getHeaderChildContainer : function()
3606 if (this.el.select('.navbar-header').getCount()) {
3607 return this.el.select('.navbar-header',true).first();
3610 return this.getChildContainer();
3614 initEvents : function()
3616 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3618 if (this.autohide) {
3623 Roo.get(document).on('scroll',function(e) {
3624 var ns = Roo.get(document).getScroll().top;
3625 var os = prevScroll;
3629 ft.removeClass('slideDown');
3630 ft.addClass('slideUp');
3633 ft.removeClass('slideUp');
3634 ft.addClass('slideDown');
3655 * @class Roo.bootstrap.NavSidebar
3656 * @extends Roo.bootstrap.Navbar
3657 * Bootstrap Sidebar class
3660 * Create a new Sidebar
3661 * @param {Object} config The config object
3665 Roo.bootstrap.NavSidebar = function(config){
3666 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3669 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3671 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3673 getAutoCreate : function(){
3678 cls: 'sidebar sidebar-nav'
3700 * @class Roo.bootstrap.NavGroup
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap NavGroup class
3703 * @cfg {String} align (left|right)
3704 * @cfg {Boolean} inverse
3705 * @cfg {String} type (nav|pills|tab) default nav
3706 * @cfg {String} navId - reference Id for navbar.
3710 * Create a new nav group
3711 * @param {Object} config The config object
3714 Roo.bootstrap.NavGroup = function(config){
3715 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3718 Roo.bootstrap.NavGroup.register(this);
3722 * Fires when the active item changes
3723 * @param {Roo.bootstrap.NavGroup} this
3724 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3725 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3732 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3743 getAutoCreate : function()
3745 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3752 if (['tabs','pills'].indexOf(this.type)!==-1) {
3753 cfg.cls += ' nav-' + this.type
3755 if (this.type!=='nav') {
3756 Roo.log('nav type must be nav/tabs/pills')
3758 cfg.cls += ' navbar-nav'
3761 if (this.parent().sidebar) {
3764 cls: 'dashboard-menu sidebar-menu'
3770 if (this.form === true) {
3776 if (this.align === 'right') {
3777 cfg.cls += ' navbar-right';
3779 cfg.cls += ' navbar-left';
3783 if (this.align === 'right') {
3784 cfg.cls += ' navbar-right';
3788 cfg.cls += ' navbar-inverse';
3796 * sets the active Navigation item
3797 * @param {Roo.bootstrap.NavItem} the new current navitem
3799 setActiveItem : function(item)
3802 Roo.each(this.navItems, function(v){
3807 v.setActive(false, true);
3814 item.setActive(true, true);
3815 this.fireEvent('changed', this, item, prev);
3820 * gets the active Navigation item
3821 * @return {Roo.bootstrap.NavItem} the current navitem
3823 getActive : function()
3827 Roo.each(this.navItems, function(v){
3838 indexOfNav : function()
3842 Roo.each(this.navItems, function(v,i){
3853 * adds a Navigation item
3854 * @param {Roo.bootstrap.NavItem} the navitem to add
3856 addItem : function(cfg)
3858 var cn = new Roo.bootstrap.NavItem(cfg);
3860 cn.parentId = this.id;
3861 cn.onRender(this.el, null);
3865 * register a Navigation item
3866 * @param {Roo.bootstrap.NavItem} the navitem to add
3868 register : function(item)
3870 this.navItems.push( item);
3871 item.navId = this.navId;
3876 * clear all the Navigation item
3879 clearAll : function()
3882 this.el.dom.innerHTML = '';
3885 getNavItem: function(tabId)
3888 Roo.each(this.navItems, function(e) {
3889 if (e.tabId == tabId) {
3899 setActiveNext : function()
3901 var i = this.indexOfNav(this.getActive());
3902 if (i > this.navItems.length) {
3905 this.setActiveItem(this.navItems[i+1]);
3907 setActivePrev : function()
3909 var i = this.indexOfNav(this.getActive());
3913 this.setActiveItem(this.navItems[i-1]);
3915 clearWasActive : function(except) {
3916 Roo.each(this.navItems, function(e) {
3917 if (e.tabId != except.tabId && e.was_active) {
3918 e.was_active = false;
3925 getWasActive : function ()
3928 Roo.each(this.navItems, function(e) {
3943 Roo.apply(Roo.bootstrap.NavGroup, {
3947 * register a Navigation Group
3948 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3950 register : function(navgrp)
3952 this.groups[navgrp.navId] = navgrp;
3956 * fetch a Navigation Group based on the navigation ID
3957 * @param {string} the navgroup to add
3958 * @returns {Roo.bootstrap.NavGroup} the navgroup
3960 get: function(navId) {
3961 if (typeof(this.groups[navId]) == 'undefined') {
3963 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3965 return this.groups[navId] ;
3980 * @class Roo.bootstrap.NavItem
3981 * @extends Roo.bootstrap.Component
3982 * Bootstrap Navbar.NavItem class
3983 * @cfg {String} href link to
3984 * @cfg {String} html content of button
3985 * @cfg {String} badge text inside badge
3986 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3987 * @cfg {String} glyphicon name of glyphicon
3988 * @cfg {String} icon name of font awesome icon
3989 * @cfg {Boolean} active Is item active
3990 * @cfg {Boolean} disabled Is item disabled
3992 * @cfg {Boolean} preventDefault (true | false) default false
3993 * @cfg {String} tabId the tab that this item activates.
3994 * @cfg {String} tagtype (a|span) render as a href or span?
3995 * @cfg {Boolean} animateRef (true|false) link to element default false
3998 * Create a new Navbar Item
3999 * @param {Object} config The config object
4001 Roo.bootstrap.NavItem = function(config){
4002 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4007 * The raw click event for the entire grid.
4008 * @param {Roo.EventObject} e
4013 * Fires when the active item active state changes
4014 * @param {Roo.bootstrap.NavItem} this
4015 * @param {boolean} state the new state
4021 * Fires when scroll to element
4022 * @param {Roo.bootstrap.NavItem} this
4023 * @param {Object} options
4024 * @param {Roo.EventObject} e
4032 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4040 preventDefault : false,
4047 getAutoCreate : function(){
4055 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4057 if (this.disabled) {
4058 cfg.cls += ' disabled';
4061 if (this.href || this.html || this.glyphicon || this.icon) {
4065 href : this.href || "#",
4066 html: this.html || ''
4071 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4074 if(this.glyphicon) {
4075 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4080 cfg.cn[0].html += " <span class='caret'></span>";
4084 if (this.badge !== '') {
4086 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4094 initEvents: function()
4096 if (typeof (this.menu) != 'undefined') {
4097 this.menu.parentType = this.xtype;
4098 this.menu.triggerEl = this.el;
4099 this.menu = this.addxtype(Roo.apply({}, this.menu));
4102 this.el.select('a',true).on('click', this.onClick, this);
4104 if(this.tagtype == 'span'){
4105 this.el.select('span',true).on('click', this.onClick, this);
4108 // at this point parent should be available..
4109 this.parent().register(this);
4112 onClick : function(e)
4115 this.preventDefault ||
4122 if (this.disabled) {
4126 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4127 if (tg && tg.transition) {
4128 Roo.log("waiting for the transitionend");
4134 //Roo.log("fire event clicked");
4135 if(this.fireEvent('click', this, e) === false){
4139 if(this.tagtype == 'span'){
4143 //Roo.log(this.href);
4144 var ael = this.el.select('a',true).first();
4147 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4148 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4149 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4150 return; // ignore... - it's a 'hash' to another page.
4154 this.scrollToElement(e);
4158 var p = this.parent();
4160 if (['tabs','pills'].indexOf(p.type)!==-1) {
4161 if (typeof(p.setActiveItem) !== 'undefined') {
4162 p.setActiveItem(this);
4166 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4167 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4168 // remove the collapsed menu expand...
4169 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4173 isActive: function () {
4176 setActive : function(state, fire, is_was_active)
4178 if (this.active && !state & this.navId) {
4179 this.was_active = true;
4180 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4182 nv.clearWasActive(this);
4186 this.active = state;
4189 this.el.removeClass('active');
4190 } else if (!this.el.hasClass('active')) {
4191 this.el.addClass('active');
4194 this.fireEvent('changed', this, state);
4197 // show a panel if it's registered and related..
4199 if (!this.navId || !this.tabId || !state || is_was_active) {
4203 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4207 var pan = tg.getPanelByName(this.tabId);
4211 // if we can not flip to new panel - go back to old nav highlight..
4212 if (false == tg.showPanel(pan)) {
4213 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4215 var onav = nv.getWasActive();
4217 onav.setActive(true, false, true);
4226 // this should not be here...
4227 setDisabled : function(state)
4229 this.disabled = state;
4231 this.el.removeClass('disabled');
4232 } else if (!this.el.hasClass('disabled')) {
4233 this.el.addClass('disabled');
4239 * Fetch the element to display the tooltip on.
4240 * @return {Roo.Element} defaults to this.el
4242 tooltipEl : function()
4244 return this.el.select('' + this.tagtype + '', true).first();
4247 scrollToElement : function(e)
4249 var c = document.body;
4252 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4254 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4255 c = document.documentElement;
4258 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4264 var o = target.calcOffsetsTo(c);
4271 this.fireEvent('scrollto', this, options, e);
4273 Roo.get(c).scrollTo('top', options.value, true);
4286 * <span> icon </span>
4287 * <span> text </span>
4288 * <span>badge </span>
4292 * @class Roo.bootstrap.NavSidebarItem
4293 * @extends Roo.bootstrap.NavItem
4294 * Bootstrap Navbar.NavSidebarItem class
4296 * Create a new Navbar Button
4297 * @param {Object} config The config object
4299 Roo.bootstrap.NavSidebarItem = function(config){
4300 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4305 * The raw click event for the entire grid.
4306 * @param {Roo.EventObject} e
4311 * Fires when the active item active state changes
4312 * @param {Roo.bootstrap.NavSidebarItem} this
4313 * @param {boolean} state the new state
4321 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4324 getAutoCreate : function(){
4329 href : this.href || '#',
4341 html : this.html || ''
4346 cfg.cls += ' active';
4350 if (this.glyphicon || this.icon) {
4351 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4352 a.cn.push({ tag : 'i', cls : c }) ;
4357 if (this.badge !== '') {
4358 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4362 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4363 a.cls += 'dropdown-toggle treeview' ;
4387 * @class Roo.bootstrap.Row
4388 * @extends Roo.bootstrap.Component
4389 * Bootstrap Row class (contains columns...)
4393 * @param {Object} config The config object
4396 Roo.bootstrap.Row = function(config){
4397 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4400 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4402 getAutoCreate : function(){
4421 * @class Roo.bootstrap.Element
4422 * @extends Roo.bootstrap.Component
4423 * Bootstrap Element class
4424 * @cfg {String} html contents of the element
4425 * @cfg {String} tag tag of the element
4426 * @cfg {String} cls class of the element
4427 * @cfg {Boolean} preventDefault (true|false) default false
4428 * @cfg {Boolean} clickable (true|false) default false
4431 * Create a new Element
4432 * @param {Object} config The config object
4435 Roo.bootstrap.Element = function(config){
4436 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4442 * When a element is chick
4443 * @param {Roo.bootstrap.Element} this
4444 * @param {Roo.EventObject} e
4450 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4455 preventDefault: false,
4458 getAutoCreate : function(){
4469 initEvents: function()
4471 Roo.bootstrap.Element.superclass.initEvents.call(this);
4474 this.el.on('click', this.onClick, this);
4479 onClick : function(e)
4481 if(this.preventDefault){
4485 this.fireEvent('click', this, e);
4488 getValue : function()
4490 return this.el.dom.innerHTML;
4493 setValue : function(value)
4495 this.el.dom.innerHTML = value;
4510 * @class Roo.bootstrap.Pagination
4511 * @extends Roo.bootstrap.Component
4512 * Bootstrap Pagination class
4513 * @cfg {String} size xs | sm | md | lg
4514 * @cfg {Boolean} inverse false | true
4517 * Create a new Pagination
4518 * @param {Object} config The config object
4521 Roo.bootstrap.Pagination = function(config){
4522 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4525 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4531 getAutoCreate : function(){
4537 cfg.cls += ' inverse';
4543 cfg.cls += " " + this.cls;
4561 * @class Roo.bootstrap.PaginationItem
4562 * @extends Roo.bootstrap.Component
4563 * Bootstrap PaginationItem class
4564 * @cfg {String} html text
4565 * @cfg {String} href the link
4566 * @cfg {Boolean} preventDefault (true | false) default true
4567 * @cfg {Boolean} active (true | false) default false
4568 * @cfg {Boolean} disabled default false
4572 * Create a new PaginationItem
4573 * @param {Object} config The config object
4577 Roo.bootstrap.PaginationItem = function(config){
4578 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4583 * The raw click event for the entire grid.
4584 * @param {Roo.EventObject} e
4590 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4594 preventDefault: true,
4599 getAutoCreate : function(){
4605 href : this.href ? this.href : '#',
4606 html : this.html ? this.html : ''
4616 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4620 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4626 initEvents: function() {
4628 this.el.on('click', this.onClick, this);
4631 onClick : function(e)
4633 Roo.log('PaginationItem on click ');
4634 if(this.preventDefault){
4642 this.fireEvent('click', this, e);
4658 * @class Roo.bootstrap.Slider
4659 * @extends Roo.bootstrap.Component
4660 * Bootstrap Slider class
4663 * Create a new Slider
4664 * @param {Object} config The config object
4667 Roo.bootstrap.Slider = function(config){
4668 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4671 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4673 getAutoCreate : function(){
4677 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4681 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4693 * Ext JS Library 1.1.1
4694 * Copyright(c) 2006-2007, Ext JS, LLC.
4696 * Originally Released Under LGPL - original licence link has changed is not relivant.
4699 * <script type="text/javascript">
4704 * @class Roo.grid.ColumnModel
4705 * @extends Roo.util.Observable
4706 * This is the default implementation of a ColumnModel used by the Grid. It defines
4707 * the columns in the grid.
4710 var colModel = new Roo.grid.ColumnModel([
4711 {header: "Ticker", width: 60, sortable: true, locked: true},
4712 {header: "Company Name", width: 150, sortable: true},
4713 {header: "Market Cap.", width: 100, sortable: true},
4714 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4715 {header: "Employees", width: 100, sortable: true, resizable: false}
4720 * The config options listed for this class are options which may appear in each
4721 * individual column definition.
4722 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4724 * @param {Object} config An Array of column config objects. See this class's
4725 * config objects for details.
4727 Roo.grid.ColumnModel = function(config){
4729 * The config passed into the constructor
4731 this.config = config;
4734 // if no id, create one
4735 // if the column does not have a dataIndex mapping,
4736 // map it to the order it is in the config
4737 for(var i = 0, len = config.length; i < len; i++){
4739 if(typeof c.dataIndex == "undefined"){
4742 if(typeof c.renderer == "string"){
4743 c.renderer = Roo.util.Format[c.renderer];
4745 if(typeof c.id == "undefined"){
4748 if(c.editor && c.editor.xtype){
4749 c.editor = Roo.factory(c.editor, Roo.grid);
4751 if(c.editor && c.editor.isFormField){
4752 c.editor = new Roo.grid.GridEditor(c.editor);
4754 this.lookup[c.id] = c;
4758 * The width of columns which have no width specified (defaults to 100)
4761 this.defaultWidth = 100;
4764 * Default sortable of columns which have no sortable specified (defaults to false)
4767 this.defaultSortable = false;
4771 * @event widthchange
4772 * Fires when the width of a column changes.
4773 * @param {ColumnModel} this
4774 * @param {Number} columnIndex The column index
4775 * @param {Number} newWidth The new width
4777 "widthchange": true,
4779 * @event headerchange
4780 * Fires when the text of a header changes.
4781 * @param {ColumnModel} this
4782 * @param {Number} columnIndex The column index
4783 * @param {Number} newText The new header text
4785 "headerchange": true,
4787 * @event hiddenchange
4788 * Fires when a column is hidden or "unhidden".
4789 * @param {ColumnModel} this
4790 * @param {Number} columnIndex The column index
4791 * @param {Boolean} hidden true if hidden, false otherwise
4793 "hiddenchange": true,
4795 * @event columnmoved
4796 * Fires when a column is moved.
4797 * @param {ColumnModel} this
4798 * @param {Number} oldIndex
4799 * @param {Number} newIndex
4801 "columnmoved" : true,
4803 * @event columlockchange
4804 * Fires when a column's locked state is changed
4805 * @param {ColumnModel} this
4806 * @param {Number} colIndex
4807 * @param {Boolean} locked true if locked
4809 "columnlockchange" : true
4811 Roo.grid.ColumnModel.superclass.constructor.call(this);
4813 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4815 * @cfg {String} header The header text to display in the Grid view.
4818 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4819 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4820 * specified, the column's index is used as an index into the Record's data Array.
4823 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4824 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4827 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4828 * Defaults to the value of the {@link #defaultSortable} property.
4829 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4832 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4835 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4838 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4841 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4844 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4845 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4846 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4847 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4850 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4853 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4856 * @cfg {String} cursor (Optional)
4859 * @cfg {String} tooltip (Optional)
4862 * Returns the id of the column at the specified index.
4863 * @param {Number} index The column index
4864 * @return {String} the id
4866 getColumnId : function(index){
4867 return this.config[index].id;
4871 * Returns the column for a specified id.
4872 * @param {String} id The column id
4873 * @return {Object} the column
4875 getColumnById : function(id){
4876 return this.lookup[id];
4881 * Returns the column for a specified dataIndex.
4882 * @param {String} dataIndex The column dataIndex
4883 * @return {Object|Boolean} the column or false if not found
4885 getColumnByDataIndex: function(dataIndex){
4886 var index = this.findColumnIndex(dataIndex);
4887 return index > -1 ? this.config[index] : false;
4891 * Returns the index for a specified column id.
4892 * @param {String} id The column id
4893 * @return {Number} the index, or -1 if not found
4895 getIndexById : function(id){
4896 for(var i = 0, len = this.config.length; i < len; i++){
4897 if(this.config[i].id == id){
4905 * Returns the index for a specified column dataIndex.
4906 * @param {String} dataIndex The column dataIndex
4907 * @return {Number} the index, or -1 if not found
4910 findColumnIndex : function(dataIndex){
4911 for(var i = 0, len = this.config.length; i < len; i++){
4912 if(this.config[i].dataIndex == dataIndex){
4920 moveColumn : function(oldIndex, newIndex){
4921 var c = this.config[oldIndex];
4922 this.config.splice(oldIndex, 1);
4923 this.config.splice(newIndex, 0, c);
4924 this.dataMap = null;
4925 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4928 isLocked : function(colIndex){
4929 return this.config[colIndex].locked === true;
4932 setLocked : function(colIndex, value, suppressEvent){
4933 if(this.isLocked(colIndex) == value){
4936 this.config[colIndex].locked = value;
4938 this.fireEvent("columnlockchange", this, colIndex, value);
4942 getTotalLockedWidth : function(){
4944 for(var i = 0; i < this.config.length; i++){
4945 if(this.isLocked(i) && !this.isHidden(i)){
4946 this.totalWidth += this.getColumnWidth(i);
4952 getLockedCount : function(){
4953 for(var i = 0, len = this.config.length; i < len; i++){
4954 if(!this.isLocked(i)){
4961 * Returns the number of columns.
4964 getColumnCount : function(visibleOnly){
4965 if(visibleOnly === true){
4967 for(var i = 0, len = this.config.length; i < len; i++){
4968 if(!this.isHidden(i)){
4974 return this.config.length;
4978 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4979 * @param {Function} fn
4980 * @param {Object} scope (optional)
4981 * @return {Array} result
4983 getColumnsBy : function(fn, scope){
4985 for(var i = 0, len = this.config.length; i < len; i++){
4986 var c = this.config[i];
4987 if(fn.call(scope||this, c, i) === true){
4995 * Returns true if the specified column is sortable.
4996 * @param {Number} col The column index
4999 isSortable : function(col){
5000 if(typeof this.config[col].sortable == "undefined"){
5001 return this.defaultSortable;
5003 return this.config[col].sortable;
5007 * Returns the rendering (formatting) function defined for the column.
5008 * @param {Number} col The column index.
5009 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5011 getRenderer : function(col){
5012 if(!this.config[col].renderer){
5013 return Roo.grid.ColumnModel.defaultRenderer;
5015 return this.config[col].renderer;
5019 * Sets the rendering (formatting) function for a column.
5020 * @param {Number} col The column index
5021 * @param {Function} fn The function to use to process the cell's raw data
5022 * to return HTML markup for the grid view. The render function is called with
5023 * the following parameters:<ul>
5024 * <li>Data value.</li>
5025 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5026 * <li>css A CSS style string to apply to the table cell.</li>
5027 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5028 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5029 * <li>Row index</li>
5030 * <li>Column index</li>
5031 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5033 setRenderer : function(col, fn){
5034 this.config[col].renderer = fn;
5038 * Returns the width for the specified column.
5039 * @param {Number} col The column index
5042 getColumnWidth : function(col){
5043 return this.config[col].width * 1 || this.defaultWidth;
5047 * Sets the width for a column.
5048 * @param {Number} col The column index
5049 * @param {Number} width The new width
5051 setColumnWidth : function(col, width, suppressEvent){
5052 this.config[col].width = width;
5053 this.totalWidth = null;
5055 this.fireEvent("widthchange", this, col, width);
5060 * Returns the total width of all columns.
5061 * @param {Boolean} includeHidden True to include hidden column widths
5064 getTotalWidth : function(includeHidden){
5065 if(!this.totalWidth){
5066 this.totalWidth = 0;
5067 for(var i = 0, len = this.config.length; i < len; i++){
5068 if(includeHidden || !this.isHidden(i)){
5069 this.totalWidth += this.getColumnWidth(i);
5073 return this.totalWidth;
5077 * Returns the header for the specified column.
5078 * @param {Number} col The column index
5081 getColumnHeader : function(col){
5082 return this.config[col].header;
5086 * Sets the header for a column.
5087 * @param {Number} col The column index
5088 * @param {String} header The new header
5090 setColumnHeader : function(col, header){
5091 this.config[col].header = header;
5092 this.fireEvent("headerchange", this, col, header);
5096 * Returns the tooltip for the specified column.
5097 * @param {Number} col The column index
5100 getColumnTooltip : function(col){
5101 return this.config[col].tooltip;
5104 * Sets the tooltip for a column.
5105 * @param {Number} col The column index
5106 * @param {String} tooltip The new tooltip
5108 setColumnTooltip : function(col, tooltip){
5109 this.config[col].tooltip = tooltip;
5113 * Returns the dataIndex for the specified column.
5114 * @param {Number} col The column index
5117 getDataIndex : function(col){
5118 return this.config[col].dataIndex;
5122 * Sets the dataIndex for a column.
5123 * @param {Number} col The column index
5124 * @param {Number} dataIndex The new dataIndex
5126 setDataIndex : function(col, dataIndex){
5127 this.config[col].dataIndex = dataIndex;
5133 * Returns true if the cell is editable.
5134 * @param {Number} colIndex The column index
5135 * @param {Number} rowIndex The row index
5138 isCellEditable : function(colIndex, rowIndex){
5139 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5143 * Returns the editor defined for the cell/column.
5144 * return false or null to disable editing.
5145 * @param {Number} colIndex The column index
5146 * @param {Number} rowIndex The row index
5149 getCellEditor : function(colIndex, rowIndex){
5150 return this.config[colIndex].editor;
5154 * Sets if a column is editable.
5155 * @param {Number} col The column index
5156 * @param {Boolean} editable True if the column is editable
5158 setEditable : function(col, editable){
5159 this.config[col].editable = editable;
5164 * Returns true if the column is hidden.
5165 * @param {Number} colIndex The column index
5168 isHidden : function(colIndex){
5169 return this.config[colIndex].hidden;
5174 * Returns true if the column width cannot be changed
5176 isFixed : function(colIndex){
5177 return this.config[colIndex].fixed;
5181 * Returns true if the column can be resized
5184 isResizable : function(colIndex){
5185 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5188 * Sets if a column is hidden.
5189 * @param {Number} colIndex The column index
5190 * @param {Boolean} hidden True if the column is hidden
5192 setHidden : function(colIndex, hidden){
5193 this.config[colIndex].hidden = hidden;
5194 this.totalWidth = null;
5195 this.fireEvent("hiddenchange", this, colIndex, hidden);
5199 * Sets the editor for a column.
5200 * @param {Number} col The column index
5201 * @param {Object} editor The editor object
5203 setEditor : function(col, editor){
5204 this.config[col].editor = editor;
5208 Roo.grid.ColumnModel.defaultRenderer = function(value){
5209 if(typeof value == "string" && value.length < 1){
5215 // Alias for backwards compatibility
5216 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5219 * Ext JS Library 1.1.1
5220 * Copyright(c) 2006-2007, Ext JS, LLC.
5222 * Originally Released Under LGPL - original licence link has changed is not relivant.
5225 * <script type="text/javascript">
5229 * @class Roo.LoadMask
5230 * A simple utility class for generically masking elements while loading data. If the element being masked has
5231 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5232 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5233 * element's UpdateManager load indicator and will be destroyed after the initial load.
5235 * Create a new LoadMask
5236 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5237 * @param {Object} config The config object
5239 Roo.LoadMask = function(el, config){
5240 this.el = Roo.get(el);
5241 Roo.apply(this, config);
5243 this.store.on('beforeload', this.onBeforeLoad, this);
5244 this.store.on('load', this.onLoad, this);
5245 this.store.on('loadexception', this.onLoadException, this);
5246 this.removeMask = false;
5248 var um = this.el.getUpdateManager();
5249 um.showLoadIndicator = false; // disable the default indicator
5250 um.on('beforeupdate', this.onBeforeLoad, this);
5251 um.on('update', this.onLoad, this);
5252 um.on('failure', this.onLoad, this);
5253 this.removeMask = true;
5257 Roo.LoadMask.prototype = {
5259 * @cfg {Boolean} removeMask
5260 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5261 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5265 * The text to display in a centered loading message box (defaults to 'Loading...')
5269 * @cfg {String} msgCls
5270 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5272 msgCls : 'x-mask-loading',
5275 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5281 * Disables the mask to prevent it from being displayed
5283 disable : function(){
5284 this.disabled = true;
5288 * Enables the mask so that it can be displayed
5290 enable : function(){
5291 this.disabled = false;
5294 onLoadException : function()
5298 if (typeof(arguments[3]) != 'undefined') {
5299 Roo.MessageBox.alert("Error loading",arguments[3]);
5303 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5304 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5313 this.el.unmask(this.removeMask);
5318 this.el.unmask(this.removeMask);
5322 onBeforeLoad : function(){
5324 this.el.mask(this.msg, this.msgCls);
5329 destroy : function(){
5331 this.store.un('beforeload', this.onBeforeLoad, this);
5332 this.store.un('load', this.onLoad, this);
5333 this.store.un('loadexception', this.onLoadException, this);
5335 var um = this.el.getUpdateManager();
5336 um.un('beforeupdate', this.onBeforeLoad, this);
5337 um.un('update', this.onLoad, this);
5338 um.un('failure', this.onLoad, this);
5349 * @class Roo.bootstrap.Table
5350 * @extends Roo.bootstrap.Component
5351 * Bootstrap Table class
5352 * @cfg {String} cls table class
5353 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5354 * @cfg {String} bgcolor Specifies the background color for a table
5355 * @cfg {Number} border Specifies whether the table cells should have borders or not
5356 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5357 * @cfg {Number} cellspacing Specifies the space between cells
5358 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5359 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5360 * @cfg {String} sortable Specifies that the table should be sortable
5361 * @cfg {String} summary Specifies a summary of the content of a table
5362 * @cfg {Number} width Specifies the width of a table
5363 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5365 * @cfg {boolean} striped Should the rows be alternative striped
5366 * @cfg {boolean} bordered Add borders to the table
5367 * @cfg {boolean} hover Add hover highlighting
5368 * @cfg {boolean} condensed Format condensed
5369 * @cfg {boolean} responsive Format condensed
5370 * @cfg {Boolean} loadMask (true|false) default false
5371 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5372 * @cfg {Boolean} thead (true|false) generate thead, default true
5373 * @cfg {Boolean} RowSelection (true|false) default false
5374 * @cfg {Boolean} CellSelection (true|false) default false
5375 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5379 * Create a new Table
5380 * @param {Object} config The config object
5383 Roo.bootstrap.Table = function(config){
5384 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5387 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5388 this.sm = this.selModel;
5389 this.sm.xmodule = this.xmodule || false;
5391 if (this.cm && typeof(this.cm.config) == 'undefined') {
5392 this.colModel = new Roo.grid.ColumnModel(this.cm);
5393 this.cm = this.colModel;
5394 this.cm.xmodule = this.xmodule || false;
5397 this.store= Roo.factory(this.store, Roo.data);
5398 this.ds = this.store;
5399 this.ds.xmodule = this.xmodule || false;
5402 if (this.footer && this.store) {
5403 this.footer.dataSource = this.ds;
5404 this.footer = Roo.factory(this.footer);
5411 * Fires when a cell is clicked
5412 * @param {Roo.bootstrap.Table} this
5413 * @param {Roo.Element} el
5414 * @param {Number} rowIndex
5415 * @param {Number} columnIndex
5416 * @param {Roo.EventObject} e
5420 * @event celldblclick
5421 * Fires when a cell is double clicked
5422 * @param {Roo.bootstrap.Table} this
5423 * @param {Roo.Element} el
5424 * @param {Number} rowIndex
5425 * @param {Number} columnIndex
5426 * @param {Roo.EventObject} e
5428 "celldblclick" : true,
5431 * Fires when a row is clicked
5432 * @param {Roo.bootstrap.Table} this
5433 * @param {Roo.Element} el
5434 * @param {Number} rowIndex
5435 * @param {Roo.EventObject} e
5439 * @event rowdblclick
5440 * Fires when a row is double clicked
5441 * @param {Roo.bootstrap.Table} this
5442 * @param {Roo.Element} el
5443 * @param {Number} rowIndex
5444 * @param {Roo.EventObject} e
5446 "rowdblclick" : true,
5449 * Fires when a mouseover occur
5450 * @param {Roo.bootstrap.Table} this
5451 * @param {Roo.Element} el
5452 * @param {Number} rowIndex
5453 * @param {Number} columnIndex
5454 * @param {Roo.EventObject} e
5459 * Fires when a mouseout occur
5460 * @param {Roo.bootstrap.Table} this
5461 * @param {Roo.Element} el
5462 * @param {Number} rowIndex
5463 * @param {Number} columnIndex
5464 * @param {Roo.EventObject} e
5469 * Fires when a row is rendered, so you can change add a style to it.
5470 * @param {Roo.bootstrap.Table} this
5471 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5475 * @event rowsrendered
5476 * Fires when all the rows have been rendered
5477 * @param {Roo.bootstrap.Table} this
5479 'rowsrendered' : true
5484 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5508 RowSelection : false,
5509 CellSelection : false,
5512 // Roo.Element - the tbody
5515 getAutoCreate : function(){
5516 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5525 cfg.cls += ' table-striped';
5529 cfg.cls += ' table-hover';
5531 if (this.bordered) {
5532 cfg.cls += ' table-bordered';
5534 if (this.condensed) {
5535 cfg.cls += ' table-condensed';
5537 if (this.responsive) {
5538 cfg.cls += ' table-responsive';
5542 cfg.cls+= ' ' +this.cls;
5545 // this lot should be simplifed...
5548 cfg.align=this.align;
5551 cfg.bgcolor=this.bgcolor;
5554 cfg.border=this.border;
5556 if (this.cellpadding) {
5557 cfg.cellpadding=this.cellpadding;
5559 if (this.cellspacing) {
5560 cfg.cellspacing=this.cellspacing;
5563 cfg.frame=this.frame;
5566 cfg.rules=this.rules;
5568 if (this.sortable) {
5569 cfg.sortable=this.sortable;
5572 cfg.summary=this.summary;
5575 cfg.width=this.width;
5578 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5581 if(this.store || this.cm){
5583 cfg.cn.push(this.renderHeader());
5586 cfg.cn.push(this.renderBody());
5589 cfg.cn.push(this.renderFooter());
5592 cfg.cls+= ' TableGrid';
5595 return { cn : [ cfg ] };
5598 initEvents : function()
5600 if(!this.store || !this.cm){
5604 //Roo.log('initEvents with ds!!!!');
5606 this.mainBody = this.el.select('tbody', true).first();
5611 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5612 e.on('click', _this.sort, _this);
5615 this.el.on("click", this.onClick, this);
5616 this.el.on("dblclick", this.onDblClick, this);
5618 // why is this done????? = it breaks dialogs??
5619 //this.parent().el.setStyle('position', 'relative');
5623 this.footer.parentId = this.id;
5624 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5627 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5629 this.store.on('load', this.onLoad, this);
5630 this.store.on('beforeload', this.onBeforeLoad, this);
5631 this.store.on('update', this.onUpdate, this);
5632 this.store.on('add', this.onAdd, this);
5636 onMouseover : function(e, el)
5638 var cell = Roo.get(el);
5644 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5645 cell = cell.findParent('td', false, true);
5648 var row = cell.findParent('tr', false, true);
5649 var cellIndex = cell.dom.cellIndex;
5650 var rowIndex = row.dom.rowIndex - 1; // start from 0
5652 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5656 onMouseout : function(e, el)
5658 var cell = Roo.get(el);
5664 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5665 cell = cell.findParent('td', false, true);
5668 var row = cell.findParent('tr', false, true);
5669 var cellIndex = cell.dom.cellIndex;
5670 var rowIndex = row.dom.rowIndex - 1; // start from 0
5672 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5676 onClick : function(e, el)
5678 var cell = Roo.get(el);
5680 if(!cell || (!this.CellSelection && !this.RowSelection)){
5684 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5685 cell = cell.findParent('td', false, true);
5688 if(!cell || typeof(cell) == 'undefined'){
5692 var row = cell.findParent('tr', false, true);
5694 if(!row || typeof(row) == 'undefined'){
5698 var cellIndex = cell.dom.cellIndex;
5699 var rowIndex = this.getRowIndex(row);
5701 if(this.CellSelection){
5702 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5705 if(this.RowSelection){
5706 this.fireEvent('rowclick', this, row, rowIndex, e);
5712 onDblClick : function(e,el)
5714 var cell = Roo.get(el);
5716 if(!cell || (!this.CellSelection && !this.RowSelection)){
5720 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5721 cell = cell.findParent('td', false, true);
5724 if(!cell || typeof(cell) == 'undefined'){
5728 var row = cell.findParent('tr', false, true);
5730 if(!row || typeof(row) == 'undefined'){
5734 var cellIndex = cell.dom.cellIndex;
5735 var rowIndex = this.getRowIndex(row);
5737 if(this.CellSelection){
5738 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5741 if(this.RowSelection){
5742 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5746 sort : function(e,el)
5748 var col = Roo.get(el);
5750 if(!col.hasClass('sortable')){
5754 var sort = col.attr('sort');
5757 if(col.hasClass('glyphicon-arrow-up')){
5761 this.store.sortInfo = {field : sort, direction : dir};
5764 Roo.log("calling footer first");
5765 this.footer.onClick('first');
5768 this.store.load({ params : { start : 0 } });
5772 renderHeader : function()
5781 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5783 var config = cm.config[i];
5788 html: cm.getColumnHeader(i)
5791 if(typeof(config.tooltip) != 'undefined'){
5792 c.tooltip = config.tooltip;
5795 if(typeof(config.colspan) != 'undefined'){
5796 c.colspan = config.colspan;
5799 if(typeof(config.hidden) != 'undefined' && config.hidden){
5800 c.style += ' display:none;';
5803 if(typeof(config.dataIndex) != 'undefined'){
5804 c.sort = config.dataIndex;
5807 if(typeof(config.sortable) != 'undefined' && config.sortable){
5811 if(typeof(config.align) != 'undefined' && config.align.length){
5812 c.style += ' text-align:' + config.align + ';';
5815 if(typeof(config.width) != 'undefined'){
5816 c.style += ' width:' + config.width + 'px;';
5819 if(typeof(config.cls) != 'undefined'){
5820 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5829 renderBody : function()
5839 colspan : this.cm.getColumnCount()
5849 renderFooter : function()
5859 colspan : this.cm.getColumnCount()
5873 Roo.log('ds onload');
5878 var ds = this.store;
5880 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5881 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5883 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5884 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5887 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5888 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5892 var tbody = this.mainBody;
5894 if(ds.getCount() > 0){
5895 ds.data.each(function(d,rowIndex){
5896 var row = this.renderRow(cm, ds, rowIndex);
5898 tbody.createChild(row);
5902 if(row.cellObjects.length){
5903 Roo.each(row.cellObjects, function(r){
5904 _this.renderCellObject(r);
5911 Roo.each(this.el.select('tbody td', true).elements, function(e){
5912 e.on('mouseover', _this.onMouseover, _this);
5915 Roo.each(this.el.select('tbody td', true).elements, function(e){
5916 e.on('mouseout', _this.onMouseout, _this);
5918 this.fireEvent('rowsrendered', this);
5919 //if(this.loadMask){
5920 // this.maskEl.hide();
5925 onUpdate : function(ds,record)
5927 this.refreshRow(record);
5930 onRemove : function(ds, record, index, isUpdate){
5931 if(isUpdate !== true){
5932 this.fireEvent("beforerowremoved", this, index, record);
5934 var bt = this.mainBody.dom;
5936 var rows = this.el.select('tbody > tr', true).elements;
5938 if(typeof(rows[index]) != 'undefined'){
5939 bt.removeChild(rows[index].dom);
5942 // if(bt.rows[index]){
5943 // bt.removeChild(bt.rows[index]);
5946 if(isUpdate !== true){
5947 //this.stripeRows(index);
5948 //this.syncRowHeights(index, index);
5950 this.fireEvent("rowremoved", this, index, record);
5954 onAdd : function(ds, records, rowIndex)
5956 //Roo.log('on Add called');
5957 // - note this does not handle multiple adding very well..
5958 var bt = this.mainBody.dom;
5959 for (var i =0 ; i < records.length;i++) {
5960 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5961 //Roo.log(records[i]);
5962 //Roo.log(this.store.getAt(rowIndex+i));
5963 this.insertRow(this.store, rowIndex + i, false);
5970 refreshRow : function(record){
5971 var ds = this.store, index;
5972 if(typeof record == 'number'){
5974 record = ds.getAt(index);
5976 index = ds.indexOf(record);
5978 this.insertRow(ds, index, true);
5979 this.onRemove(ds, record, index+1, true);
5980 //this.syncRowHeights(index, index);
5982 this.fireEvent("rowupdated", this, index, record);
5985 insertRow : function(dm, rowIndex, isUpdate){
5988 this.fireEvent("beforerowsinserted", this, rowIndex);
5990 //var s = this.getScrollState();
5991 var row = this.renderRow(this.cm, this.store, rowIndex);
5992 // insert before rowIndex..
5993 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5997 if(row.cellObjects.length){
5998 Roo.each(row.cellObjects, function(r){
5999 _this.renderCellObject(r);
6004 this.fireEvent("rowsinserted", this, rowIndex);
6005 //this.syncRowHeights(firstRow, lastRow);
6006 //this.stripeRows(firstRow);
6013 getRowDom : function(rowIndex)
6015 var rows = this.el.select('tbody > tr', true).elements;
6017 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6020 // returns the object tree for a tr..
6023 renderRow : function(cm, ds, rowIndex)
6026 var d = ds.getAt(rowIndex);
6033 var cellObjects = [];
6035 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6036 var config = cm.config[i];
6038 var renderer = cm.getRenderer(i);
6042 if(typeof(renderer) !== 'undefined'){
6043 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6045 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6046 // and are rendered into the cells after the row is rendered - using the id for the element.
6048 if(typeof(value) === 'object'){
6058 rowIndex : rowIndex,
6063 this.fireEvent('rowclass', this, rowcfg);
6067 cls : rowcfg.rowClass,
6069 html: (typeof(value) === 'object') ? '' : value
6076 if(typeof(config.colspan) != 'undefined'){
6077 td.colspan = config.colspan;
6080 if(typeof(config.hidden) != 'undefined' && config.hidden){
6081 td.style += ' display:none;';
6084 if(typeof(config.align) != 'undefined' && config.align.length){
6085 td.style += ' text-align:' + config.align + ';';
6088 if(typeof(config.width) != 'undefined'){
6089 td.style += ' width:' + config.width + 'px;';
6092 if(typeof(config.cursor) != 'undefined'){
6093 td.style += ' cursor:' + config.cursor + ';';
6096 if(typeof(config.cls) != 'undefined'){
6097 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6104 row.cellObjects = cellObjects;
6112 onBeforeLoad : function()
6114 //Roo.log('ds onBeforeLoad');
6118 //if(this.loadMask){
6119 // this.maskEl.show();
6127 this.el.select('tbody', true).first().dom.innerHTML = '';
6130 * Show or hide a row.
6131 * @param {Number} rowIndex to show or hide
6132 * @param {Boolean} state hide
6134 setRowVisibility : function(rowIndex, state)
6136 var bt = this.mainBody.dom;
6138 var rows = this.el.select('tbody > tr', true).elements;
6140 if(typeof(rows[rowIndex]) == 'undefined'){
6143 rows[rowIndex].dom.style.display = state ? '' : 'none';
6147 getSelectionModel : function(){
6149 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6151 return this.selModel;
6154 * Render the Roo.bootstrap object from renderder
6156 renderCellObject : function(r)
6160 var t = r.cfg.render(r.container);
6163 Roo.each(r.cfg.cn, function(c){
6165 container: t.getChildContainer(),
6168 _this.renderCellObject(child);
6173 getRowIndex : function(row)
6177 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6200 * @class Roo.bootstrap.TableCell
6201 * @extends Roo.bootstrap.Component
6202 * Bootstrap TableCell class
6203 * @cfg {String} html cell contain text
6204 * @cfg {String} cls cell class
6205 * @cfg {String} tag cell tag (td|th) default td
6206 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6207 * @cfg {String} align Aligns the content in a cell
6208 * @cfg {String} axis Categorizes cells
6209 * @cfg {String} bgcolor Specifies the background color of a cell
6210 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6211 * @cfg {Number} colspan Specifies the number of columns a cell should span
6212 * @cfg {String} headers Specifies one or more header cells a cell is related to
6213 * @cfg {Number} height Sets the height of a cell
6214 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6215 * @cfg {Number} rowspan Sets the number of rows a cell should span
6216 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6217 * @cfg {String} valign Vertical aligns the content in a cell
6218 * @cfg {Number} width Specifies the width of a cell
6221 * Create a new TableCell
6222 * @param {Object} config The config object
6225 Roo.bootstrap.TableCell = function(config){
6226 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6229 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6249 getAutoCreate : function(){
6250 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6270 cfg.align=this.align
6276 cfg.bgcolor=this.bgcolor
6279 cfg.charoff=this.charoff
6282 cfg.colspan=this.colspan
6285 cfg.headers=this.headers
6288 cfg.height=this.height
6291 cfg.nowrap=this.nowrap
6294 cfg.rowspan=this.rowspan
6297 cfg.scope=this.scope
6300 cfg.valign=this.valign
6303 cfg.width=this.width
6322 * @class Roo.bootstrap.TableRow
6323 * @extends Roo.bootstrap.Component
6324 * Bootstrap TableRow class
6325 * @cfg {String} cls row class
6326 * @cfg {String} align Aligns the content in a table row
6327 * @cfg {String} bgcolor Specifies a background color for a table row
6328 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6329 * @cfg {String} valign Vertical aligns the content in a table row
6332 * Create a new TableRow
6333 * @param {Object} config The config object
6336 Roo.bootstrap.TableRow = function(config){
6337 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6340 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6348 getAutoCreate : function(){
6349 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6359 cfg.align = this.align;
6362 cfg.bgcolor = this.bgcolor;
6365 cfg.charoff = this.charoff;
6368 cfg.valign = this.valign;
6386 * @class Roo.bootstrap.TableBody
6387 * @extends Roo.bootstrap.Component
6388 * Bootstrap TableBody class
6389 * @cfg {String} cls element class
6390 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6391 * @cfg {String} align Aligns the content inside the element
6392 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6393 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6396 * Create a new TableBody
6397 * @param {Object} config The config object
6400 Roo.bootstrap.TableBody = function(config){
6401 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6404 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6412 getAutoCreate : function(){
6413 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6427 cfg.align = this.align;
6430 cfg.charoff = this.charoff;
6433 cfg.valign = this.valign;
6440 // initEvents : function()
6447 // this.store = Roo.factory(this.store, Roo.data);
6448 // this.store.on('load', this.onLoad, this);
6450 // this.store.load();
6454 // onLoad: function ()
6456 // this.fireEvent('load', this);
6466 * Ext JS Library 1.1.1
6467 * Copyright(c) 2006-2007, Ext JS, LLC.
6469 * Originally Released Under LGPL - original licence link has changed is not relivant.
6472 * <script type="text/javascript">
6475 // as we use this in bootstrap.
6476 Roo.namespace('Roo.form');
6478 * @class Roo.form.Action
6479 * Internal Class used to handle form actions
6481 * @param {Roo.form.BasicForm} el The form element or its id
6482 * @param {Object} config Configuration options
6487 // define the action interface
6488 Roo.form.Action = function(form, options){
6490 this.options = options || {};
6493 * Client Validation Failed
6496 Roo.form.Action.CLIENT_INVALID = 'client';
6498 * Server Validation Failed
6501 Roo.form.Action.SERVER_INVALID = 'server';
6503 * Connect to Server Failed
6506 Roo.form.Action.CONNECT_FAILURE = 'connect';
6508 * Reading Data from Server Failed
6511 Roo.form.Action.LOAD_FAILURE = 'load';
6513 Roo.form.Action.prototype = {
6515 failureType : undefined,
6516 response : undefined,
6520 run : function(options){
6525 success : function(response){
6530 handleResponse : function(response){
6534 // default connection failure
6535 failure : function(response){
6537 this.response = response;
6538 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6539 this.form.afterAction(this, false);
6542 processResponse : function(response){
6543 this.response = response;
6544 if(!response.responseText){
6547 this.result = this.handleResponse(response);
6551 // utility functions used internally
6552 getUrl : function(appendParams){
6553 var url = this.options.url || this.form.url || this.form.el.dom.action;
6555 var p = this.getParams();
6557 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6563 getMethod : function(){
6564 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6567 getParams : function(){
6568 var bp = this.form.baseParams;
6569 var p = this.options.params;
6571 if(typeof p == "object"){
6572 p = Roo.urlEncode(Roo.applyIf(p, bp));
6573 }else if(typeof p == 'string' && bp){
6574 p += '&' + Roo.urlEncode(bp);
6577 p = Roo.urlEncode(bp);
6582 createCallback : function(){
6584 success: this.success,
6585 failure: this.failure,
6587 timeout: (this.form.timeout*1000),
6588 upload: this.form.fileUpload ? this.success : undefined
6593 Roo.form.Action.Submit = function(form, options){
6594 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6597 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6600 haveProgress : false,
6601 uploadComplete : false,
6603 // uploadProgress indicator.
6604 uploadProgress : function()
6606 if (!this.form.progressUrl) {
6610 if (!this.haveProgress) {
6611 Roo.MessageBox.progress("Uploading", "Uploading");
6613 if (this.uploadComplete) {
6614 Roo.MessageBox.hide();
6618 this.haveProgress = true;
6620 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6622 var c = new Roo.data.Connection();
6624 url : this.form.progressUrl,
6629 success : function(req){
6630 //console.log(data);
6634 rdata = Roo.decode(req.responseText)
6636 Roo.log("Invalid data from server..");
6640 if (!rdata || !rdata.success) {
6642 Roo.MessageBox.alert(Roo.encode(rdata));
6645 var data = rdata.data;
6647 if (this.uploadComplete) {
6648 Roo.MessageBox.hide();
6653 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6654 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6657 this.uploadProgress.defer(2000,this);
6660 failure: function(data) {
6661 Roo.log('progress url failed ');
6672 // run get Values on the form, so it syncs any secondary forms.
6673 this.form.getValues();
6675 var o = this.options;
6676 var method = this.getMethod();
6677 var isPost = method == 'POST';
6678 if(o.clientValidation === false || this.form.isValid()){
6680 if (this.form.progressUrl) {
6681 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6682 (new Date() * 1) + '' + Math.random());
6687 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6688 form:this.form.el.dom,
6689 url:this.getUrl(!isPost),
6691 params:isPost ? this.getParams() : null,
6692 isUpload: this.form.fileUpload
6695 this.uploadProgress();
6697 }else if (o.clientValidation !== false){ // client validation failed
6698 this.failureType = Roo.form.Action.CLIENT_INVALID;
6699 this.form.afterAction(this, false);
6703 success : function(response)
6705 this.uploadComplete= true;
6706 if (this.haveProgress) {
6707 Roo.MessageBox.hide();
6711 var result = this.processResponse(response);
6712 if(result === true || result.success){
6713 this.form.afterAction(this, true);
6717 this.form.markInvalid(result.errors);
6718 this.failureType = Roo.form.Action.SERVER_INVALID;
6720 this.form.afterAction(this, false);
6722 failure : function(response)
6724 this.uploadComplete= true;
6725 if (this.haveProgress) {
6726 Roo.MessageBox.hide();
6729 this.response = response;
6730 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6731 this.form.afterAction(this, false);
6734 handleResponse : function(response){
6735 if(this.form.errorReader){
6736 var rs = this.form.errorReader.read(response);
6739 for(var i = 0, len = rs.records.length; i < len; i++) {
6740 var r = rs.records[i];
6744 if(errors.length < 1){
6748 success : rs.success,
6754 ret = Roo.decode(response.responseText);
6758 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6768 Roo.form.Action.Load = function(form, options){
6769 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6770 this.reader = this.form.reader;
6773 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6778 Roo.Ajax.request(Roo.apply(
6779 this.createCallback(), {
6780 method:this.getMethod(),
6781 url:this.getUrl(false),
6782 params:this.getParams()
6786 success : function(response){
6788 var result = this.processResponse(response);
6789 if(result === true || !result.success || !result.data){
6790 this.failureType = Roo.form.Action.LOAD_FAILURE;
6791 this.form.afterAction(this, false);
6794 this.form.clearInvalid();
6795 this.form.setValues(result.data);
6796 this.form.afterAction(this, true);
6799 handleResponse : function(response){
6800 if(this.form.reader){
6801 var rs = this.form.reader.read(response);
6802 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6804 success : rs.success,
6808 return Roo.decode(response.responseText);
6812 Roo.form.Action.ACTION_TYPES = {
6813 'load' : Roo.form.Action.Load,
6814 'submit' : Roo.form.Action.Submit
6823 * @class Roo.bootstrap.Form
6824 * @extends Roo.bootstrap.Component
6825 * Bootstrap Form class
6826 * @cfg {String} method GET | POST (default POST)
6827 * @cfg {String} labelAlign top | left (default top)
6828 * @cfg {String} align left | right - for navbars
6829 * @cfg {Boolean} loadMask load mask when submit (default true)
6834 * @param {Object} config The config object
6838 Roo.bootstrap.Form = function(config){
6839 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6842 * @event clientvalidation
6843 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6844 * @param {Form} this
6845 * @param {Boolean} valid true if the form has passed client-side validation
6847 clientvalidation: true,
6849 * @event beforeaction
6850 * Fires before any action is performed. Return false to cancel the action.
6851 * @param {Form} this
6852 * @param {Action} action The action to be performed
6856 * @event actionfailed
6857 * Fires when an action fails.
6858 * @param {Form} this
6859 * @param {Action} action The action that failed
6861 actionfailed : true,
6863 * @event actioncomplete
6864 * Fires when an action is completed.
6865 * @param {Form} this
6866 * @param {Action} action The action that completed
6868 actioncomplete : true
6873 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6876 * @cfg {String} method
6877 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6882 * The URL to use for form actions if one isn't supplied in the action options.
6885 * @cfg {Boolean} fileUpload
6886 * Set to true if this form is a file upload.
6890 * @cfg {Object} baseParams
6891 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6895 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6899 * @cfg {Sting} align (left|right) for navbar forms
6904 activeAction : null,
6907 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6908 * element by passing it or its id or mask the form itself by passing in true.
6911 waitMsgTarget : false,
6915 getAutoCreate : function(){
6919 method : this.method || 'POST',
6920 id : this.id || Roo.id(),
6923 if (this.parent().xtype.match(/^Nav/)) {
6924 cfg.cls = 'navbar-form navbar-' + this.align;
6928 if (this.labelAlign == 'left' ) {
6929 cfg.cls += ' form-horizontal';
6935 initEvents : function()
6937 this.el.on('submit', this.onSubmit, this);
6938 // this was added as random key presses on the form where triggering form submit.
6939 this.el.on('keypress', function(e) {
6940 if (e.getCharCode() != 13) {
6943 // we might need to allow it for textareas.. and some other items.
6944 // check e.getTarget().
6946 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6950 Roo.log("keypress blocked");
6958 onSubmit : function(e){
6963 * Returns true if client-side validation on the form is successful.
6966 isValid : function(){
6967 var items = this.getItems();
6969 items.each(function(f){
6978 * Returns true if any fields in this form have changed since their original load.
6981 isDirty : function(){
6983 var items = this.getItems();
6984 items.each(function(f){
6994 * Performs a predefined action (submit or load) or custom actions you define on this form.
6995 * @param {String} actionName The name of the action type
6996 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6997 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6998 * accept other config options):
7000 Property Type Description
7001 ---------------- --------------- ----------------------------------------------------------------------------------
7002 url String The url for the action (defaults to the form's url)
7003 method String The form method to use (defaults to the form's method, or POST if not defined)
7004 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7005 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7006 validate the form on the client (defaults to false)
7008 * @return {BasicForm} this
7010 doAction : function(action, options){
7011 if(typeof action == 'string'){
7012 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7014 if(this.fireEvent('beforeaction', this, action) !== false){
7015 this.beforeAction(action);
7016 action.run.defer(100, action);
7022 beforeAction : function(action){
7023 var o = action.options;
7026 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7028 // not really supported yet.. ??
7030 //if(this.waitMsgTarget === true){
7031 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7032 //}else if(this.waitMsgTarget){
7033 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7034 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7036 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7042 afterAction : function(action, success){
7043 this.activeAction = null;
7044 var o = action.options;
7046 //if(this.waitMsgTarget === true){
7048 //}else if(this.waitMsgTarget){
7049 // this.waitMsgTarget.unmask();
7051 // Roo.MessageBox.updateProgress(1);
7052 // Roo.MessageBox.hide();
7059 Roo.callback(o.success, o.scope, [this, action]);
7060 this.fireEvent('actioncomplete', this, action);
7064 // failure condition..
7065 // we have a scenario where updates need confirming.
7066 // eg. if a locking scenario exists..
7067 // we look for { errors : { needs_confirm : true }} in the response.
7069 (typeof(action.result) != 'undefined') &&
7070 (typeof(action.result.errors) != 'undefined') &&
7071 (typeof(action.result.errors.needs_confirm) != 'undefined')
7074 Roo.log("not supported yet");
7077 Roo.MessageBox.confirm(
7078 "Change requires confirmation",
7079 action.result.errorMsg,
7084 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7094 Roo.callback(o.failure, o.scope, [this, action]);
7095 // show an error message if no failed handler is set..
7096 if (!this.hasListener('actionfailed')) {
7097 Roo.log("need to add dialog support");
7099 Roo.MessageBox.alert("Error",
7100 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7101 action.result.errorMsg :
7102 "Saving Failed, please check your entries or try again"
7107 this.fireEvent('actionfailed', this, action);
7112 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7113 * @param {String} id The value to search for
7116 findField : function(id){
7117 var items = this.getItems();
7118 var field = items.get(id);
7120 items.each(function(f){
7121 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7128 return field || null;
7131 * Mark fields in this form invalid in bulk.
7132 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7133 * @return {BasicForm} this
7135 markInvalid : function(errors){
7136 if(errors instanceof Array){
7137 for(var i = 0, len = errors.length; i < len; i++){
7138 var fieldError = errors[i];
7139 var f = this.findField(fieldError.id);
7141 f.markInvalid(fieldError.msg);
7147 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7148 field.markInvalid(errors[id]);
7152 //Roo.each(this.childForms || [], function (f) {
7153 // f.markInvalid(errors);
7160 * Set values for fields in this form in bulk.
7161 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7162 * @return {BasicForm} this
7164 setValues : function(values){
7165 if(values instanceof Array){ // array of objects
7166 for(var i = 0, len = values.length; i < len; i++){
7168 var f = this.findField(v.id);
7170 f.setValue(v.value);
7171 if(this.trackResetOnLoad){
7172 f.originalValue = f.getValue();
7176 }else{ // object hash
7179 if(typeof values[id] != 'function' && (field = this.findField(id))){
7181 if (field.setFromData &&
7183 field.displayField &&
7184 // combos' with local stores can
7185 // be queried via setValue()
7186 // to set their value..
7187 (field.store && !field.store.isLocal)
7191 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7192 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7193 field.setFromData(sd);
7196 field.setValue(values[id]);
7200 if(this.trackResetOnLoad){
7201 field.originalValue = field.getValue();
7207 //Roo.each(this.childForms || [], function (f) {
7208 // f.setValues(values);
7215 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7216 * they are returned as an array.
7217 * @param {Boolean} asString
7220 getValues : function(asString){
7221 //if (this.childForms) {
7222 // copy values from the child forms
7223 // Roo.each(this.childForms, function (f) {
7224 // this.setValues(f.getValues());
7230 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7231 if(asString === true){
7234 return Roo.urlDecode(fs);
7238 * Returns the fields in this form as an object with key/value pairs.
7239 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7242 getFieldValues : function(with_hidden)
7244 var items = this.getItems();
7246 items.each(function(f){
7250 var v = f.getValue();
7251 if (f.inputType =='radio') {
7252 if (typeof(ret[f.getName()]) == 'undefined') {
7253 ret[f.getName()] = ''; // empty..
7256 if (!f.el.dom.checked) {
7264 // not sure if this supported any more..
7265 if ((typeof(v) == 'object') && f.getRawValue) {
7266 v = f.getRawValue() ; // dates..
7268 // combo boxes where name != hiddenName...
7269 if (f.name != f.getName()) {
7270 ret[f.name] = f.getRawValue();
7272 ret[f.getName()] = v;
7279 * Clears all invalid messages in this form.
7280 * @return {BasicForm} this
7282 clearInvalid : function(){
7283 var items = this.getItems();
7285 items.each(function(f){
7296 * @return {BasicForm} this
7299 var items = this.getItems();
7300 items.each(function(f){
7304 Roo.each(this.childForms || [], function (f) {
7311 getItems : function()
7313 var r=new Roo.util.MixedCollection(false, function(o){
7314 return o.id || (o.id = Roo.id());
7316 var iter = function(el) {
7323 Roo.each(el.items,function(e) {
7343 * Ext JS Library 1.1.1
7344 * Copyright(c) 2006-2007, Ext JS, LLC.
7346 * Originally Released Under LGPL - original licence link has changed is not relivant.
7349 * <script type="text/javascript">
7352 * @class Roo.form.VTypes
7353 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7356 Roo.form.VTypes = function(){
7357 // closure these in so they are only created once.
7358 var alpha = /^[a-zA-Z_]+$/;
7359 var alphanum = /^[a-zA-Z0-9_]+$/;
7360 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7361 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7363 // All these messages and functions are configurable
7366 * The function used to validate email addresses
7367 * @param {String} value The email address
7369 'email' : function(v){
7370 return email.test(v);
7373 * The error text to display when the email validation function returns false
7376 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7378 * The keystroke filter mask to be applied on email input
7381 'emailMask' : /[a-z0-9_\.\-@]/i,
7384 * The function used to validate URLs
7385 * @param {String} value The URL
7387 'url' : function(v){
7391 * The error text to display when the url validation function returns false
7394 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7397 * The function used to validate alpha values
7398 * @param {String} value The value
7400 'alpha' : function(v){
7401 return alpha.test(v);
7404 * The error text to display when the alpha validation function returns false
7407 'alphaText' : 'This field should only contain letters and _',
7409 * The keystroke filter mask to be applied on alpha input
7412 'alphaMask' : /[a-z_]/i,
7415 * The function used to validate alphanumeric values
7416 * @param {String} value The value
7418 'alphanum' : function(v){
7419 return alphanum.test(v);
7422 * The error text to display when the alphanumeric validation function returns false
7425 'alphanumText' : 'This field should only contain letters, numbers and _',
7427 * The keystroke filter mask to be applied on alphanumeric input
7430 'alphanumMask' : /[a-z0-9_]/i
7440 * @class Roo.bootstrap.Input
7441 * @extends Roo.bootstrap.Component
7442 * Bootstrap Input class
7443 * @cfg {Boolean} disabled is it disabled
7444 * @cfg {String} fieldLabel - the label associated
7445 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7446 * @cfg {String} name name of the input
7447 * @cfg {string} fieldLabel - the label associated
7448 * @cfg {string} inputType - input / file submit ...
7449 * @cfg {string} placeholder - placeholder to put in text.
7450 * @cfg {string} before - input group add on before
7451 * @cfg {string} after - input group add on after
7452 * @cfg {string} size - (lg|sm) or leave empty..
7453 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7454 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7455 * @cfg {Number} md colspan out of 12 for computer-sized screens
7456 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7457 * @cfg {string} value default value of the input
7458 * @cfg {Number} labelWidth set the width of label (0-12)
7459 * @cfg {String} labelAlign (top|left)
7460 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7461 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7463 * @cfg {String} align (left|center|right) Default left
7468 * Create a new Input
7469 * @param {Object} config The config object
7472 Roo.bootstrap.Input = function(config){
7473 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7478 * Fires when this field receives input focus.
7479 * @param {Roo.form.Field} this
7484 * Fires when this field loses input focus.
7485 * @param {Roo.form.Field} this
7490 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7491 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7492 * @param {Roo.form.Field} this
7493 * @param {Roo.EventObject} e The event object
7498 * Fires just before the field blurs if the field value has changed.
7499 * @param {Roo.form.Field} this
7500 * @param {Mixed} newValue The new value
7501 * @param {Mixed} oldValue The original value
7506 * Fires after the field has been marked as invalid.
7507 * @param {Roo.form.Field} this
7508 * @param {String} msg The validation message
7513 * Fires after the field has been validated with no errors.
7514 * @param {Roo.form.Field} this
7519 * Fires after the key up
7520 * @param {Roo.form.Field} this
7521 * @param {Roo.EventObject} e The event Object
7527 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7529 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7530 automatic validation (defaults to "keyup").
7532 validationEvent : "keyup",
7534 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7536 validateOnBlur : true,
7538 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7540 validationDelay : 250,
7542 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7544 focusClass : "x-form-focus", // not needed???
7548 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7550 invalidClass : "has-warning",
7553 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7555 validClass : "has-success",
7558 * @cfg {Boolean} hasFeedback (true|false) default true
7563 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7565 invalidFeedbackClass : "glyphicon-warning-sign",
7568 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7570 validFeedbackClass : "glyphicon-ok",
7573 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7575 selectOnFocus : false,
7578 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7582 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7587 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7589 disableKeyFilter : false,
7592 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7596 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7600 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7602 blankText : "This field is required",
7605 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7609 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7611 maxLength : Number.MAX_VALUE,
7613 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7615 minLengthText : "The minimum length for this field is {0}",
7617 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7619 maxLengthText : "The maximum length for this field is {0}",
7623 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7624 * If available, this function will be called only after the basic validators all return true, and will be passed the
7625 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7629 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7630 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7631 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7635 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7639 autocomplete: false,
7658 formatedValue : false,
7660 parentLabelAlign : function()
7663 while (parent.parent()) {
7664 parent = parent.parent();
7665 if (typeof(parent.labelAlign) !='undefined') {
7666 return parent.labelAlign;
7673 getAutoCreate : function(){
7675 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7681 if(this.inputType != 'hidden'){
7682 cfg.cls = 'form-group' //input-group
7688 type : this.inputType,
7690 cls : 'form-control',
7691 placeholder : this.placeholder || '',
7692 autocomplete : this.autocomplete || 'new-password'
7697 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7700 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7701 input.maxLength = this.maxLength;
7704 if (this.disabled) {
7705 input.disabled=true;
7708 if (this.readOnly) {
7709 input.readonly=true;
7713 input.name = this.name;
7716 input.cls += ' input-' + this.size;
7719 ['xs','sm','md','lg'].map(function(size){
7720 if (settings[size]) {
7721 cfg.cls += ' col-' + size + '-' + settings[size];
7725 var inputblock = input;
7729 cls: 'glyphicon form-control-feedback'
7732 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7735 cls : 'has-feedback',
7743 if (this.before || this.after) {
7746 cls : 'input-group',
7750 if (this.before && typeof(this.before) == 'string') {
7752 inputblock.cn.push({
7754 cls : 'roo-input-before input-group-addon',
7758 if (this.before && typeof(this.before) == 'object') {
7759 this.before = Roo.factory(this.before);
7760 Roo.log(this.before);
7761 inputblock.cn.push({
7763 cls : 'roo-input-before input-group-' +
7764 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7768 inputblock.cn.push(input);
7770 if (this.after && typeof(this.after) == 'string') {
7771 inputblock.cn.push({
7773 cls : 'roo-input-after input-group-addon',
7777 if (this.after && typeof(this.after) == 'object') {
7778 this.after = Roo.factory(this.after);
7779 Roo.log(this.after);
7780 inputblock.cn.push({
7782 cls : 'roo-input-after input-group-' +
7783 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7787 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7788 inputblock.cls += ' has-feedback';
7789 inputblock.cn.push(feedback);
7793 if (align ==='left' && this.fieldLabel.length) {
7794 Roo.log("left and has label");
7800 cls : 'control-label col-sm-' + this.labelWidth,
7801 html : this.fieldLabel
7805 cls : "col-sm-" + (12 - this.labelWidth),
7812 } else if ( this.fieldLabel.length) {
7818 //cls : 'input-group-addon',
7819 html : this.fieldLabel
7829 Roo.log(" no label && no align");
7838 Roo.log('input-parentType: ' + this.parentType);
7840 if (this.parentType === 'Navbar' && this.parent().bar) {
7841 cfg.cls += ' navbar-form';
7849 * return the real input element.
7851 inputEl: function ()
7853 return this.el.select('input.form-control',true).first();
7856 tooltipEl : function()
7858 return this.inputEl();
7861 setDisabled : function(v)
7863 var i = this.inputEl().dom;
7865 i.removeAttribute('disabled');
7869 i.setAttribute('disabled','true');
7871 initEvents : function()
7874 this.inputEl().on("keydown" , this.fireKey, this);
7875 this.inputEl().on("focus", this.onFocus, this);
7876 this.inputEl().on("blur", this.onBlur, this);
7878 this.inputEl().relayEvent('keyup', this);
7880 // reference to original value for reset
7881 this.originalValue = this.getValue();
7882 //Roo.form.TextField.superclass.initEvents.call(this);
7883 if(this.validationEvent == 'keyup'){
7884 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7885 this.inputEl().on('keyup', this.filterValidation, this);
7887 else if(this.validationEvent !== false){
7888 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7891 if(this.selectOnFocus){
7892 this.on("focus", this.preFocus, this);
7895 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7896 this.inputEl().on("keypress", this.filterKeys, this);
7899 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7900 this.el.on("click", this.autoSize, this);
7903 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7904 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7907 if (typeof(this.before) == 'object') {
7908 this.before.render(this.el.select('.roo-input-before',true).first());
7910 if (typeof(this.after) == 'object') {
7911 this.after.render(this.el.select('.roo-input-after',true).first());
7916 filterValidation : function(e){
7917 if(!e.isNavKeyPress()){
7918 this.validationTask.delay(this.validationDelay);
7922 * Validates the field value
7923 * @return {Boolean} True if the value is valid, else false
7925 validate : function(){
7926 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7927 if(this.disabled || this.validateValue(this.getRawValue())){
7938 * Validates a value according to the field's validation rules and marks the field as invalid
7939 * if the validation fails
7940 * @param {Mixed} value The value to validate
7941 * @return {Boolean} True if the value is valid, else false
7943 validateValue : function(value){
7944 if(value.length < 1) { // if it's blank
7945 if(this.allowBlank){
7951 if(value.length < this.minLength){
7954 if(value.length > this.maxLength){
7958 var vt = Roo.form.VTypes;
7959 if(!vt[this.vtype](value, this)){
7963 if(typeof this.validator == "function"){
7964 var msg = this.validator(value);
7970 if(this.regex && !this.regex.test(value)){
7980 fireKey : function(e){
7981 //Roo.log('field ' + e.getKey());
7982 if(e.isNavKeyPress()){
7983 this.fireEvent("specialkey", this, e);
7986 focus : function (selectText){
7988 this.inputEl().focus();
7989 if(selectText === true){
7990 this.inputEl().dom.select();
7996 onFocus : function(){
7997 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7998 // this.el.addClass(this.focusClass);
8001 this.hasFocus = true;
8002 this.startValue = this.getValue();
8003 this.fireEvent("focus", this);
8007 beforeBlur : Roo.emptyFn,
8011 onBlur : function(){
8013 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8014 //this.el.removeClass(this.focusClass);
8016 this.hasFocus = false;
8017 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8020 var v = this.getValue();
8021 if(String(v) !== String(this.startValue)){
8022 this.fireEvent('change', this, v, this.startValue);
8024 this.fireEvent("blur", this);
8028 * Resets the current field value to the originally loaded value and clears any validation messages
8031 this.setValue(this.originalValue);
8035 * Returns the name of the field
8036 * @return {Mixed} name The name field
8038 getName: function(){
8042 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8043 * @return {Mixed} value The field value
8045 getValue : function(){
8047 var v = this.inputEl().getValue();
8052 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8053 * @return {Mixed} value The field value
8055 getRawValue : function(){
8056 var v = this.inputEl().getValue();
8062 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8063 * @param {Mixed} value The value to set
8065 setRawValue : function(v){
8066 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8069 selectText : function(start, end){
8070 var v = this.getRawValue();
8072 start = start === undefined ? 0 : start;
8073 end = end === undefined ? v.length : end;
8074 var d = this.inputEl().dom;
8075 if(d.setSelectionRange){
8076 d.setSelectionRange(start, end);
8077 }else if(d.createTextRange){
8078 var range = d.createTextRange();
8079 range.moveStart("character", start);
8080 range.moveEnd("character", v.length-end);
8087 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8088 * @param {Mixed} value The value to set
8090 setValue : function(v){
8093 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8099 processValue : function(value){
8100 if(this.stripCharsRe){
8101 var newValue = value.replace(this.stripCharsRe, '');
8102 if(newValue !== value){
8103 this.setRawValue(newValue);
8110 preFocus : function(){
8112 if(this.selectOnFocus){
8113 this.inputEl().dom.select();
8116 filterKeys : function(e){
8118 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8121 var c = e.getCharCode(), cc = String.fromCharCode(c);
8122 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8125 if(!this.maskRe.test(cc)){
8130 * Clear any invalid styles/messages for this field
8132 clearInvalid : function(){
8134 if(!this.el || this.preventMark){ // not rendered
8137 this.el.removeClass(this.invalidClass);
8139 this.fireEvent('valid', this);
8143 * Mark this field as valid
8145 markValid : function(){
8146 if(!this.el || this.preventMark){ // not rendered
8150 this.el.removeClass([this.invalidClass, this.validClass]);
8152 if(this.disabled || this.allowBlank){
8156 this.el.addClass(this.validClass);
8158 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8160 var feedback = this.el.select('.form-control-feedback', true).first();
8163 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8164 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8169 this.fireEvent('valid', this);
8173 * Mark this field as invalid
8174 * @param {String} msg The validation message
8176 markInvalid : function(msg){
8177 if(!this.el || this.preventMark){ // not rendered
8181 this.el.removeClass([this.invalidClass, this.validClass]);
8183 if(this.disabled || this.allowBlank){
8187 this.el.addClass(this.invalidClass);
8189 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8191 var feedback = this.el.select('.form-control-feedback', true).first();
8194 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8196 if(this.getValue().length){
8197 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8204 this.fireEvent('invalid', this, msg);
8207 SafariOnKeyDown : function(event)
8209 // this is a workaround for a password hang bug on chrome/ webkit.
8211 var isSelectAll = false;
8213 if(this.inputEl().dom.selectionEnd > 0){
8214 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8216 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8217 event.preventDefault();
8222 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8224 event.preventDefault();
8225 // this is very hacky as keydown always get's upper case.
8227 var cc = String.fromCharCode(event.getCharCode());
8228 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8232 adjustWidth : function(tag, w){
8233 tag = tag.toLowerCase();
8234 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8235 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8239 if(tag == 'textarea'){
8242 }else if(Roo.isOpera){
8246 if(tag == 'textarea'){
8265 * @class Roo.bootstrap.TextArea
8266 * @extends Roo.bootstrap.Input
8267 * Bootstrap TextArea class
8268 * @cfg {Number} cols Specifies the visible width of a text area
8269 * @cfg {Number} rows Specifies the visible number of lines in a text area
8270 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8271 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8272 * @cfg {string} html text
8275 * Create a new TextArea
8276 * @param {Object} config The config object
8279 Roo.bootstrap.TextArea = function(config){
8280 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8284 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8294 getAutoCreate : function(){
8296 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8307 value : this.value || '',
8308 html: this.html || '',
8309 cls : 'form-control',
8310 placeholder : this.placeholder || ''
8314 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8315 input.maxLength = this.maxLength;
8319 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8323 input.cols = this.cols;
8326 if (this.readOnly) {
8327 input.readonly = true;
8331 input.name = this.name;
8335 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8339 ['xs','sm','md','lg'].map(function(size){
8340 if (settings[size]) {
8341 cfg.cls += ' col-' + size + '-' + settings[size];
8345 var inputblock = input;
8347 if(this.hasFeedback && !this.allowBlank){
8351 cls: 'glyphicon form-control-feedback'
8355 cls : 'has-feedback',
8364 if (this.before || this.after) {
8367 cls : 'input-group',
8371 inputblock.cn.push({
8373 cls : 'input-group-addon',
8378 inputblock.cn.push(input);
8380 if(this.hasFeedback && !this.allowBlank){
8381 inputblock.cls += ' has-feedback';
8382 inputblock.cn.push(feedback);
8386 inputblock.cn.push({
8388 cls : 'input-group-addon',
8395 if (align ==='left' && this.fieldLabel.length) {
8396 Roo.log("left and has label");
8402 cls : 'control-label col-sm-' + this.labelWidth,
8403 html : this.fieldLabel
8407 cls : "col-sm-" + (12 - this.labelWidth),
8414 } else if ( this.fieldLabel.length) {
8420 //cls : 'input-group-addon',
8421 html : this.fieldLabel
8431 Roo.log(" no label && no align");
8441 if (this.disabled) {
8442 input.disabled=true;
8449 * return the real textarea element.
8451 inputEl: function ()
8453 return this.el.select('textarea.form-control',true).first();
8461 * trigger field - base class for combo..
8466 * @class Roo.bootstrap.TriggerField
8467 * @extends Roo.bootstrap.Input
8468 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8469 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8470 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8471 * for which you can provide a custom implementation. For example:
8473 var trigger = new Roo.bootstrap.TriggerField();
8474 trigger.onTriggerClick = myTriggerFn;
8475 trigger.applyTo('my-field');
8478 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8479 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8480 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8481 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8482 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8485 * Create a new TriggerField.
8486 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8487 * to the base TextField)
8489 Roo.bootstrap.TriggerField = function(config){
8490 this.mimicing = false;
8491 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8494 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8496 * @cfg {String} triggerClass A CSS class to apply to the trigger
8499 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8504 * @cfg {Boolean} removable (true|false) special filter default false
8508 /** @cfg {Boolean} grow @hide */
8509 /** @cfg {Number} growMin @hide */
8510 /** @cfg {Number} growMax @hide */
8516 autoSize: Roo.emptyFn,
8523 actionMode : 'wrap',
8528 getAutoCreate : function(){
8530 var align = this.labelAlign || this.parentLabelAlign();
8535 cls: 'form-group' //input-group
8542 type : this.inputType,
8543 cls : 'form-control',
8544 autocomplete: 'new-password',
8545 placeholder : this.placeholder || ''
8549 input.name = this.name;
8552 input.cls += ' input-' + this.size;
8555 if (this.disabled) {
8556 input.disabled=true;
8559 var inputblock = input;
8561 if(this.hasFeedback && !this.allowBlank){
8565 cls: 'glyphicon form-control-feedback'
8568 if(this.removable && !this.editable && !this.tickable){
8570 cls : 'has-feedback',
8576 cls : 'roo-combo-removable-btn close'
8583 cls : 'has-feedback',
8592 if(this.removable && !this.editable && !this.tickable){
8594 cls : 'roo-removable',
8600 cls : 'roo-combo-removable-btn close'
8607 if (this.before || this.after) {
8610 cls : 'input-group',
8614 inputblock.cn.push({
8616 cls : 'input-group-addon',
8621 inputblock.cn.push(input);
8623 if(this.hasFeedback && !this.allowBlank){
8624 inputblock.cls += ' has-feedback';
8625 inputblock.cn.push(feedback);
8629 inputblock.cn.push({
8631 cls : 'input-group-addon',
8644 cls: 'form-hidden-field'
8652 Roo.log('multiple');
8660 cls: 'form-hidden-field'
8664 cls: 'select2-choices',
8668 cls: 'select2-search-field',
8681 cls: 'select2-container input-group',
8686 // cls: 'typeahead typeahead-long dropdown-menu',
8687 // style: 'display:none'
8692 if(!this.multiple && this.showToggleBtn){
8698 if (this.caret != false) {
8701 cls: 'fa fa-' + this.caret
8708 cls : 'input-group-addon btn dropdown-toggle',
8713 cls: 'combobox-clear',
8727 combobox.cls += ' select2-container-multi';
8730 if (align ==='left' && this.fieldLabel.length) {
8732 Roo.log("left and has label");
8738 cls : 'control-label col-sm-' + this.labelWidth,
8739 html : this.fieldLabel
8743 cls : "col-sm-" + (12 - this.labelWidth),
8750 } else if ( this.fieldLabel.length) {
8756 //cls : 'input-group-addon',
8757 html : this.fieldLabel
8767 Roo.log(" no label && no align");
8774 ['xs','sm','md','lg'].map(function(size){
8775 if (settings[size]) {
8776 cfg.cls += ' col-' + size + '-' + settings[size];
8787 onResize : function(w, h){
8788 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8789 // if(typeof w == 'number'){
8790 // var x = w - this.trigger.getWidth();
8791 // this.inputEl().setWidth(this.adjustWidth('input', x));
8792 // this.trigger.setStyle('left', x+'px');
8797 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8800 getResizeEl : function(){
8801 return this.inputEl();
8805 getPositionEl : function(){
8806 return this.inputEl();
8810 alignErrorIcon : function(){
8811 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8815 initEvents : function(){
8819 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8820 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8821 if(!this.multiple && this.showToggleBtn){
8822 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8823 if(this.hideTrigger){
8824 this.trigger.setDisplayed(false);
8826 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8830 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8833 if(this.removable && !this.editable && !this.tickable){
8834 var close = this.closeTriggerEl();
8837 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8838 close.on('click', this.removeBtnClick, this, close);
8842 //this.trigger.addClassOnOver('x-form-trigger-over');
8843 //this.trigger.addClassOnClick('x-form-trigger-click');
8846 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8850 closeTriggerEl : function()
8852 var close = this.el.select('.roo-combo-removable-btn', true).first();
8853 return close ? close : false;
8856 removeBtnClick : function(e, h, el)
8860 this.fireEvent("remove", this);
8863 createList : function()
8865 this.list = Roo.get(document.body).createChild({
8867 cls: 'typeahead typeahead-long dropdown-menu',
8868 style: 'display:none'
8871 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8876 initTrigger : function(){
8881 onDestroy : function(){
8883 this.trigger.removeAllListeners();
8884 // this.trigger.remove();
8887 // this.wrap.remove();
8889 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8893 onFocus : function(){
8894 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8897 this.wrap.addClass('x-trigger-wrap-focus');
8898 this.mimicing = true;
8899 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8900 if(this.monitorTab){
8901 this.el.on("keydown", this.checkTab, this);
8908 checkTab : function(e){
8909 if(e.getKey() == e.TAB){
8915 onBlur : function(){
8920 mimicBlur : function(e, t){
8922 if(!this.wrap.contains(t) && this.validateBlur()){
8929 triggerBlur : function(){
8930 this.mimicing = false;
8931 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8932 if(this.monitorTab){
8933 this.el.un("keydown", this.checkTab, this);
8935 //this.wrap.removeClass('x-trigger-wrap-focus');
8936 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8940 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8941 validateBlur : function(e, t){
8946 onDisable : function(){
8947 this.inputEl().dom.disabled = true;
8948 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8950 // this.wrap.addClass('x-item-disabled');
8955 onEnable : function(){
8956 this.inputEl().dom.disabled = false;
8957 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8959 // this.el.removeClass('x-item-disabled');
8964 onShow : function(){
8965 var ae = this.getActionEl();
8968 ae.dom.style.display = '';
8969 ae.dom.style.visibility = 'visible';
8975 onHide : function(){
8976 var ae = this.getActionEl();
8977 ae.dom.style.display = 'none';
8981 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8982 * by an implementing function.
8984 * @param {EventObject} e
8986 onTriggerClick : Roo.emptyFn
8990 * Ext JS Library 1.1.1
8991 * Copyright(c) 2006-2007, Ext JS, LLC.
8993 * Originally Released Under LGPL - original licence link has changed is not relivant.
8996 * <script type="text/javascript">
9001 * @class Roo.data.SortTypes
9003 * Defines the default sorting (casting?) comparison functions used when sorting data.
9005 Roo.data.SortTypes = {
9007 * Default sort that does nothing
9008 * @param {Mixed} s The value being converted
9009 * @return {Mixed} The comparison value
9016 * The regular expression used to strip tags
9020 stripTagsRE : /<\/?[^>]+>/gi,
9023 * Strips all HTML tags to sort on text only
9024 * @param {Mixed} s The value being converted
9025 * @return {String} The comparison value
9027 asText : function(s){
9028 return String(s).replace(this.stripTagsRE, "");
9032 * Strips all HTML tags to sort on text only - Case insensitive
9033 * @param {Mixed} s The value being converted
9034 * @return {String} The comparison value
9036 asUCText : function(s){
9037 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9041 * Case insensitive string
9042 * @param {Mixed} s The value being converted
9043 * @return {String} The comparison value
9045 asUCString : function(s) {
9046 return String(s).toUpperCase();
9051 * @param {Mixed} s The value being converted
9052 * @return {Number} The comparison value
9054 asDate : function(s) {
9058 if(s instanceof Date){
9061 return Date.parse(String(s));
9066 * @param {Mixed} s The value being converted
9067 * @return {Float} The comparison value
9069 asFloat : function(s) {
9070 var val = parseFloat(String(s).replace(/,/g, ""));
9071 if(isNaN(val)) val = 0;
9077 * @param {Mixed} s The value being converted
9078 * @return {Number} The comparison value
9080 asInt : function(s) {
9081 var val = parseInt(String(s).replace(/,/g, ""));
9082 if(isNaN(val)) val = 0;
9087 * Ext JS Library 1.1.1
9088 * Copyright(c) 2006-2007, Ext JS, LLC.
9090 * Originally Released Under LGPL - original licence link has changed is not relivant.
9093 * <script type="text/javascript">
9097 * @class Roo.data.Record
9098 * Instances of this class encapsulate both record <em>definition</em> information, and record
9099 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9100 * to access Records cached in an {@link Roo.data.Store} object.<br>
9102 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9103 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9106 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9108 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9109 * {@link #create}. The parameters are the same.
9110 * @param {Array} data An associative Array of data values keyed by the field name.
9111 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9112 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9113 * not specified an integer id is generated.
9115 Roo.data.Record = function(data, id){
9116 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9121 * Generate a constructor for a specific record layout.
9122 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9123 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9124 * Each field definition object may contain the following properties: <ul>
9125 * <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,
9126 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9127 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9128 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9129 * is being used, then this is a string containing the javascript expression to reference the data relative to
9130 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9131 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9132 * this may be omitted.</p></li>
9133 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9134 * <ul><li>auto (Default, implies no conversion)</li>
9139 * <li>date</li></ul></p></li>
9140 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9141 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9142 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9143 * by the Reader into an object that will be stored in the Record. It is passed the
9144 * following parameters:<ul>
9145 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9147 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9149 * <br>usage:<br><pre><code>
9150 var TopicRecord = Roo.data.Record.create(
9151 {name: 'title', mapping: 'topic_title'},
9152 {name: 'author', mapping: 'username'},
9153 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9154 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9155 {name: 'lastPoster', mapping: 'user2'},
9156 {name: 'excerpt', mapping: 'post_text'}
9159 var myNewRecord = new TopicRecord({
9160 title: 'Do my job please',
9163 lastPost: new Date(),
9164 lastPoster: 'Animal',
9165 excerpt: 'No way dude!'
9167 myStore.add(myNewRecord);
9172 Roo.data.Record.create = function(o){
9174 f.superclass.constructor.apply(this, arguments);
9176 Roo.extend(f, Roo.data.Record);
9177 var p = f.prototype;
9178 p.fields = new Roo.util.MixedCollection(false, function(field){
9181 for(var i = 0, len = o.length; i < len; i++){
9182 p.fields.add(new Roo.data.Field(o[i]));
9184 f.getField = function(name){
9185 return p.fields.get(name);
9190 Roo.data.Record.AUTO_ID = 1000;
9191 Roo.data.Record.EDIT = 'edit';
9192 Roo.data.Record.REJECT = 'reject';
9193 Roo.data.Record.COMMIT = 'commit';
9195 Roo.data.Record.prototype = {
9197 * Readonly flag - true if this record has been modified.
9206 join : function(store){
9211 * Set the named field to the specified value.
9212 * @param {String} name The name of the field to set.
9213 * @param {Object} value The value to set the field to.
9215 set : function(name, value){
9216 if(this.data[name] == value){
9223 if(typeof this.modified[name] == 'undefined'){
9224 this.modified[name] = this.data[name];
9226 this.data[name] = value;
9227 if(!this.editing && this.store){
9228 this.store.afterEdit(this);
9233 * Get the value of the named field.
9234 * @param {String} name The name of the field to get the value of.
9235 * @return {Object} The value of the field.
9237 get : function(name){
9238 return this.data[name];
9242 beginEdit : function(){
9243 this.editing = true;
9248 cancelEdit : function(){
9249 this.editing = false;
9250 delete this.modified;
9254 endEdit : function(){
9255 this.editing = false;
9256 if(this.dirty && this.store){
9257 this.store.afterEdit(this);
9262 * Usually called by the {@link Roo.data.Store} which owns the Record.
9263 * Rejects all changes made to the Record since either creation, or the last commit operation.
9264 * Modified fields are reverted to their original values.
9266 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9267 * of reject operations.
9269 reject : function(){
9270 var m = this.modified;
9272 if(typeof m[n] != "function"){
9273 this.data[n] = m[n];
9277 delete this.modified;
9278 this.editing = false;
9280 this.store.afterReject(this);
9285 * Usually called by the {@link Roo.data.Store} which owns the Record.
9286 * Commits all changes made to the Record since either creation, or the last commit operation.
9288 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9289 * of commit operations.
9291 commit : function(){
9293 delete this.modified;
9294 this.editing = false;
9296 this.store.afterCommit(this);
9301 hasError : function(){
9302 return this.error != null;
9306 clearError : function(){
9311 * Creates a copy of this record.
9312 * @param {String} id (optional) A new record id if you don't want to use this record's id
9315 copy : function(newId) {
9316 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9320 * Ext JS Library 1.1.1
9321 * Copyright(c) 2006-2007, Ext JS, LLC.
9323 * Originally Released Under LGPL - original licence link has changed is not relivant.
9326 * <script type="text/javascript">
9332 * @class Roo.data.Store
9333 * @extends Roo.util.Observable
9334 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9335 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9337 * 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
9338 * has no knowledge of the format of the data returned by the Proxy.<br>
9340 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9341 * instances from the data object. These records are cached and made available through accessor functions.
9343 * Creates a new Store.
9344 * @param {Object} config A config object containing the objects needed for the Store to access data,
9345 * and read the data into Records.
9347 Roo.data.Store = function(config){
9348 this.data = new Roo.util.MixedCollection(false);
9349 this.data.getKey = function(o){
9352 this.baseParams = {};
9359 "multisort" : "_multisort"
9362 if(config && config.data){
9363 this.inlineData = config.data;
9367 Roo.apply(this, config);
9369 if(this.reader){ // reader passed
9370 this.reader = Roo.factory(this.reader, Roo.data);
9371 this.reader.xmodule = this.xmodule || false;
9372 if(!this.recordType){
9373 this.recordType = this.reader.recordType;
9375 if(this.reader.onMetaChange){
9376 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9380 if(this.recordType){
9381 this.fields = this.recordType.prototype.fields;
9387 * @event datachanged
9388 * Fires when the data cache has changed, and a widget which is using this Store
9389 * as a Record cache should refresh its view.
9390 * @param {Store} this
9395 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9396 * @param {Store} this
9397 * @param {Object} meta The JSON metadata
9402 * Fires when Records have been added to the Store
9403 * @param {Store} this
9404 * @param {Roo.data.Record[]} records The array of Records added
9405 * @param {Number} index The index at which the record(s) were added
9410 * Fires when a Record has been removed from the Store
9411 * @param {Store} this
9412 * @param {Roo.data.Record} record The Record that was removed
9413 * @param {Number} index The index at which the record was removed
9418 * Fires when a Record has been updated
9419 * @param {Store} this
9420 * @param {Roo.data.Record} record The Record that was updated
9421 * @param {String} operation The update operation being performed. Value may be one of:
9423 Roo.data.Record.EDIT
9424 Roo.data.Record.REJECT
9425 Roo.data.Record.COMMIT
9431 * Fires when the data cache has been cleared.
9432 * @param {Store} this
9437 * Fires before a request is made for a new data object. If the beforeload handler returns false
9438 * the load action will be canceled.
9439 * @param {Store} this
9440 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9444 * @event beforeloadadd
9445 * Fires after a new set of Records has been loaded.
9446 * @param {Store} this
9447 * @param {Roo.data.Record[]} records The Records that were loaded
9448 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9450 beforeloadadd : true,
9453 * Fires after a new set of Records has been loaded, before they are added to the store.
9454 * @param {Store} this
9455 * @param {Roo.data.Record[]} records The Records that were loaded
9456 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9457 * @params {Object} return from reader
9461 * @event loadexception
9462 * Fires if an exception occurs in the Proxy during loading.
9463 * Called with the signature of the Proxy's "loadexception" event.
9464 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9467 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9468 * @param {Object} load options
9469 * @param {Object} jsonData from your request (normally this contains the Exception)
9471 loadexception : true
9475 this.proxy = Roo.factory(this.proxy, Roo.data);
9476 this.proxy.xmodule = this.xmodule || false;
9477 this.relayEvents(this.proxy, ["loadexception"]);
9479 this.sortToggle = {};
9480 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9482 Roo.data.Store.superclass.constructor.call(this);
9484 if(this.inlineData){
9485 this.loadData(this.inlineData);
9486 delete this.inlineData;
9490 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9492 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9493 * without a remote query - used by combo/forms at present.
9497 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9500 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9503 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9504 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9507 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9508 * on any HTTP request
9511 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9514 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9518 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9519 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9524 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9525 * loaded or when a record is removed. (defaults to false).
9527 pruneModifiedRecords : false,
9533 * Add Records to the Store and fires the add event.
9534 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9536 add : function(records){
9537 records = [].concat(records);
9538 for(var i = 0, len = records.length; i < len; i++){
9539 records[i].join(this);
9541 var index = this.data.length;
9542 this.data.addAll(records);
9543 this.fireEvent("add", this, records, index);
9547 * Remove a Record from the Store and fires the remove event.
9548 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9550 remove : function(record){
9551 var index = this.data.indexOf(record);
9552 this.data.removeAt(index);
9553 if(this.pruneModifiedRecords){
9554 this.modified.remove(record);
9556 this.fireEvent("remove", this, record, index);
9560 * Remove all Records from the Store and fires the clear event.
9562 removeAll : function(){
9564 if(this.pruneModifiedRecords){
9567 this.fireEvent("clear", this);
9571 * Inserts Records to the Store at the given index and fires the add event.
9572 * @param {Number} index The start index at which to insert the passed Records.
9573 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9575 insert : function(index, records){
9576 records = [].concat(records);
9577 for(var i = 0, len = records.length; i < len; i++){
9578 this.data.insert(index, records[i]);
9579 records[i].join(this);
9581 this.fireEvent("add", this, records, index);
9585 * Get the index within the cache of the passed Record.
9586 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9587 * @return {Number} The index of the passed Record. Returns -1 if not found.
9589 indexOf : function(record){
9590 return this.data.indexOf(record);
9594 * Get the index within the cache of the Record with the passed id.
9595 * @param {String} id The id of the Record to find.
9596 * @return {Number} The index of the Record. Returns -1 if not found.
9598 indexOfId : function(id){
9599 return this.data.indexOfKey(id);
9603 * Get the Record with the specified id.
9604 * @param {String} id The id of the Record to find.
9605 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9607 getById : function(id){
9608 return this.data.key(id);
9612 * Get the Record at the specified index.
9613 * @param {Number} index The index of the Record to find.
9614 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9616 getAt : function(index){
9617 return this.data.itemAt(index);
9621 * Returns a range of Records between specified indices.
9622 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9623 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9624 * @return {Roo.data.Record[]} An array of Records
9626 getRange : function(start, end){
9627 return this.data.getRange(start, end);
9631 storeOptions : function(o){
9632 o = Roo.apply({}, o);
9635 this.lastOptions = o;
9639 * Loads the Record cache from the configured Proxy using the configured Reader.
9641 * If using remote paging, then the first load call must specify the <em>start</em>
9642 * and <em>limit</em> properties in the options.params property to establish the initial
9643 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9645 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9646 * and this call will return before the new data has been loaded. Perform any post-processing
9647 * in a callback function, or in a "load" event handler.</strong>
9649 * @param {Object} options An object containing properties which control loading options:<ul>
9650 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9651 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9652 * passed the following arguments:<ul>
9653 * <li>r : Roo.data.Record[]</li>
9654 * <li>options: Options object from the load call</li>
9655 * <li>success: Boolean success indicator</li></ul></li>
9656 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9657 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9660 load : function(options){
9661 options = options || {};
9662 if(this.fireEvent("beforeload", this, options) !== false){
9663 this.storeOptions(options);
9664 var p = Roo.apply(options.params || {}, this.baseParams);
9665 // if meta was not loaded from remote source.. try requesting it.
9666 if (!this.reader.metaFromRemote) {
9669 if(this.sortInfo && this.remoteSort){
9670 var pn = this.paramNames;
9671 p[pn["sort"]] = this.sortInfo.field;
9672 p[pn["dir"]] = this.sortInfo.direction;
9674 if (this.multiSort) {
9675 var pn = this.paramNames;
9676 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9679 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9684 * Reloads the Record cache from the configured Proxy using the configured Reader and
9685 * the options from the last load operation performed.
9686 * @param {Object} options (optional) An object containing properties which may override the options
9687 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9688 * the most recently used options are reused).
9690 reload : function(options){
9691 this.load(Roo.applyIf(options||{}, this.lastOptions));
9695 // Called as a callback by the Reader during a load operation.
9696 loadRecords : function(o, options, success){
9697 if(!o || success === false){
9698 if(success !== false){
9699 this.fireEvent("load", this, [], options, o);
9701 if(options.callback){
9702 options.callback.call(options.scope || this, [], options, false);
9706 // if data returned failure - throw an exception.
9707 if (o.success === false) {
9708 // show a message if no listener is registered.
9709 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9710 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9712 // loadmask wil be hooked into this..
9713 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9716 var r = o.records, t = o.totalRecords || r.length;
9718 this.fireEvent("beforeloadadd", this, r, options, o);
9720 if(!options || options.add !== true){
9721 if(this.pruneModifiedRecords){
9724 for(var i = 0, len = r.length; i < len; i++){
9728 this.data = this.snapshot;
9729 delete this.snapshot;
9732 this.data.addAll(r);
9733 this.totalLength = t;
9735 this.fireEvent("datachanged", this);
9737 this.totalLength = Math.max(t, this.data.length+r.length);
9740 this.fireEvent("load", this, r, options, o);
9741 if(options.callback){
9742 options.callback.call(options.scope || this, r, options, true);
9748 * Loads data from a passed data block. A Reader which understands the format of the data
9749 * must have been configured in the constructor.
9750 * @param {Object} data The data block from which to read the Records. The format of the data expected
9751 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9752 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9754 loadData : function(o, append){
9755 var r = this.reader.readRecords(o);
9756 this.loadRecords(r, {add: append}, true);
9760 * Gets the number of cached records.
9762 * <em>If using paging, this may not be the total size of the dataset. If the data object
9763 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9764 * the data set size</em>
9766 getCount : function(){
9767 return this.data.length || 0;
9771 * Gets the total number of records in the dataset as returned by the server.
9773 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9774 * the dataset size</em>
9776 getTotalCount : function(){
9777 return this.totalLength || 0;
9781 * Returns the sort state of the Store as an object with two properties:
9783 field {String} The name of the field by which the Records are sorted
9784 direction {String} The sort order, "ASC" or "DESC"
9787 getSortState : function(){
9788 return this.sortInfo;
9792 applySort : function(){
9793 if(this.sortInfo && !this.remoteSort){
9794 var s = this.sortInfo, f = s.field;
9795 var st = this.fields.get(f).sortType;
9796 var fn = function(r1, r2){
9797 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9798 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9800 this.data.sort(s.direction, fn);
9801 if(this.snapshot && this.snapshot != this.data){
9802 this.snapshot.sort(s.direction, fn);
9808 * Sets the default sort column and order to be used by the next load operation.
9809 * @param {String} fieldName The name of the field to sort by.
9810 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9812 setDefaultSort : function(field, dir){
9813 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9818 * If remote sorting is used, the sort is performed on the server, and the cache is
9819 * reloaded. If local sorting is used, the cache is sorted internally.
9820 * @param {String} fieldName The name of the field to sort by.
9821 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9823 sort : function(fieldName, dir){
9824 var f = this.fields.get(fieldName);
9826 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9828 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9829 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9834 this.sortToggle[f.name] = dir;
9835 this.sortInfo = {field: f.name, direction: dir};
9836 if(!this.remoteSort){
9838 this.fireEvent("datachanged", this);
9840 this.load(this.lastOptions);
9845 * Calls the specified function for each of the Records in the cache.
9846 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9847 * Returning <em>false</em> aborts and exits the iteration.
9848 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9850 each : function(fn, scope){
9851 this.data.each(fn, scope);
9855 * Gets all records modified since the last commit. Modified records are persisted across load operations
9856 * (e.g., during paging).
9857 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9859 getModifiedRecords : function(){
9860 return this.modified;
9864 createFilterFn : function(property, value, anyMatch){
9865 if(!value.exec){ // not a regex
9866 value = String(value);
9867 if(value.length == 0){
9870 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9873 return value.test(r.data[property]);
9878 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9879 * @param {String} property A field on your records
9880 * @param {Number} start The record index to start at (defaults to 0)
9881 * @param {Number} end The last record index to include (defaults to length - 1)
9882 * @return {Number} The sum
9884 sum : function(property, start, end){
9885 var rs = this.data.items, v = 0;
9887 end = (end || end === 0) ? end : rs.length-1;
9889 for(var i = start; i <= end; i++){
9890 v += (rs[i].data[property] || 0);
9896 * Filter the records by a specified property.
9897 * @param {String} field A field on your records
9898 * @param {String/RegExp} value Either a string that the field
9899 * should start with or a RegExp to test against the field
9900 * @param {Boolean} anyMatch True to match any part not just the beginning
9902 filter : function(property, value, anyMatch){
9903 var fn = this.createFilterFn(property, value, anyMatch);
9904 return fn ? this.filterBy(fn) : this.clearFilter();
9908 * Filter by a function. The specified function will be called with each
9909 * record in this data source. If the function returns true the record is included,
9910 * otherwise it is filtered.
9911 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9912 * @param {Object} scope (optional) The scope of the function (defaults to this)
9914 filterBy : function(fn, scope){
9915 this.snapshot = this.snapshot || this.data;
9916 this.data = this.queryBy(fn, scope||this);
9917 this.fireEvent("datachanged", this);
9921 * Query the records by a specified property.
9922 * @param {String} field A field on your records
9923 * @param {String/RegExp} value Either a string that the field
9924 * should start with or a RegExp to test against the field
9925 * @param {Boolean} anyMatch True to match any part not just the beginning
9926 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9928 query : function(property, value, anyMatch){
9929 var fn = this.createFilterFn(property, value, anyMatch);
9930 return fn ? this.queryBy(fn) : this.data.clone();
9934 * Query by a function. The specified function will be called with each
9935 * record in this data source. If the function returns true the record is included
9937 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9938 * @param {Object} scope (optional) The scope of the function (defaults to this)
9939 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9941 queryBy : function(fn, scope){
9942 var data = this.snapshot || this.data;
9943 return data.filterBy(fn, scope||this);
9947 * Collects unique values for a particular dataIndex from this store.
9948 * @param {String} dataIndex The property to collect
9949 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9950 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9951 * @return {Array} An array of the unique values
9953 collect : function(dataIndex, allowNull, bypassFilter){
9954 var d = (bypassFilter === true && this.snapshot) ?
9955 this.snapshot.items : this.data.items;
9956 var v, sv, r = [], l = {};
9957 for(var i = 0, len = d.length; i < len; i++){
9958 v = d[i].data[dataIndex];
9960 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9969 * Revert to a view of the Record cache with no filtering applied.
9970 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9972 clearFilter : function(suppressEvent){
9973 if(this.snapshot && this.snapshot != this.data){
9974 this.data = this.snapshot;
9975 delete this.snapshot;
9976 if(suppressEvent !== true){
9977 this.fireEvent("datachanged", this);
9983 afterEdit : function(record){
9984 if(this.modified.indexOf(record) == -1){
9985 this.modified.push(record);
9987 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9991 afterReject : function(record){
9992 this.modified.remove(record);
9993 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9997 afterCommit : function(record){
9998 this.modified.remove(record);
9999 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10003 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10004 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10006 commitChanges : function(){
10007 var m = this.modified.slice(0);
10008 this.modified = [];
10009 for(var i = 0, len = m.length; i < len; i++){
10015 * Cancel outstanding changes on all changed records.
10017 rejectChanges : function(){
10018 var m = this.modified.slice(0);
10019 this.modified = [];
10020 for(var i = 0, len = m.length; i < len; i++){
10025 onMetaChange : function(meta, rtype, o){
10026 this.recordType = rtype;
10027 this.fields = rtype.prototype.fields;
10028 delete this.snapshot;
10029 this.sortInfo = meta.sortInfo || this.sortInfo;
10030 this.modified = [];
10031 this.fireEvent('metachange', this, this.reader.meta);
10034 moveIndex : function(data, type)
10036 var index = this.indexOf(data);
10038 var newIndex = index + type;
10042 this.insert(newIndex, data);
10047 * Ext JS Library 1.1.1
10048 * Copyright(c) 2006-2007, Ext JS, LLC.
10050 * Originally Released Under LGPL - original licence link has changed is not relivant.
10053 * <script type="text/javascript">
10057 * @class Roo.data.SimpleStore
10058 * @extends Roo.data.Store
10059 * Small helper class to make creating Stores from Array data easier.
10060 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10061 * @cfg {Array} fields An array of field definition objects, or field name strings.
10062 * @cfg {Array} data The multi-dimensional array of data
10064 * @param {Object} config
10066 Roo.data.SimpleStore = function(config){
10067 Roo.data.SimpleStore.superclass.constructor.call(this, {
10069 reader: new Roo.data.ArrayReader({
10072 Roo.data.Record.create(config.fields)
10074 proxy : new Roo.data.MemoryProxy(config.data)
10078 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10080 * Ext JS Library 1.1.1
10081 * Copyright(c) 2006-2007, Ext JS, LLC.
10083 * Originally Released Under LGPL - original licence link has changed is not relivant.
10086 * <script type="text/javascript">
10091 * @extends Roo.data.Store
10092 * @class Roo.data.JsonStore
10093 * Small helper class to make creating Stores for JSON data easier. <br/>
10095 var store = new Roo.data.JsonStore({
10096 url: 'get-images.php',
10098 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10101 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10102 * JsonReader and HttpProxy (unless inline data is provided).</b>
10103 * @cfg {Array} fields An array of field definition objects, or field name strings.
10105 * @param {Object} config
10107 Roo.data.JsonStore = function(c){
10108 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10109 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10110 reader: new Roo.data.JsonReader(c, c.fields)
10113 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10115 * Ext JS Library 1.1.1
10116 * Copyright(c) 2006-2007, Ext JS, LLC.
10118 * Originally Released Under LGPL - original licence link has changed is not relivant.
10121 * <script type="text/javascript">
10125 Roo.data.Field = function(config){
10126 if(typeof config == "string"){
10127 config = {name: config};
10129 Roo.apply(this, config);
10132 this.type = "auto";
10135 var st = Roo.data.SortTypes;
10136 // named sortTypes are supported, here we look them up
10137 if(typeof this.sortType == "string"){
10138 this.sortType = st[this.sortType];
10141 // set default sortType for strings and dates
10142 if(!this.sortType){
10145 this.sortType = st.asUCString;
10148 this.sortType = st.asDate;
10151 this.sortType = st.none;
10156 var stripRe = /[\$,%]/g;
10158 // prebuilt conversion function for this field, instead of
10159 // switching every time we're reading a value
10161 var cv, dateFormat = this.dateFormat;
10166 cv = function(v){ return v; };
10169 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10173 return v !== undefined && v !== null && v !== '' ?
10174 parseInt(String(v).replace(stripRe, ""), 10) : '';
10179 return v !== undefined && v !== null && v !== '' ?
10180 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10185 cv = function(v){ return v === true || v === "true" || v == 1; };
10192 if(v instanceof Date){
10196 if(dateFormat == "timestamp"){
10197 return new Date(v*1000);
10199 return Date.parseDate(v, dateFormat);
10201 var parsed = Date.parse(v);
10202 return parsed ? new Date(parsed) : null;
10211 Roo.data.Field.prototype = {
10219 * Ext JS Library 1.1.1
10220 * Copyright(c) 2006-2007, Ext JS, LLC.
10222 * Originally Released Under LGPL - original licence link has changed is not relivant.
10225 * <script type="text/javascript">
10228 // Base class for reading structured data from a data source. This class is intended to be
10229 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10232 * @class Roo.data.DataReader
10233 * Base class for reading structured data from a data source. This class is intended to be
10234 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10237 Roo.data.DataReader = function(meta, recordType){
10241 this.recordType = recordType instanceof Array ?
10242 Roo.data.Record.create(recordType) : recordType;
10245 Roo.data.DataReader.prototype = {
10247 * Create an empty record
10248 * @param {Object} data (optional) - overlay some values
10249 * @return {Roo.data.Record} record created.
10251 newRow : function(d) {
10253 this.recordType.prototype.fields.each(function(c) {
10255 case 'int' : da[c.name] = 0; break;
10256 case 'date' : da[c.name] = new Date(); break;
10257 case 'float' : da[c.name] = 0.0; break;
10258 case 'boolean' : da[c.name] = false; break;
10259 default : da[c.name] = ""; break;
10263 return new this.recordType(Roo.apply(da, d));
10268 * Ext JS Library 1.1.1
10269 * Copyright(c) 2006-2007, Ext JS, LLC.
10271 * Originally Released Under LGPL - original licence link has changed is not relivant.
10274 * <script type="text/javascript">
10278 * @class Roo.data.DataProxy
10279 * @extends Roo.data.Observable
10280 * This class is an abstract base class for implementations which provide retrieval of
10281 * unformatted data objects.<br>
10283 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10284 * (of the appropriate type which knows how to parse the data object) to provide a block of
10285 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10287 * Custom implementations must implement the load method as described in
10288 * {@link Roo.data.HttpProxy#load}.
10290 Roo.data.DataProxy = function(){
10293 * @event beforeload
10294 * Fires before a network request is made to retrieve a data object.
10295 * @param {Object} This DataProxy object.
10296 * @param {Object} params The params parameter to the load function.
10301 * Fires before the load method's callback is called.
10302 * @param {Object} This DataProxy object.
10303 * @param {Object} o The data object.
10304 * @param {Object} arg The callback argument object passed to the load function.
10308 * @event loadexception
10309 * Fires if an Exception occurs during data retrieval.
10310 * @param {Object} This DataProxy object.
10311 * @param {Object} o The data object.
10312 * @param {Object} arg The callback argument object passed to the load function.
10313 * @param {Object} e The Exception.
10315 loadexception : true
10317 Roo.data.DataProxy.superclass.constructor.call(this);
10320 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10323 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10327 * Ext JS Library 1.1.1
10328 * Copyright(c) 2006-2007, Ext JS, LLC.
10330 * Originally Released Under LGPL - original licence link has changed is not relivant.
10333 * <script type="text/javascript">
10336 * @class Roo.data.MemoryProxy
10337 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10338 * to the Reader when its load method is called.
10340 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10342 Roo.data.MemoryProxy = function(data){
10346 Roo.data.MemoryProxy.superclass.constructor.call(this);
10350 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10352 * Load data from the requested source (in this case an in-memory
10353 * data object passed to the constructor), read the data object into
10354 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10355 * process that block using the passed callback.
10356 * @param {Object} params This parameter is not used by the MemoryProxy class.
10357 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10358 * object into a block of Roo.data.Records.
10359 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10360 * The function must be passed <ul>
10361 * <li>The Record block object</li>
10362 * <li>The "arg" argument from the load function</li>
10363 * <li>A boolean success indicator</li>
10365 * @param {Object} scope The scope in which to call the callback
10366 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10368 load : function(params, reader, callback, scope, arg){
10369 params = params || {};
10372 result = reader.readRecords(this.data);
10374 this.fireEvent("loadexception", this, arg, null, e);
10375 callback.call(scope, null, arg, false);
10378 callback.call(scope, result, arg, true);
10382 update : function(params, records){
10387 * Ext JS Library 1.1.1
10388 * Copyright(c) 2006-2007, Ext JS, LLC.
10390 * Originally Released Under LGPL - original licence link has changed is not relivant.
10393 * <script type="text/javascript">
10396 * @class Roo.data.HttpProxy
10397 * @extends Roo.data.DataProxy
10398 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10399 * configured to reference a certain URL.<br><br>
10401 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10402 * from which the running page was served.<br><br>
10404 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10406 * Be aware that to enable the browser to parse an XML document, the server must set
10407 * the Content-Type header in the HTTP response to "text/xml".
10409 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10410 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10411 * will be used to make the request.
10413 Roo.data.HttpProxy = function(conn){
10414 Roo.data.HttpProxy.superclass.constructor.call(this);
10415 // is conn a conn config or a real conn?
10417 this.useAjax = !conn || !conn.events;
10421 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10422 // thse are take from connection...
10425 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10428 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10429 * extra parameters to each request made by this object. (defaults to undefined)
10432 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10433 * to each request made by this object. (defaults to undefined)
10436 * @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)
10439 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10442 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10448 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10452 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10453 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10454 * a finer-grained basis than the DataProxy events.
10456 getConnection : function(){
10457 return this.useAjax ? Roo.Ajax : this.conn;
10461 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10462 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10463 * process that block using the passed callback.
10464 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10465 * for the request to the remote server.
10466 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10467 * object into a block of Roo.data.Records.
10468 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10469 * The function must be passed <ul>
10470 * <li>The Record block object</li>
10471 * <li>The "arg" argument from the load function</li>
10472 * <li>A boolean success indicator</li>
10474 * @param {Object} scope The scope in which to call the callback
10475 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10477 load : function(params, reader, callback, scope, arg){
10478 if(this.fireEvent("beforeload", this, params) !== false){
10480 params : params || {},
10482 callback : callback,
10487 callback : this.loadResponse,
10491 Roo.applyIf(o, this.conn);
10492 if(this.activeRequest){
10493 Roo.Ajax.abort(this.activeRequest);
10495 this.activeRequest = Roo.Ajax.request(o);
10497 this.conn.request(o);
10500 callback.call(scope||this, null, arg, false);
10505 loadResponse : function(o, success, response){
10506 delete this.activeRequest;
10508 this.fireEvent("loadexception", this, o, response);
10509 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10514 result = o.reader.read(response);
10516 this.fireEvent("loadexception", this, o, response, e);
10517 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10521 this.fireEvent("load", this, o, o.request.arg);
10522 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10526 update : function(dataSet){
10531 updateResponse : function(dataSet){
10536 * Ext JS Library 1.1.1
10537 * Copyright(c) 2006-2007, Ext JS, LLC.
10539 * Originally Released Under LGPL - original licence link has changed is not relivant.
10542 * <script type="text/javascript">
10546 * @class Roo.data.ScriptTagProxy
10547 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10548 * other than the originating domain of the running page.<br><br>
10550 * <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
10551 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10553 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10554 * source code that is used as the source inside a <script> tag.<br><br>
10556 * In order for the browser to process the returned data, the server must wrap the data object
10557 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10558 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10559 * depending on whether the callback name was passed:
10562 boolean scriptTag = false;
10563 String cb = request.getParameter("callback");
10566 response.setContentType("text/javascript");
10568 response.setContentType("application/x-json");
10570 Writer out = response.getWriter();
10572 out.write(cb + "(");
10574 out.print(dataBlock.toJsonString());
10581 * @param {Object} config A configuration object.
10583 Roo.data.ScriptTagProxy = function(config){
10584 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10585 Roo.apply(this, config);
10586 this.head = document.getElementsByTagName("head")[0];
10589 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10591 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10593 * @cfg {String} url The URL from which to request the data object.
10596 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10600 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10601 * the server the name of the callback function set up by the load call to process the returned data object.
10602 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10603 * javascript output which calls this named function passing the data object as its only parameter.
10605 callbackParam : "callback",
10607 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10608 * name to the request.
10613 * Load data from the configured URL, read the data object into
10614 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10615 * process that block using the passed callback.
10616 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10617 * for the request to the remote server.
10618 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10619 * object into a block of Roo.data.Records.
10620 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10621 * The function must be passed <ul>
10622 * <li>The Record block object</li>
10623 * <li>The "arg" argument from the load function</li>
10624 * <li>A boolean success indicator</li>
10626 * @param {Object} scope The scope in which to call the callback
10627 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10629 load : function(params, reader, callback, scope, arg){
10630 if(this.fireEvent("beforeload", this, params) !== false){
10632 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10634 var url = this.url;
10635 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10637 url += "&_dc=" + (new Date().getTime());
10639 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10642 cb : "stcCallback"+transId,
10643 scriptId : "stcScript"+transId,
10647 callback : callback,
10653 window[trans.cb] = function(o){
10654 conn.handleResponse(o, trans);
10657 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10659 if(this.autoAbort !== false){
10663 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10665 var script = document.createElement("script");
10666 script.setAttribute("src", url);
10667 script.setAttribute("type", "text/javascript");
10668 script.setAttribute("id", trans.scriptId);
10669 this.head.appendChild(script);
10671 this.trans = trans;
10673 callback.call(scope||this, null, arg, false);
10678 isLoading : function(){
10679 return this.trans ? true : false;
10683 * Abort the current server request.
10685 abort : function(){
10686 if(this.isLoading()){
10687 this.destroyTrans(this.trans);
10692 destroyTrans : function(trans, isLoaded){
10693 this.head.removeChild(document.getElementById(trans.scriptId));
10694 clearTimeout(trans.timeoutId);
10696 window[trans.cb] = undefined;
10698 delete window[trans.cb];
10701 // if hasn't been loaded, wait for load to remove it to prevent script error
10702 window[trans.cb] = function(){
10703 window[trans.cb] = undefined;
10705 delete window[trans.cb];
10712 handleResponse : function(o, trans){
10713 this.trans = false;
10714 this.destroyTrans(trans, true);
10717 result = trans.reader.readRecords(o);
10719 this.fireEvent("loadexception", this, o, trans.arg, e);
10720 trans.callback.call(trans.scope||window, null, trans.arg, false);
10723 this.fireEvent("load", this, o, trans.arg);
10724 trans.callback.call(trans.scope||window, result, trans.arg, true);
10728 handleFailure : function(trans){
10729 this.trans = false;
10730 this.destroyTrans(trans, false);
10731 this.fireEvent("loadexception", this, null, trans.arg);
10732 trans.callback.call(trans.scope||window, null, trans.arg, false);
10736 * Ext JS Library 1.1.1
10737 * Copyright(c) 2006-2007, Ext JS, LLC.
10739 * Originally Released Under LGPL - original licence link has changed is not relivant.
10742 * <script type="text/javascript">
10746 * @class Roo.data.JsonReader
10747 * @extends Roo.data.DataReader
10748 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10749 * based on mappings in a provided Roo.data.Record constructor.
10751 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10752 * in the reply previously.
10757 var RecordDef = Roo.data.Record.create([
10758 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10759 {name: 'occupation'} // This field will use "occupation" as the mapping.
10761 var myReader = new Roo.data.JsonReader({
10762 totalProperty: "results", // The property which contains the total dataset size (optional)
10763 root: "rows", // The property which contains an Array of row objects
10764 id: "id" // The property within each row object that provides an ID for the record (optional)
10768 * This would consume a JSON file like this:
10770 { 'results': 2, 'rows': [
10771 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10772 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10775 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10776 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10777 * paged from the remote server.
10778 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10779 * @cfg {String} root name of the property which contains the Array of row objects.
10780 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10781 * @cfg {Array} fields Array of field definition objects
10783 * Create a new JsonReader
10784 * @param {Object} meta Metadata configuration options
10785 * @param {Object} recordType Either an Array of field definition objects,
10786 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10788 Roo.data.JsonReader = function(meta, recordType){
10791 // set some defaults:
10792 Roo.applyIf(meta, {
10793 totalProperty: 'total',
10794 successProperty : 'success',
10799 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10801 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10804 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10805 * Used by Store query builder to append _requestMeta to params.
10808 metaFromRemote : false,
10810 * This method is only used by a DataProxy which has retrieved data from a remote server.
10811 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10812 * @return {Object} data A data block which is used by an Roo.data.Store object as
10813 * a cache of Roo.data.Records.
10815 read : function(response){
10816 var json = response.responseText;
10818 var o = /* eval:var:o */ eval("("+json+")");
10820 throw {message: "JsonReader.read: Json object not found"};
10826 this.metaFromRemote = true;
10827 this.meta = o.metaData;
10828 this.recordType = Roo.data.Record.create(o.metaData.fields);
10829 this.onMetaChange(this.meta, this.recordType, o);
10831 return this.readRecords(o);
10834 // private function a store will implement
10835 onMetaChange : function(meta, recordType, o){
10842 simpleAccess: function(obj, subsc) {
10849 getJsonAccessor: function(){
10851 return function(expr) {
10853 return(re.test(expr))
10854 ? new Function("obj", "return obj." + expr)
10859 return Roo.emptyFn;
10864 * Create a data block containing Roo.data.Records from an XML document.
10865 * @param {Object} o An object which contains an Array of row objects in the property specified
10866 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10867 * which contains the total size of the dataset.
10868 * @return {Object} data A data block which is used by an Roo.data.Store object as
10869 * a cache of Roo.data.Records.
10871 readRecords : function(o){
10873 * After any data loads, the raw JSON data is available for further custom processing.
10877 var s = this.meta, Record = this.recordType,
10878 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10880 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10882 if(s.totalProperty) {
10883 this.getTotal = this.getJsonAccessor(s.totalProperty);
10885 if(s.successProperty) {
10886 this.getSuccess = this.getJsonAccessor(s.successProperty);
10888 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10890 var g = this.getJsonAccessor(s.id);
10891 this.getId = function(rec) {
10893 return (r === undefined || r === "") ? null : r;
10896 this.getId = function(){return null;};
10899 for(var jj = 0; jj < fl; jj++){
10901 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10902 this.ef[jj] = this.getJsonAccessor(map);
10906 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10907 if(s.totalProperty){
10908 var vt = parseInt(this.getTotal(o), 10);
10913 if(s.successProperty){
10914 var vs = this.getSuccess(o);
10915 if(vs === false || vs === 'false'){
10920 for(var i = 0; i < c; i++){
10923 var id = this.getId(n);
10924 for(var j = 0; j < fl; j++){
10926 var v = this.ef[j](n);
10928 Roo.log('missing convert for ' + f.name);
10932 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10934 var record = new Record(values, id);
10936 records[i] = record;
10942 totalRecords : totalRecords
10947 * Ext JS Library 1.1.1
10948 * Copyright(c) 2006-2007, Ext JS, LLC.
10950 * Originally Released Under LGPL - original licence link has changed is not relivant.
10953 * <script type="text/javascript">
10957 * @class Roo.data.ArrayReader
10958 * @extends Roo.data.DataReader
10959 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10960 * Each element of that Array represents a row of data fields. The
10961 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10962 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10966 var RecordDef = Roo.data.Record.create([
10967 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10968 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10970 var myReader = new Roo.data.ArrayReader({
10971 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10975 * This would consume an Array like this:
10977 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10979 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10981 * Create a new JsonReader
10982 * @param {Object} meta Metadata configuration options.
10983 * @param {Object} recordType Either an Array of field definition objects
10984 * as specified to {@link Roo.data.Record#create},
10985 * or an {@link Roo.data.Record} object
10986 * created using {@link Roo.data.Record#create}.
10988 Roo.data.ArrayReader = function(meta, recordType){
10989 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10992 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10994 * Create a data block containing Roo.data.Records from an XML document.
10995 * @param {Object} o An Array of row objects which represents the dataset.
10996 * @return {Object} data A data block which is used by an Roo.data.Store object as
10997 * a cache of Roo.data.Records.
10999 readRecords : function(o){
11000 var sid = this.meta ? this.meta.id : null;
11001 var recordType = this.recordType, fields = recordType.prototype.fields;
11004 for(var i = 0; i < root.length; i++){
11007 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11008 for(var j = 0, jlen = fields.length; j < jlen; j++){
11009 var f = fields.items[j];
11010 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11011 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11013 values[f.name] = v;
11015 var record = new recordType(values, id);
11017 records[records.length] = record;
11021 totalRecords : records.length
11030 * @class Roo.bootstrap.ComboBox
11031 * @extends Roo.bootstrap.TriggerField
11032 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11033 * @cfg {Boolean} append (true|false) default false
11034 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11035 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11036 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11037 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11038 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11040 * Create a new ComboBox.
11041 * @param {Object} config Configuration options
11043 Roo.bootstrap.ComboBox = function(config){
11044 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11048 * Fires when the dropdown list is expanded
11049 * @param {Roo.bootstrap.ComboBox} combo This combo box
11054 * Fires when the dropdown list is collapsed
11055 * @param {Roo.bootstrap.ComboBox} combo This combo box
11059 * @event beforeselect
11060 * Fires before a list item is selected. Return false to cancel the selection.
11061 * @param {Roo.bootstrap.ComboBox} combo This combo box
11062 * @param {Roo.data.Record} record The data record returned from the underlying store
11063 * @param {Number} index The index of the selected item in the dropdown list
11065 'beforeselect' : true,
11068 * Fires when a list item is selected
11069 * @param {Roo.bootstrap.ComboBox} combo This combo box
11070 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11071 * @param {Number} index The index of the selected item in the dropdown list
11075 * @event beforequery
11076 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11077 * The event object passed has these properties:
11078 * @param {Roo.bootstrap.ComboBox} combo This combo box
11079 * @param {String} query The query
11080 * @param {Boolean} forceAll true to force "all" query
11081 * @param {Boolean} cancel true to cancel the query
11082 * @param {Object} e The query event object
11084 'beforequery': true,
11087 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11088 * @param {Roo.bootstrap.ComboBox} combo This combo box
11093 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11094 * @param {Roo.bootstrap.ComboBox} combo This combo box
11095 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11100 * Fires when the remove value from the combobox array
11101 * @param {Roo.bootstrap.ComboBox} combo This combo box
11105 * @event specialfilter
11106 * Fires when specialfilter
11107 * @param {Roo.bootstrap.ComboBox} combo This combo box
11109 'specialfilter' : true
11114 this.tickItems = [];
11116 this.selectedIndex = -1;
11117 if(this.mode == 'local'){
11118 if(config.queryDelay === undefined){
11119 this.queryDelay = 10;
11121 if(config.minChars === undefined){
11127 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11130 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11131 * rendering into an Roo.Editor, defaults to false)
11134 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11135 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11138 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11141 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11142 * the dropdown list (defaults to undefined, with no header element)
11146 * @cfg {String/Roo.Template} tpl The template to use to render the output
11150 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11152 listWidth: undefined,
11154 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11155 * mode = 'remote' or 'text' if mode = 'local')
11157 displayField: undefined,
11160 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11161 * mode = 'remote' or 'value' if mode = 'local').
11162 * Note: use of a valueField requires the user make a selection
11163 * in order for a value to be mapped.
11165 valueField: undefined,
11169 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11170 * field's data value (defaults to the underlying DOM element's name)
11172 hiddenName: undefined,
11174 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11178 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11180 selectedClass: 'active',
11183 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11187 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11188 * anchor positions (defaults to 'tl-bl')
11190 listAlign: 'tl-bl?',
11192 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11196 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11197 * query specified by the allQuery config option (defaults to 'query')
11199 triggerAction: 'query',
11201 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11202 * (defaults to 4, does not apply if editable = false)
11206 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11207 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11211 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11212 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11216 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11217 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11221 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11222 * when editable = true (defaults to false)
11224 selectOnFocus:false,
11226 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11228 queryParam: 'query',
11230 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11231 * when mode = 'remote' (defaults to 'Loading...')
11233 loadingText: 'Loading...',
11235 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11239 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11243 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11244 * traditional select (defaults to true)
11248 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11252 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11256 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11257 * listWidth has a higher value)
11261 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11262 * allow the user to set arbitrary text into the field (defaults to false)
11264 forceSelection:false,
11266 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11267 * if typeAhead = true (defaults to 250)
11269 typeAheadDelay : 250,
11271 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11272 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11274 valueNotFoundText : undefined,
11276 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11278 blockFocus : false,
11281 * @cfg {Boolean} disableClear Disable showing of clear button.
11283 disableClear : false,
11285 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11287 alwaysQuery : false,
11290 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11295 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11297 invalidClass : "has-warning",
11300 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11302 validClass : "has-success",
11305 * @cfg {Boolean} specialFilter (true|false) special filter default false
11307 specialFilter : false,
11319 btnPosition : 'right',
11320 triggerList : true,
11321 showToggleBtn : true,
11322 // element that contains real text value.. (when hidden is used..)
11324 getAutoCreate : function()
11331 if(!this.tickable){
11332 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11337 * ComboBox with tickable selections
11340 var align = this.labelAlign || this.parentLabelAlign();
11343 cls : 'form-group roo-combobox-tickable' //input-group
11348 cls : 'tickable-buttons',
11353 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11360 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11367 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11374 buttons.cn.unshift({
11376 cls: 'select2-search-field-input'
11382 Roo.each(buttons.cn, function(c){
11384 c.cls += ' btn-' + _this.size;
11387 if (_this.disabled) {
11398 cls: 'form-hidden-field'
11402 cls: 'select2-choices',
11406 cls: 'select2-search-field',
11418 cls: 'select2-container input-group select2-container-multi',
11423 // cls: 'typeahead typeahead-long dropdown-menu',
11424 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11429 if(this.hasFeedback && !this.allowBlank){
11433 cls: 'glyphicon form-control-feedback'
11436 combobox.cn.push(feedback);
11439 if (align ==='left' && this.fieldLabel.length) {
11441 Roo.log("left and has label");
11447 cls : 'control-label col-sm-' + this.labelWidth,
11448 html : this.fieldLabel
11452 cls : "col-sm-" + (12 - this.labelWidth),
11459 } else if ( this.fieldLabel.length) {
11465 //cls : 'input-group-addon',
11466 html : this.fieldLabel
11476 Roo.log(" no label && no align");
11483 ['xs','sm','md','lg'].map(function(size){
11484 if (settings[size]) {
11485 cfg.cls += ' col-' + size + '-' + settings[size];
11494 initEvents: function()
11498 throw "can not find store for combo";
11500 this.store = Roo.factory(this.store, Roo.data);
11503 this.initTickableEvents();
11507 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11509 if(this.hiddenName){
11511 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11513 this.hiddenField.dom.value =
11514 this.hiddenValue !== undefined ? this.hiddenValue :
11515 this.value !== undefined ? this.value : '';
11517 // prevent input submission
11518 this.el.dom.removeAttribute('name');
11519 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11524 // this.el.dom.setAttribute('autocomplete', 'off');
11527 var cls = 'x-combo-list';
11529 //this.list = new Roo.Layer({
11530 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11536 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11537 _this.list.setWidth(lw);
11540 this.list.on('mouseover', this.onViewOver, this);
11541 this.list.on('mousemove', this.onViewMove, this);
11543 this.list.on('scroll', this.onViewScroll, this);
11546 this.list.swallowEvent('mousewheel');
11547 this.assetHeight = 0;
11550 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11551 this.assetHeight += this.header.getHeight();
11554 this.innerList = this.list.createChild({cls:cls+'-inner'});
11555 this.innerList.on('mouseover', this.onViewOver, this);
11556 this.innerList.on('mousemove', this.onViewMove, this);
11557 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11559 if(this.allowBlank && !this.pageSize && !this.disableClear){
11560 this.footer = this.list.createChild({cls:cls+'-ft'});
11561 this.pageTb = new Roo.Toolbar(this.footer);
11565 this.footer = this.list.createChild({cls:cls+'-ft'});
11566 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11567 {pageSize: this.pageSize});
11571 if (this.pageTb && this.allowBlank && !this.disableClear) {
11573 this.pageTb.add(new Roo.Toolbar.Fill(), {
11574 cls: 'x-btn-icon x-btn-clear',
11576 handler: function()
11579 _this.clearValue();
11580 _this.onSelect(false, -1);
11585 this.assetHeight += this.footer.getHeight();
11590 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11593 this.view = new Roo.View(this.list, this.tpl, {
11594 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11596 //this.view.wrapEl.setDisplayed(false);
11597 this.view.on('click', this.onViewClick, this);
11601 this.store.on('beforeload', this.onBeforeLoad, this);
11602 this.store.on('load', this.onLoad, this);
11603 this.store.on('loadexception', this.onLoadException, this);
11605 if(this.resizable){
11606 this.resizer = new Roo.Resizable(this.list, {
11607 pinned:true, handles:'se'
11609 this.resizer.on('resize', function(r, w, h){
11610 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11611 this.listWidth = w;
11612 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11613 this.restrictHeight();
11615 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11618 if(!this.editable){
11619 this.editable = true;
11620 this.setEditable(false);
11625 if (typeof(this.events.add.listeners) != 'undefined') {
11627 this.addicon = this.wrap.createChild(
11628 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11630 this.addicon.on('click', function(e) {
11631 this.fireEvent('add', this);
11634 if (typeof(this.events.edit.listeners) != 'undefined') {
11636 this.editicon = this.wrap.createChild(
11637 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11638 if (this.addicon) {
11639 this.editicon.setStyle('margin-left', '40px');
11641 this.editicon.on('click', function(e) {
11643 // we fire even if inothing is selected..
11644 this.fireEvent('edit', this, this.lastData );
11650 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11651 "up" : function(e){
11652 this.inKeyMode = true;
11656 "down" : function(e){
11657 if(!this.isExpanded()){
11658 this.onTriggerClick();
11660 this.inKeyMode = true;
11665 "enter" : function(e){
11666 // this.onViewClick();
11670 if(this.fireEvent("specialkey", this, e)){
11671 this.onViewClick(false);
11677 "esc" : function(e){
11681 "tab" : function(e){
11684 if(this.fireEvent("specialkey", this, e)){
11685 this.onViewClick(false);
11693 doRelay : function(foo, bar, hname){
11694 if(hname == 'down' || this.scope.isExpanded()){
11695 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11704 this.queryDelay = Math.max(this.queryDelay || 10,
11705 this.mode == 'local' ? 10 : 250);
11708 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11710 if(this.typeAhead){
11711 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11713 if(this.editable !== false){
11714 this.inputEl().on("keyup", this.onKeyUp, this);
11716 if(this.forceSelection){
11717 this.inputEl().on('blur', this.doForce, this);
11721 this.choices = this.el.select('ul.select2-choices', true).first();
11722 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11726 initTickableEvents: function()
11730 if(this.hiddenName){
11732 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11734 this.hiddenField.dom.value =
11735 this.hiddenValue !== undefined ? this.hiddenValue :
11736 this.value !== undefined ? this.value : '';
11738 // prevent input submission
11739 this.el.dom.removeAttribute('name');
11740 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11745 // this.list = this.el.select('ul.dropdown-menu',true).first();
11747 this.choices = this.el.select('ul.select2-choices', true).first();
11748 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11749 if(this.triggerList){
11750 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11753 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11754 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11756 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11757 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11759 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11760 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11762 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11763 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11764 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11767 this.cancelBtn.hide();
11772 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11773 _this.list.setWidth(lw);
11776 this.list.on('mouseover', this.onViewOver, this);
11777 this.list.on('mousemove', this.onViewMove, this);
11779 this.list.on('scroll', this.onViewScroll, this);
11782 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>';
11785 this.view = new Roo.View(this.list, this.tpl, {
11786 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11789 //this.view.wrapEl.setDisplayed(false);
11790 this.view.on('click', this.onViewClick, this);
11794 this.store.on('beforeload', this.onBeforeLoad, this);
11795 this.store.on('load', this.onLoad, this);
11796 this.store.on('loadexception', this.onLoadException, this);
11799 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11800 "up" : function(e){
11801 this.inKeyMode = true;
11805 "down" : function(e){
11806 this.inKeyMode = true;
11810 "enter" : function(e){
11811 if(this.fireEvent("specialkey", this, e)){
11812 this.onViewClick(false);
11818 "esc" : function(e){
11819 this.onTickableFooterButtonClick(e, false, false);
11822 "tab" : function(e){
11823 this.fireEvent("specialkey", this, e);
11825 this.onTickableFooterButtonClick(e, false, false);
11832 doRelay : function(e, fn, key){
11833 if(this.scope.isExpanded()){
11834 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11843 this.queryDelay = Math.max(this.queryDelay || 10,
11844 this.mode == 'local' ? 10 : 250);
11847 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11849 if(this.typeAhead){
11850 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11853 if(this.editable !== false){
11854 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11859 onDestroy : function(){
11861 this.view.setStore(null);
11862 this.view.el.removeAllListeners();
11863 this.view.el.remove();
11864 this.view.purgeListeners();
11867 this.list.dom.innerHTML = '';
11871 this.store.un('beforeload', this.onBeforeLoad, this);
11872 this.store.un('load', this.onLoad, this);
11873 this.store.un('loadexception', this.onLoadException, this);
11875 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11879 fireKey : function(e){
11880 if(e.isNavKeyPress() && !this.list.isVisible()){
11881 this.fireEvent("specialkey", this, e);
11886 onResize: function(w, h){
11887 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11889 // if(typeof w != 'number'){
11890 // // we do not handle it!?!?
11893 // var tw = this.trigger.getWidth();
11894 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11895 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11897 // this.inputEl().setWidth( this.adjustWidth('input', x));
11899 // //this.trigger.setStyle('left', x+'px');
11901 // if(this.list && this.listWidth === undefined){
11902 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11903 // this.list.setWidth(lw);
11904 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11912 * Allow or prevent the user from directly editing the field text. If false is passed,
11913 * the user will only be able to select from the items defined in the dropdown list. This method
11914 * is the runtime equivalent of setting the 'editable' config option at config time.
11915 * @param {Boolean} value True to allow the user to directly edit the field text
11917 setEditable : function(value){
11918 if(value == this.editable){
11921 this.editable = value;
11923 this.inputEl().dom.setAttribute('readOnly', true);
11924 this.inputEl().on('mousedown', this.onTriggerClick, this);
11925 this.inputEl().addClass('x-combo-noedit');
11927 this.inputEl().dom.setAttribute('readOnly', false);
11928 this.inputEl().un('mousedown', this.onTriggerClick, this);
11929 this.inputEl().removeClass('x-combo-noedit');
11935 onBeforeLoad : function(combo,opts){
11936 if(!this.hasFocus){
11940 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11942 this.restrictHeight();
11943 this.selectedIndex = -1;
11947 onLoad : function(){
11949 this.hasQuery = false;
11951 if(!this.hasFocus){
11955 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11956 this.loading.hide();
11959 if(this.store.getCount() > 0){
11961 this.restrictHeight();
11962 if(this.lastQuery == this.allQuery){
11963 if(this.editable && !this.tickable){
11964 this.inputEl().dom.select();
11968 !this.selectByValue(this.value, true) &&
11971 !this.store.lastOptions ||
11972 typeof(this.store.lastOptions.add) == 'undefined' ||
11973 this.store.lastOptions.add != true
11976 this.select(0, true);
11979 if(this.autoFocus){
11982 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11983 this.taTask.delay(this.typeAheadDelay);
11987 this.onEmptyResults();
11993 onLoadException : function()
11995 this.hasQuery = false;
11997 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11998 this.loading.hide();
12001 if(this.tickable && this.editable){
12007 Roo.log(this.store.reader.jsonData);
12008 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12010 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12016 onTypeAhead : function(){
12017 if(this.store.getCount() > 0){
12018 var r = this.store.getAt(0);
12019 var newValue = r.data[this.displayField];
12020 var len = newValue.length;
12021 var selStart = this.getRawValue().length;
12023 if(selStart != len){
12024 this.setRawValue(newValue);
12025 this.selectText(selStart, newValue.length);
12031 onSelect : function(record, index){
12033 if(this.fireEvent('beforeselect', this, record, index) !== false){
12035 this.setFromData(index > -1 ? record.data : false);
12038 this.fireEvent('select', this, record, index);
12043 * Returns the currently selected field value or empty string if no value is set.
12044 * @return {String} value The selected value
12046 getValue : function(){
12049 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12052 if(this.valueField){
12053 return typeof this.value != 'undefined' ? this.value : '';
12055 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12060 * Clears any text/value currently set in the field
12062 clearValue : function(){
12063 if(this.hiddenField){
12064 this.hiddenField.dom.value = '';
12067 this.setRawValue('');
12068 this.lastSelectionText = '';
12069 this.lastData = false;
12071 var close = this.closeTriggerEl();
12080 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12081 * will be displayed in the field. If the value does not match the data value of an existing item,
12082 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12083 * Otherwise the field will be blank (although the value will still be set).
12084 * @param {String} value The value to match
12086 setValue : function(v){
12093 if(this.valueField){
12094 var r = this.findRecord(this.valueField, v);
12096 text = r.data[this.displayField];
12097 }else if(this.valueNotFoundText !== undefined){
12098 text = this.valueNotFoundText;
12101 this.lastSelectionText = text;
12102 if(this.hiddenField){
12103 this.hiddenField.dom.value = v;
12105 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12108 var close = this.closeTriggerEl();
12111 (v.length || v * 1 > 0) ? close.show() : close.hide();
12115 * @property {Object} the last set data for the element
12120 * Sets the value of the field based on a object which is related to the record format for the store.
12121 * @param {Object} value the value to set as. or false on reset?
12123 setFromData : function(o){
12130 var dv = ''; // display value
12131 var vv = ''; // value value..
12133 if (this.displayField) {
12134 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12136 // this is an error condition!!!
12137 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12140 if(this.valueField){
12141 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12144 var close = this.closeTriggerEl();
12147 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12150 if(this.hiddenField){
12151 this.hiddenField.dom.value = vv;
12153 this.lastSelectionText = dv;
12154 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12158 // no hidden field.. - we store the value in 'value', but still display
12159 // display field!!!!
12160 this.lastSelectionText = dv;
12161 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12168 reset : function(){
12169 // overridden so that last data is reset..
12176 this.setValue(this.originalValue);
12177 this.clearInvalid();
12178 this.lastData = false;
12180 this.view.clearSelections();
12184 findRecord : function(prop, value){
12186 if(this.store.getCount() > 0){
12187 this.store.each(function(r){
12188 if(r.data[prop] == value){
12198 getName: function()
12200 // returns hidden if it's set..
12201 if (!this.rendered) {return ''};
12202 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12206 onViewMove : function(e, t){
12207 this.inKeyMode = false;
12211 onViewOver : function(e, t){
12212 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12215 var item = this.view.findItemFromChild(t);
12218 var index = this.view.indexOf(item);
12219 this.select(index, false);
12224 onViewClick : function(view, doFocus, el, e)
12226 var index = this.view.getSelectedIndexes()[0];
12228 var r = this.store.getAt(index);
12232 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12239 Roo.each(this.tickItems, function(v,k){
12241 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12242 _this.tickItems.splice(k, 1);
12244 if(typeof(e) == 'undefined' && view == false){
12245 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12257 this.tickItems.push(r.data);
12259 if(typeof(e) == 'undefined' && view == false){
12260 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12267 this.onSelect(r, index);
12269 if(doFocus !== false && !this.blockFocus){
12270 this.inputEl().focus();
12275 restrictHeight : function(){
12276 //this.innerList.dom.style.height = '';
12277 //var inner = this.innerList.dom;
12278 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12279 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12280 //this.list.beginUpdate();
12281 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12282 this.list.alignTo(this.inputEl(), this.listAlign);
12283 this.list.alignTo(this.inputEl(), this.listAlign);
12284 //this.list.endUpdate();
12288 onEmptyResults : function(){
12290 if(this.tickable && this.editable){
12291 this.restrictHeight();
12299 * Returns true if the dropdown list is expanded, else false.
12301 isExpanded : function(){
12302 return this.list.isVisible();
12306 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12307 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12308 * @param {String} value The data value of the item to select
12309 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12310 * selected item if it is not currently in view (defaults to true)
12311 * @return {Boolean} True if the value matched an item in the list, else false
12313 selectByValue : function(v, scrollIntoView){
12314 if(v !== undefined && v !== null){
12315 var r = this.findRecord(this.valueField || this.displayField, v);
12317 this.select(this.store.indexOf(r), scrollIntoView);
12325 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12326 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12327 * @param {Number} index The zero-based index of the list item to select
12328 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12329 * selected item if it is not currently in view (defaults to true)
12331 select : function(index, scrollIntoView){
12332 this.selectedIndex = index;
12333 this.view.select(index);
12334 if(scrollIntoView !== false){
12335 var el = this.view.getNode(index);
12337 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12340 this.list.scrollChildIntoView(el, false);
12346 selectNext : function(){
12347 var ct = this.store.getCount();
12349 if(this.selectedIndex == -1){
12351 }else if(this.selectedIndex < ct-1){
12352 this.select(this.selectedIndex+1);
12358 selectPrev : function(){
12359 var ct = this.store.getCount();
12361 if(this.selectedIndex == -1){
12363 }else if(this.selectedIndex != 0){
12364 this.select(this.selectedIndex-1);
12370 onKeyUp : function(e){
12371 if(this.editable !== false && !e.isSpecialKey()){
12372 this.lastKey = e.getKey();
12373 this.dqTask.delay(this.queryDelay);
12378 validateBlur : function(){
12379 return !this.list || !this.list.isVisible();
12383 initQuery : function(){
12385 var v = this.getRawValue();
12387 if(this.tickable && this.editable){
12388 v = this.tickableInputEl().getValue();
12395 doForce : function(){
12396 if(this.inputEl().dom.value.length > 0){
12397 this.inputEl().dom.value =
12398 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12404 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12405 * query allowing the query action to be canceled if needed.
12406 * @param {String} query The SQL query to execute
12407 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12408 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12409 * saved in the current store (defaults to false)
12411 doQuery : function(q, forceAll){
12413 if(q === undefined || q === null){
12418 forceAll: forceAll,
12422 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12427 forceAll = qe.forceAll;
12428 if(forceAll === true || (q.length >= this.minChars)){
12430 this.hasQuery = true;
12432 if(this.lastQuery != q || this.alwaysQuery){
12433 this.lastQuery = q;
12434 if(this.mode == 'local'){
12435 this.selectedIndex = -1;
12437 this.store.clearFilter();
12440 if(this.specialFilter){
12441 this.fireEvent('specialfilter', this);
12446 this.store.filter(this.displayField, q);
12449 this.store.fireEvent("datachanged", this.store);
12456 this.store.baseParams[this.queryParam] = q;
12458 var options = {params : this.getParams(q)};
12461 options.add = true;
12462 options.params.start = this.page * this.pageSize;
12465 this.store.load(options);
12468 * this code will make the page width larger, at the beginning, the list not align correctly,
12469 * we should expand the list on onLoad
12470 * so command out it
12475 this.selectedIndex = -1;
12480 this.loadNext = false;
12484 getParams : function(q){
12486 //p[this.queryParam] = q;
12490 p.limit = this.pageSize;
12496 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12498 collapse : function(){
12499 if(!this.isExpanded()){
12506 this.hasFocus = false;
12508 this.cancelBtn.hide();
12509 this.trigger.show();
12512 this.tickableInputEl().dom.value = '';
12513 this.tickableInputEl().blur();
12518 Roo.get(document).un('mousedown', this.collapseIf, this);
12519 Roo.get(document).un('mousewheel', this.collapseIf, this);
12520 if (!this.editable) {
12521 Roo.get(document).un('keydown', this.listKeyPress, this);
12523 this.fireEvent('collapse', this);
12527 collapseIf : function(e){
12528 var in_combo = e.within(this.el);
12529 var in_list = e.within(this.list);
12530 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12532 if (in_combo || in_list || is_list) {
12533 //e.stopPropagation();
12538 this.onTickableFooterButtonClick(e, false, false);
12546 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12548 expand : function(){
12550 if(this.isExpanded() || !this.hasFocus){
12554 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12555 this.list.setWidth(lw);
12562 this.restrictHeight();
12566 this.tickItems = Roo.apply([], this.item);
12569 this.cancelBtn.show();
12570 this.trigger.hide();
12573 this.tickableInputEl().focus();
12578 Roo.get(document).on('mousedown', this.collapseIf, this);
12579 Roo.get(document).on('mousewheel', this.collapseIf, this);
12580 if (!this.editable) {
12581 Roo.get(document).on('keydown', this.listKeyPress, this);
12584 this.fireEvent('expand', this);
12588 // Implements the default empty TriggerField.onTriggerClick function
12589 onTriggerClick : function(e)
12591 Roo.log('trigger click');
12593 if(this.disabled || !this.triggerList){
12598 this.loadNext = false;
12600 if(this.isExpanded()){
12602 if (!this.blockFocus) {
12603 this.inputEl().focus();
12607 this.hasFocus = true;
12608 if(this.triggerAction == 'all') {
12609 this.doQuery(this.allQuery, true);
12611 this.doQuery(this.getRawValue());
12613 if (!this.blockFocus) {
12614 this.inputEl().focus();
12619 onTickableTriggerClick : function(e)
12626 this.loadNext = false;
12627 this.hasFocus = true;
12629 if(this.triggerAction == 'all') {
12630 this.doQuery(this.allQuery, true);
12632 this.doQuery(this.getRawValue());
12636 onSearchFieldClick : function(e)
12638 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12639 this.onTickableFooterButtonClick(e, false, false);
12643 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12648 this.loadNext = false;
12649 this.hasFocus = true;
12651 if(this.triggerAction == 'all') {
12652 this.doQuery(this.allQuery, true);
12654 this.doQuery(this.getRawValue());
12658 listKeyPress : function(e)
12660 //Roo.log('listkeypress');
12661 // scroll to first matching element based on key pres..
12662 if (e.isSpecialKey()) {
12665 var k = String.fromCharCode(e.getKey()).toUpperCase();
12668 var csel = this.view.getSelectedNodes();
12669 var cselitem = false;
12671 var ix = this.view.indexOf(csel[0]);
12672 cselitem = this.store.getAt(ix);
12673 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12679 this.store.each(function(v) {
12681 // start at existing selection.
12682 if (cselitem.id == v.id) {
12688 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12689 match = this.store.indexOf(v);
12695 if (match === false) {
12696 return true; // no more action?
12699 this.view.select(match);
12700 var sn = Roo.get(this.view.getSelectedNodes()[0])
12701 sn.scrollIntoView(sn.dom.parentNode, false);
12704 onViewScroll : function(e, t){
12706 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){
12710 this.hasQuery = true;
12712 this.loading = this.list.select('.loading', true).first();
12714 if(this.loading === null){
12715 this.list.createChild({
12717 cls: 'loading select2-more-results select2-active',
12718 html: 'Loading more results...'
12721 this.loading = this.list.select('.loading', true).first();
12723 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12725 this.loading.hide();
12728 this.loading.show();
12733 this.loadNext = true;
12735 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12740 addItem : function(o)
12742 var dv = ''; // display value
12744 if (this.displayField) {
12745 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12747 // this is an error condition!!!
12748 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12755 var choice = this.choices.createChild({
12757 cls: 'select2-search-choice',
12766 cls: 'select2-search-choice-close',
12771 }, this.searchField);
12773 var close = choice.select('a.select2-search-choice-close', true).first()
12775 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12783 this.inputEl().dom.value = '';
12788 onRemoveItem : function(e, _self, o)
12790 e.preventDefault();
12792 this.lastItem = Roo.apply([], this.item);
12794 var index = this.item.indexOf(o.data) * 1;
12797 Roo.log('not this item?!');
12801 this.item.splice(index, 1);
12806 this.fireEvent('remove', this, e);
12812 syncValue : function()
12814 if(!this.item.length){
12821 Roo.each(this.item, function(i){
12822 if(_this.valueField){
12823 value.push(i[_this.valueField]);
12830 this.value = value.join(',');
12832 if(this.hiddenField){
12833 this.hiddenField.dom.value = this.value;
12836 this.store.fireEvent("datachanged", this.store);
12839 clearItem : function()
12841 if(!this.multiple){
12847 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12856 inputEl: function ()
12859 return this.searchField;
12861 return this.el.select('input.form-control',true).first();
12865 onTickableFooterButtonClick : function(e, btn, el)
12867 e.preventDefault();
12869 this.lastItem = Roo.apply([], this.item);
12871 if(btn && btn.name == 'cancel'){
12872 this.tickItems = Roo.apply([], this.item);
12881 Roo.each(this.tickItems, function(o){
12889 validate : function()
12891 var v = this.getRawValue();
12894 v = this.getValue();
12897 if(this.disabled || this.allowBlank || v.length){
12902 this.markInvalid();
12906 tickableInputEl : function()
12908 if(!this.tickable || !this.editable){
12909 return this.inputEl();
12912 return this.inputEl().select('.select2-search-field-input', true).first();
12918 * @cfg {Boolean} grow
12922 * @cfg {Number} growMin
12926 * @cfg {Number} growMax
12936 * Ext JS Library 1.1.1
12937 * Copyright(c) 2006-2007, Ext JS, LLC.
12939 * Originally Released Under LGPL - original licence link has changed is not relivant.
12942 * <script type="text/javascript">
12947 * @extends Roo.util.Observable
12948 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12949 * This class also supports single and multi selection modes. <br>
12950 * Create a data model bound view:
12952 var store = new Roo.data.Store(...);
12954 var view = new Roo.View({
12956 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12958 singleSelect: true,
12959 selectedClass: "ydataview-selected",
12963 // listen for node click?
12964 view.on("click", function(vw, index, node, e){
12965 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12969 dataModel.load("foobar.xml");
12971 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12973 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12974 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12976 * Note: old style constructor is still suported (container, template, config)
12979 * Create a new View
12980 * @param {Object} config The config object
12983 Roo.View = function(config, depreciated_tpl, depreciated_config){
12985 this.parent = false;
12987 if (typeof(depreciated_tpl) == 'undefined') {
12988 // new way.. - universal constructor.
12989 Roo.apply(this, config);
12990 this.el = Roo.get(this.el);
12993 this.el = Roo.get(config);
12994 this.tpl = depreciated_tpl;
12995 Roo.apply(this, depreciated_config);
12997 this.wrapEl = this.el.wrap().wrap();
12998 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
13001 if(typeof(this.tpl) == "string"){
13002 this.tpl = new Roo.Template(this.tpl);
13004 // support xtype ctors..
13005 this.tpl = new Roo.factory(this.tpl, Roo);
13009 this.tpl.compile();
13014 * @event beforeclick
13015 * Fires before a click is processed. Returns false to cancel the default action.
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
13021 "beforeclick" : true,
13024 * Fires when a template node is 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
13033 * Fires when a template node is double 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
13041 * @event contextmenu
13042 * Fires when a template node is right clicked.
13043 * @param {Roo.View} this
13044 * @param {Number} index The index of the target node
13045 * @param {HTMLElement} node The target node
13046 * @param {Roo.EventObject} e The raw event object
13048 "contextmenu" : true,
13050 * @event selectionchange
13051 * Fires when the selected nodes change.
13052 * @param {Roo.View} this
13053 * @param {Array} selections Array of the selected nodes
13055 "selectionchange" : true,
13058 * @event beforeselect
13059 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13060 * @param {Roo.View} this
13061 * @param {HTMLElement} node The node to be selected
13062 * @param {Array} selections Array of currently selected nodes
13064 "beforeselect" : true,
13066 * @event preparedata
13067 * Fires on every row to render, to allow you to change the data.
13068 * @param {Roo.View} this
13069 * @param {Object} data to be rendered (change this)
13071 "preparedata" : true
13079 "click": this.onClick,
13080 "dblclick": this.onDblClick,
13081 "contextmenu": this.onContextMenu,
13085 this.selections = [];
13087 this.cmp = new Roo.CompositeElementLite([]);
13089 this.store = Roo.factory(this.store, Roo.data);
13090 this.setStore(this.store, true);
13093 if ( this.footer && this.footer.xtype) {
13095 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13097 this.footer.dataSource = this.store
13098 this.footer.container = fctr;
13099 this.footer = Roo.factory(this.footer, Roo);
13100 fctr.insertFirst(this.el);
13102 // this is a bit insane - as the paging toolbar seems to detach the el..
13103 // dom.parentNode.parentNode.parentNode
13104 // they get detached?
13108 Roo.View.superclass.constructor.call(this);
13113 Roo.extend(Roo.View, Roo.util.Observable, {
13116 * @cfg {Roo.data.Store} store Data store to load data from.
13121 * @cfg {String|Roo.Element} el The container element.
13126 * @cfg {String|Roo.Template} tpl The template used by this View
13130 * @cfg {String} dataName the named area of the template to use as the data area
13131 * Works with domtemplates roo-name="name"
13135 * @cfg {String} selectedClass The css class to add to selected nodes
13137 selectedClass : "x-view-selected",
13139 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13144 * @cfg {String} text to display on mask (default Loading)
13148 * @cfg {Boolean} multiSelect Allow multiple selection
13150 multiSelect : false,
13152 * @cfg {Boolean} singleSelect Allow single selection
13154 singleSelect: false,
13157 * @cfg {Boolean} toggleSelect - selecting
13159 toggleSelect : false,
13162 * @cfg {Boolean} tickable - selecting
13167 * Returns the element this view is bound to.
13168 * @return {Roo.Element}
13170 getEl : function(){
13171 return this.wrapEl;
13177 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13179 refresh : function(){
13180 //Roo.log('refresh');
13183 // if we are using something like 'domtemplate', then
13184 // the what gets used is:
13185 // t.applySubtemplate(NAME, data, wrapping data..)
13186 // the outer template then get' applied with
13187 // the store 'extra data'
13188 // and the body get's added to the
13189 // roo-name="data" node?
13190 // <span class='roo-tpl-{name}'></span> ?????
13194 this.clearSelections();
13195 this.el.update("");
13197 var records = this.store.getRange();
13198 if(records.length < 1) {
13200 // is this valid?? = should it render a template??
13202 this.el.update(this.emptyText);
13206 if (this.dataName) {
13207 this.el.update(t.apply(this.store.meta)); //????
13208 el = this.el.child('.roo-tpl-' + this.dataName);
13211 for(var i = 0, len = records.length; i < len; i++){
13212 var data = this.prepareData(records[i].data, i, records[i]);
13213 this.fireEvent("preparedata", this, data, i, records[i]);
13215 var d = Roo.apply({}, data);
13218 Roo.apply(d, {'roo-id' : Roo.id()});
13222 Roo.each(this.parent.item, function(item){
13223 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13226 Roo.apply(d, {'roo-data-checked' : 'checked'});
13230 html[html.length] = Roo.util.Format.trim(
13232 t.applySubtemplate(this.dataName, d, this.store.meta) :
13239 el.update(html.join(""));
13240 this.nodes = el.dom.childNodes;
13241 this.updateIndexes(0);
13246 * Function to override to reformat the data that is sent to
13247 * the template for each node.
13248 * DEPRICATED - use the preparedata event handler.
13249 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13250 * a JSON object for an UpdateManager bound view).
13252 prepareData : function(data, index, record)
13254 this.fireEvent("preparedata", this, data, index, record);
13258 onUpdate : function(ds, record){
13259 // Roo.log('on update');
13260 this.clearSelections();
13261 var index = this.store.indexOf(record);
13262 var n = this.nodes[index];
13263 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13264 n.parentNode.removeChild(n);
13265 this.updateIndexes(index, index);
13271 onAdd : function(ds, records, index)
13273 //Roo.log(['on Add', ds, records, index] );
13274 this.clearSelections();
13275 if(this.nodes.length == 0){
13279 var n = this.nodes[index];
13280 for(var i = 0, len = records.length; i < len; i++){
13281 var d = this.prepareData(records[i].data, i, records[i]);
13283 this.tpl.insertBefore(n, d);
13286 this.tpl.append(this.el, d);
13289 this.updateIndexes(index);
13292 onRemove : function(ds, record, index){
13293 // Roo.log('onRemove');
13294 this.clearSelections();
13295 var el = this.dataName ?
13296 this.el.child('.roo-tpl-' + this.dataName) :
13299 el.dom.removeChild(this.nodes[index]);
13300 this.updateIndexes(index);
13304 * Refresh an individual node.
13305 * @param {Number} index
13307 refreshNode : function(index){
13308 this.onUpdate(this.store, this.store.getAt(index));
13311 updateIndexes : function(startIndex, endIndex){
13312 var ns = this.nodes;
13313 startIndex = startIndex || 0;
13314 endIndex = endIndex || ns.length - 1;
13315 for(var i = startIndex; i <= endIndex; i++){
13316 ns[i].nodeIndex = i;
13321 * Changes the data store this view uses and refresh the view.
13322 * @param {Store} store
13324 setStore : function(store, initial){
13325 if(!initial && this.store){
13326 this.store.un("datachanged", this.refresh);
13327 this.store.un("add", this.onAdd);
13328 this.store.un("remove", this.onRemove);
13329 this.store.un("update", this.onUpdate);
13330 this.store.un("clear", this.refresh);
13331 this.store.un("beforeload", this.onBeforeLoad);
13332 this.store.un("load", this.onLoad);
13333 this.store.un("loadexception", this.onLoad);
13337 store.on("datachanged", this.refresh, this);
13338 store.on("add", this.onAdd, this);
13339 store.on("remove", this.onRemove, this);
13340 store.on("update", this.onUpdate, this);
13341 store.on("clear", this.refresh, this);
13342 store.on("beforeload", this.onBeforeLoad, this);
13343 store.on("load", this.onLoad, this);
13344 store.on("loadexception", this.onLoad, this);
13352 * onbeforeLoad - masks the loading area.
13355 onBeforeLoad : function(store,opts)
13357 //Roo.log('onBeforeLoad');
13359 this.el.update("");
13361 this.el.mask(this.mask ? this.mask : "Loading" );
13363 onLoad : function ()
13370 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13371 * @param {HTMLElement} node
13372 * @return {HTMLElement} The template node
13374 findItemFromChild : function(node){
13375 var el = this.dataName ?
13376 this.el.child('.roo-tpl-' + this.dataName,true) :
13379 if(!node || node.parentNode == el){
13382 var p = node.parentNode;
13383 while(p && p != el){
13384 if(p.parentNode == el){
13393 onClick : function(e){
13394 var item = this.findItemFromChild(e.getTarget());
13396 var index = this.indexOf(item);
13397 if(this.onItemClick(item, index, e) !== false){
13398 this.fireEvent("click", this, index, item, e);
13401 this.clearSelections();
13406 onContextMenu : function(e){
13407 var item = this.findItemFromChild(e.getTarget());
13409 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13414 onDblClick : function(e){
13415 var item = this.findItemFromChild(e.getTarget());
13417 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13421 onItemClick : function(item, index, e)
13423 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13426 if (this.toggleSelect) {
13427 var m = this.isSelected(item) ? 'unselect' : 'select';
13430 _t[m](item, true, false);
13433 if(this.multiSelect || this.singleSelect){
13434 if(this.multiSelect && e.shiftKey && this.lastSelection){
13435 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13437 this.select(item, this.multiSelect && e.ctrlKey);
13438 this.lastSelection = item;
13441 if(!this.tickable){
13442 e.preventDefault();
13450 * Get the number of selected nodes.
13453 getSelectionCount : function(){
13454 return this.selections.length;
13458 * Get the currently selected nodes.
13459 * @return {Array} An array of HTMLElements
13461 getSelectedNodes : function(){
13462 return this.selections;
13466 * Get the indexes of the selected nodes.
13469 getSelectedIndexes : function(){
13470 var indexes = [], s = this.selections;
13471 for(var i = 0, len = s.length; i < len; i++){
13472 indexes.push(s[i].nodeIndex);
13478 * Clear all selections
13479 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13481 clearSelections : function(suppressEvent){
13482 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13483 this.cmp.elements = this.selections;
13484 this.cmp.removeClass(this.selectedClass);
13485 this.selections = [];
13486 if(!suppressEvent){
13487 this.fireEvent("selectionchange", this, this.selections);
13493 * Returns true if the passed node is selected
13494 * @param {HTMLElement/Number} node The node or node index
13495 * @return {Boolean}
13497 isSelected : function(node){
13498 var s = this.selections;
13502 node = this.getNode(node);
13503 return s.indexOf(node) !== -1;
13508 * @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
13509 * @param {Boolean} keepExisting (optional) true to keep existing selections
13510 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13512 select : function(nodeInfo, keepExisting, suppressEvent){
13513 if(nodeInfo instanceof Array){
13515 this.clearSelections(true);
13517 for(var i = 0, len = nodeInfo.length; i < len; i++){
13518 this.select(nodeInfo[i], true, true);
13522 var node = this.getNode(nodeInfo);
13523 if(!node || this.isSelected(node)){
13524 return; // already selected.
13527 this.clearSelections(true);
13530 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13531 Roo.fly(node).addClass(this.selectedClass);
13532 this.selections.push(node);
13533 if(!suppressEvent){
13534 this.fireEvent("selectionchange", this, this.selections);
13542 * @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
13543 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13544 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13546 unselect : function(nodeInfo, keepExisting, suppressEvent)
13548 if(nodeInfo instanceof Array){
13549 Roo.each(this.selections, function(s) {
13550 this.unselect(s, nodeInfo);
13554 var node = this.getNode(nodeInfo);
13555 if(!node || !this.isSelected(node)){
13556 //Roo.log("not selected");
13557 return; // not selected.
13561 Roo.each(this.selections, function(s) {
13563 Roo.fly(node).removeClass(this.selectedClass);
13570 this.selections= ns;
13571 this.fireEvent("selectionchange", this, this.selections);
13575 * Gets a template node.
13576 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13577 * @return {HTMLElement} The node or null if it wasn't found
13579 getNode : function(nodeInfo){
13580 if(typeof nodeInfo == "string"){
13581 return document.getElementById(nodeInfo);
13582 }else if(typeof nodeInfo == "number"){
13583 return this.nodes[nodeInfo];
13589 * Gets a range template nodes.
13590 * @param {Number} startIndex
13591 * @param {Number} endIndex
13592 * @return {Array} An array of nodes
13594 getNodes : function(start, end){
13595 var ns = this.nodes;
13596 start = start || 0;
13597 end = typeof end == "undefined" ? ns.length - 1 : end;
13600 for(var i = start; i <= end; i++){
13604 for(var i = start; i >= end; i--){
13612 * Finds the index of the passed node
13613 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13614 * @return {Number} The index of the node or -1
13616 indexOf : function(node){
13617 node = this.getNode(node);
13618 if(typeof node.nodeIndex == "number"){
13619 return node.nodeIndex;
13621 var ns = this.nodes;
13622 for(var i = 0, len = ns.length; i < len; i++){
13633 * based on jquery fullcalendar
13637 Roo.bootstrap = Roo.bootstrap || {};
13639 * @class Roo.bootstrap.Calendar
13640 * @extends Roo.bootstrap.Component
13641 * Bootstrap Calendar class
13642 * @cfg {Boolean} loadMask (true|false) default false
13643 * @cfg {Object} header generate the user specific header of the calendar, default false
13646 * Create a new Container
13647 * @param {Object} config The config object
13652 Roo.bootstrap.Calendar = function(config){
13653 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13657 * Fires when a date is selected
13658 * @param {DatePicker} this
13659 * @param {Date} date The selected date
13663 * @event monthchange
13664 * Fires when the displayed month changes
13665 * @param {DatePicker} this
13666 * @param {Date} date The selected month
13668 'monthchange': true,
13670 * @event evententer
13671 * Fires when mouse over an event
13672 * @param {Calendar} this
13673 * @param {event} Event
13675 'evententer': true,
13677 * @event eventleave
13678 * Fires when the mouse leaves an
13679 * @param {Calendar} this
13682 'eventleave': true,
13684 * @event eventclick
13685 * Fires when the mouse click an
13686 * @param {Calendar} this
13695 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13698 * @cfg {Number} startDay
13699 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13707 getAutoCreate : function(){
13710 var fc_button = function(name, corner, style, content ) {
13711 return Roo.apply({},{
13713 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13715 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13718 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13729 style : 'width:100%',
13736 cls : 'fc-header-left',
13738 fc_button('prev', 'left', 'arrow', '‹' ),
13739 fc_button('next', 'right', 'arrow', '›' ),
13740 { tag: 'span', cls: 'fc-header-space' },
13741 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13749 cls : 'fc-header-center',
13753 cls: 'fc-header-title',
13756 html : 'month / year'
13764 cls : 'fc-header-right',
13766 /* fc_button('month', 'left', '', 'month' ),
13767 fc_button('week', '', '', 'week' ),
13768 fc_button('day', 'right', '', 'day' )
13780 header = this.header;
13783 var cal_heads = function() {
13785 // fixme - handle this.
13787 for (var i =0; i < Date.dayNames.length; i++) {
13788 var d = Date.dayNames[i];
13791 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13792 html : d.substring(0,3)
13796 ret[0].cls += ' fc-first';
13797 ret[6].cls += ' fc-last';
13800 var cal_cell = function(n) {
13803 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13808 cls: 'fc-day-number',
13812 cls: 'fc-day-content',
13816 style: 'position: relative;' // height: 17px;
13828 var cal_rows = function() {
13831 for (var r = 0; r < 6; r++) {
13838 for (var i =0; i < Date.dayNames.length; i++) {
13839 var d = Date.dayNames[i];
13840 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13843 row.cn[0].cls+=' fc-first';
13844 row.cn[0].cn[0].style = 'min-height:90px';
13845 row.cn[6].cls+=' fc-last';
13849 ret[0].cls += ' fc-first';
13850 ret[4].cls += ' fc-prev-last';
13851 ret[5].cls += ' fc-last';
13858 cls: 'fc-border-separate',
13859 style : 'width:100%',
13867 cls : 'fc-first fc-last',
13885 cls : 'fc-content',
13886 style : "position: relative;",
13889 cls : 'fc-view fc-view-month fc-grid',
13890 style : 'position: relative',
13891 unselectable : 'on',
13894 cls : 'fc-event-container',
13895 style : 'position:absolute;z-index:8;top:0;left:0;'
13913 initEvents : function()
13916 throw "can not find store for calendar";
13922 style: "text-align:center",
13926 style: "background-color:white;width:50%;margin:250 auto",
13930 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13941 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13943 var size = this.el.select('.fc-content', true).first().getSize();
13944 this.maskEl.setSize(size.width, size.height);
13945 this.maskEl.enableDisplayMode("block");
13946 if(!this.loadMask){
13947 this.maskEl.hide();
13950 this.store = Roo.factory(this.store, Roo.data);
13951 this.store.on('load', this.onLoad, this);
13952 this.store.on('beforeload', this.onBeforeLoad, this);
13956 this.cells = this.el.select('.fc-day',true);
13957 //Roo.log(this.cells);
13958 this.textNodes = this.el.query('.fc-day-number');
13959 this.cells.addClassOnOver('fc-state-hover');
13961 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13962 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13963 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13964 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13966 this.on('monthchange', this.onMonthChange, this);
13968 this.update(new Date().clearTime());
13971 resize : function() {
13972 var sz = this.el.getSize();
13974 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13975 this.el.select('.fc-day-content div',true).setHeight(34);
13980 showPrevMonth : function(e){
13981 this.update(this.activeDate.add("mo", -1));
13983 showToday : function(e){
13984 this.update(new Date().clearTime());
13987 showNextMonth : function(e){
13988 this.update(this.activeDate.add("mo", 1));
13992 showPrevYear : function(){
13993 this.update(this.activeDate.add("y", -1));
13997 showNextYear : function(){
13998 this.update(this.activeDate.add("y", 1));
14003 update : function(date)
14005 var vd = this.activeDate;
14006 this.activeDate = date;
14007 // if(vd && this.el){
14008 // var t = date.getTime();
14009 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14010 // Roo.log('using add remove');
14012 // this.fireEvent('monthchange', this, date);
14014 // this.cells.removeClass("fc-state-highlight");
14015 // this.cells.each(function(c){
14016 // if(c.dateValue == t){
14017 // c.addClass("fc-state-highlight");
14018 // setTimeout(function(){
14019 // try{c.dom.firstChild.focus();}catch(e){}
14029 var days = date.getDaysInMonth();
14031 var firstOfMonth = date.getFirstDateOfMonth();
14032 var startingPos = firstOfMonth.getDay()-this.startDay;
14034 if(startingPos < this.startDay){
14038 var pm = date.add(Date.MONTH, -1);
14039 var prevStart = pm.getDaysInMonth()-startingPos;
14041 this.cells = this.el.select('.fc-day',true);
14042 this.textNodes = this.el.query('.fc-day-number');
14043 this.cells.addClassOnOver('fc-state-hover');
14045 var cells = this.cells.elements;
14046 var textEls = this.textNodes;
14048 Roo.each(cells, function(cell){
14049 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14052 days += startingPos;
14054 // convert everything to numbers so it's fast
14055 var day = 86400000;
14056 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14059 //Roo.log(prevStart);
14061 var today = new Date().clearTime().getTime();
14062 var sel = date.clearTime().getTime();
14063 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14064 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14065 var ddMatch = this.disabledDatesRE;
14066 var ddText = this.disabledDatesText;
14067 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14068 var ddaysText = this.disabledDaysText;
14069 var format = this.format;
14071 var setCellClass = function(cal, cell){
14075 //Roo.log('set Cell Class');
14077 var t = d.getTime();
14081 cell.dateValue = t;
14083 cell.className += " fc-today";
14084 cell.className += " fc-state-highlight";
14085 cell.title = cal.todayText;
14088 // disable highlight in other month..
14089 //cell.className += " fc-state-highlight";
14094 cell.className = " fc-state-disabled";
14095 cell.title = cal.minText;
14099 cell.className = " fc-state-disabled";
14100 cell.title = cal.maxText;
14104 if(ddays.indexOf(d.getDay()) != -1){
14105 cell.title = ddaysText;
14106 cell.className = " fc-state-disabled";
14109 if(ddMatch && format){
14110 var fvalue = d.dateFormat(format);
14111 if(ddMatch.test(fvalue)){
14112 cell.title = ddText.replace("%0", fvalue);
14113 cell.className = " fc-state-disabled";
14117 if (!cell.initialClassName) {
14118 cell.initialClassName = cell.dom.className;
14121 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14126 for(; i < startingPos; i++) {
14127 textEls[i].innerHTML = (++prevStart);
14128 d.setDate(d.getDate()+1);
14130 cells[i].className = "fc-past fc-other-month";
14131 setCellClass(this, cells[i]);
14136 for(; i < days; i++){
14137 intDay = i - startingPos + 1;
14138 textEls[i].innerHTML = (intDay);
14139 d.setDate(d.getDate()+1);
14141 cells[i].className = ''; // "x-date-active";
14142 setCellClass(this, cells[i]);
14146 for(; i < 42; i++) {
14147 textEls[i].innerHTML = (++extraDays);
14148 d.setDate(d.getDate()+1);
14150 cells[i].className = "fc-future fc-other-month";
14151 setCellClass(this, cells[i]);
14154 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14156 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14158 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14159 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14161 if(totalRows != 6){
14162 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14163 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14166 this.fireEvent('monthchange', this, date);
14170 if(!this.internalRender){
14171 var main = this.el.dom.firstChild;
14172 var w = main.offsetWidth;
14173 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14174 Roo.fly(main).setWidth(w);
14175 this.internalRender = true;
14176 // opera does not respect the auto grow header center column
14177 // then, after it gets a width opera refuses to recalculate
14178 // without a second pass
14179 if(Roo.isOpera && !this.secondPass){
14180 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14181 this.secondPass = true;
14182 this.update.defer(10, this, [date]);
14189 findCell : function(dt) {
14190 dt = dt.clearTime().getTime();
14192 this.cells.each(function(c){
14193 //Roo.log("check " +c.dateValue + '?=' + dt);
14194 if(c.dateValue == dt){
14204 findCells : function(ev) {
14205 var s = ev.start.clone().clearTime().getTime();
14207 var e= ev.end.clone().clearTime().getTime();
14210 this.cells.each(function(c){
14211 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14213 if(c.dateValue > e){
14216 if(c.dateValue < s){
14225 // findBestRow: function(cells)
14229 // for (var i =0 ; i < cells.length;i++) {
14230 // ret = Math.max(cells[i].rows || 0,ret);
14237 addItem : function(ev)
14239 // look for vertical location slot in
14240 var cells = this.findCells(ev);
14242 // ev.row = this.findBestRow(cells);
14244 // work out the location.
14248 for(var i =0; i < cells.length; i++) {
14250 cells[i].row = cells[0].row;
14253 cells[i].row = cells[i].row + 1;
14263 if (crow.start.getY() == cells[i].getY()) {
14265 crow.end = cells[i];
14282 cells[0].events.push(ev);
14284 this.calevents.push(ev);
14287 clearEvents: function() {
14289 if(!this.calevents){
14293 Roo.each(this.cells.elements, function(c){
14299 Roo.each(this.calevents, function(e) {
14300 Roo.each(e.els, function(el) {
14301 el.un('mouseenter' ,this.onEventEnter, this);
14302 el.un('mouseleave' ,this.onEventLeave, this);
14307 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14313 renderEvents: function()
14317 this.cells.each(function(c) {
14326 if(c.row != c.events.length){
14327 r = 4 - (4 - (c.row - c.events.length));
14330 c.events = ev.slice(0, r);
14331 c.more = ev.slice(r);
14333 if(c.more.length && c.more.length == 1){
14334 c.events.push(c.more.pop());
14337 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14341 this.cells.each(function(c) {
14343 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14346 for (var e = 0; e < c.events.length; e++){
14347 var ev = c.events[e];
14348 var rows = ev.rows;
14350 for(var i = 0; i < rows.length; i++) {
14352 // how many rows should it span..
14355 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14356 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14358 unselectable : "on",
14361 cls: 'fc-event-inner',
14365 // cls: 'fc-event-time',
14366 // html : cells.length > 1 ? '' : ev.time
14370 cls: 'fc-event-title',
14371 html : String.format('{0}', ev.title)
14378 cls: 'ui-resizable-handle ui-resizable-e',
14379 html : '  '
14386 cfg.cls += ' fc-event-start';
14388 if ((i+1) == rows.length) {
14389 cfg.cls += ' fc-event-end';
14392 var ctr = _this.el.select('.fc-event-container',true).first();
14393 var cg = ctr.createChild(cfg);
14395 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14396 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14398 var r = (c.more.length) ? 1 : 0;
14399 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14400 cg.setWidth(ebox.right - sbox.x -2);
14402 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14403 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14404 cg.on('click', _this.onEventClick, _this, ev);
14415 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14416 style : 'position: absolute',
14417 unselectable : "on",
14420 cls: 'fc-event-inner',
14424 cls: 'fc-event-title',
14432 cls: 'ui-resizable-handle ui-resizable-e',
14433 html : '  '
14439 var ctr = _this.el.select('.fc-event-container',true).first();
14440 var cg = ctr.createChild(cfg);
14442 var sbox = c.select('.fc-day-content',true).first().getBox();
14443 var ebox = c.select('.fc-day-content',true).first().getBox();
14445 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14446 cg.setWidth(ebox.right - sbox.x -2);
14448 cg.on('click', _this.onMoreEventClick, _this, c.more);
14458 onEventEnter: function (e, el,event,d) {
14459 this.fireEvent('evententer', this, el, event);
14462 onEventLeave: function (e, el,event,d) {
14463 this.fireEvent('eventleave', this, el, event);
14466 onEventClick: function (e, el,event,d) {
14467 this.fireEvent('eventclick', this, el, event);
14470 onMonthChange: function () {
14474 onMoreEventClick: function(e, el, more)
14478 this.calpopover.placement = 'right';
14479 this.calpopover.setTitle('More');
14481 this.calpopover.setContent('');
14483 var ctr = this.calpopover.el.select('.popover-content', true).first();
14485 Roo.each(more, function(m){
14487 cls : 'fc-event-hori fc-event-draggable',
14490 var cg = ctr.createChild(cfg);
14492 cg.on('click', _this.onEventClick, _this, m);
14495 this.calpopover.show(el);
14500 onLoad: function ()
14502 this.calevents = [];
14505 if(this.store.getCount() > 0){
14506 this.store.data.each(function(d){
14509 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14510 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14511 time : d.data.start_time,
14512 title : d.data.title,
14513 description : d.data.description,
14514 venue : d.data.venue
14519 this.renderEvents();
14521 if(this.calevents.length && this.loadMask){
14522 this.maskEl.hide();
14526 onBeforeLoad: function()
14528 this.clearEvents();
14530 this.maskEl.show();
14544 * @class Roo.bootstrap.Popover
14545 * @extends Roo.bootstrap.Component
14546 * Bootstrap Popover class
14547 * @cfg {String} html contents of the popover (or false to use children..)
14548 * @cfg {String} title of popover (or false to hide)
14549 * @cfg {String} placement how it is placed
14550 * @cfg {String} trigger click || hover (or false to trigger manually)
14551 * @cfg {String} over what (parent or false to trigger manually.)
14552 * @cfg {Number} delay - delay before showing
14555 * Create a new Popover
14556 * @param {Object} config The config object
14559 Roo.bootstrap.Popover = function(config){
14560 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14563 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14565 title: 'Fill in a title',
14568 placement : 'right',
14569 trigger : 'hover', // hover
14575 can_build_overlaid : false,
14577 getChildContainer : function()
14579 return this.el.select('.popover-content',true).first();
14582 getAutoCreate : function(){
14583 Roo.log('make popover?');
14585 cls : 'popover roo-dynamic',
14586 style: 'display:block',
14592 cls : 'popover-inner',
14596 cls: 'popover-title',
14600 cls : 'popover-content',
14611 setTitle: function(str)
14613 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14615 setContent: function(str)
14617 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14619 // as it get's added to the bottom of the page.
14620 onRender : function(ct, position)
14622 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14624 var cfg = Roo.apply({}, this.getAutoCreate());
14628 cfg.cls += ' ' + this.cls;
14631 cfg.style = this.style;
14633 Roo.log("adding to ")
14634 this.el = Roo.get(document.body).createChild(cfg, position);
14640 initEvents : function()
14642 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14643 this.el.enableDisplayMode('block');
14645 if (this.over === false) {
14648 if (this.triggers === false) {
14651 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14652 var triggers = this.trigger ? this.trigger.split(' ') : [];
14653 Roo.each(triggers, function(trigger) {
14655 if (trigger == 'click') {
14656 on_el.on('click', this.toggle, this);
14657 } else if (trigger != 'manual') {
14658 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14659 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14661 on_el.on(eventIn ,this.enter, this);
14662 on_el.on(eventOut, this.leave, this);
14673 toggle : function () {
14674 this.hoverState == 'in' ? this.leave() : this.enter();
14677 enter : function () {
14680 clearTimeout(this.timeout);
14682 this.hoverState = 'in';
14684 if (!this.delay || !this.delay.show) {
14689 this.timeout = setTimeout(function () {
14690 if (_t.hoverState == 'in') {
14693 }, this.delay.show)
14695 leave : function() {
14696 clearTimeout(this.timeout);
14698 this.hoverState = 'out';
14700 if (!this.delay || !this.delay.hide) {
14705 this.timeout = setTimeout(function () {
14706 if (_t.hoverState == 'out') {
14709 }, this.delay.hide)
14712 show : function (on_el)
14715 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14718 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14719 if (this.html !== false) {
14720 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14722 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14723 if (!this.title.length) {
14724 this.el.select('.popover-title',true).hide();
14727 var placement = typeof this.placement == 'function' ?
14728 this.placement.call(this, this.el, on_el) :
14731 var autoToken = /\s?auto?\s?/i;
14732 var autoPlace = autoToken.test(placement);
14734 placement = placement.replace(autoToken, '') || 'top';
14738 //this.el.setXY([0,0]);
14740 this.el.dom.style.display='block';
14741 this.el.addClass(placement);
14743 //this.el.appendTo(on_el);
14745 var p = this.getPosition();
14746 var box = this.el.getBox();
14751 var align = Roo.bootstrap.Popover.alignment[placement];
14752 this.el.alignTo(on_el, align[0],align[1]);
14753 //var arrow = this.el.select('.arrow',true).first();
14754 //arrow.set(align[2],
14756 this.el.addClass('in');
14757 this.hoverState = null;
14759 if (this.el.hasClass('fade')) {
14766 this.el.setXY([0,0]);
14767 this.el.removeClass('in');
14774 Roo.bootstrap.Popover.alignment = {
14775 'left' : ['r-l', [-10,0], 'right'],
14776 'right' : ['l-r', [10,0], 'left'],
14777 'bottom' : ['t-b', [0,10], 'top'],
14778 'top' : [ 'b-t', [0,-10], 'bottom']
14789 * @class Roo.bootstrap.Progress
14790 * @extends Roo.bootstrap.Component
14791 * Bootstrap Progress class
14792 * @cfg {Boolean} striped striped of the progress bar
14793 * @cfg {Boolean} active animated of the progress bar
14797 * Create a new Progress
14798 * @param {Object} config The config object
14801 Roo.bootstrap.Progress = function(config){
14802 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14805 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14810 getAutoCreate : function(){
14818 cfg.cls += ' progress-striped';
14822 cfg.cls += ' active';
14841 * @class Roo.bootstrap.ProgressBar
14842 * @extends Roo.bootstrap.Component
14843 * Bootstrap ProgressBar class
14844 * @cfg {Number} aria_valuenow aria-value now
14845 * @cfg {Number} aria_valuemin aria-value min
14846 * @cfg {Number} aria_valuemax aria-value max
14847 * @cfg {String} label label for the progress bar
14848 * @cfg {String} panel (success | info | warning | danger )
14849 * @cfg {String} role role of the progress bar
14850 * @cfg {String} sr_only text
14854 * Create a new ProgressBar
14855 * @param {Object} config The config object
14858 Roo.bootstrap.ProgressBar = function(config){
14859 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14862 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14866 aria_valuemax : 100,
14872 getAutoCreate : function()
14877 cls: 'progress-bar',
14878 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14890 cfg.role = this.role;
14893 if(this.aria_valuenow){
14894 cfg['aria-valuenow'] = this.aria_valuenow;
14897 if(this.aria_valuemin){
14898 cfg['aria-valuemin'] = this.aria_valuemin;
14901 if(this.aria_valuemax){
14902 cfg['aria-valuemax'] = this.aria_valuemax;
14905 if(this.label && !this.sr_only){
14906 cfg.html = this.label;
14910 cfg.cls += ' progress-bar-' + this.panel;
14916 update : function(aria_valuenow)
14918 this.aria_valuenow = aria_valuenow;
14920 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14935 * @class Roo.bootstrap.TabGroup
14936 * @extends Roo.bootstrap.Column
14937 * Bootstrap Column class
14938 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14939 * @cfg {Boolean} carousel true to make the group behave like a carousel
14940 * @cfg {Number} bullets show the panel pointer.. default 0
14941 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14942 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14943 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14946 * Create a new TabGroup
14947 * @param {Object} config The config object
14950 Roo.bootstrap.TabGroup = function(config){
14951 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14953 this.navId = Roo.id();
14956 Roo.bootstrap.TabGroup.register(this);
14960 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14963 transition : false,
14968 slideOnTouch : false,
14970 getAutoCreate : function()
14972 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14974 cfg.cls += ' tab-content';
14976 Roo.log('get auto create...............');
14978 if (this.carousel) {
14979 cfg.cls += ' carousel slide';
14982 cls : 'carousel-inner'
14985 if(this.bullets > 0 && !Roo.isTouch){
14988 cls : 'carousel-bullets',
14992 if(this.bullets_cls){
14993 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14996 for (var i = 0; i < this.bullets; i++){
14998 cls : 'bullet bullet-' + i
15006 cfg.cn[0].cn = bullets;
15013 initEvents: function()
15015 Roo.log('-------- init events on tab group ---------');
15017 if(this.bullets > 0 && !Roo.isTouch){
15023 if(Roo.isTouch && this.slideOnTouch){
15024 this.el.on("touchstart", this.onTouchStart, this);
15027 if(this.autoslide){
15030 this.slideFn = window.setInterval(function() {
15031 _this.showPanelNext();
15037 onTouchStart : function(e, el, o)
15039 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15043 this.showPanelNext();
15046 getChildContainer : function()
15048 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15052 * register a Navigation item
15053 * @param {Roo.bootstrap.NavItem} the navitem to add
15055 register : function(item)
15057 this.tabs.push( item);
15058 item.navId = this.navId; // not really needed..
15062 getActivePanel : function()
15065 Roo.each(this.tabs, function(t) {
15075 getPanelByName : function(n)
15078 Roo.each(this.tabs, function(t) {
15079 if (t.tabId == n) {
15087 indexOfPanel : function(p)
15090 Roo.each(this.tabs, function(t,i) {
15091 if (t.tabId == p.tabId) {
15100 * show a specific panel
15101 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15102 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15104 showPanel : function (pan)
15106 if(this.transition){
15107 Roo.log("waiting for the transitionend");
15111 if (typeof(pan) == 'number') {
15112 pan = this.tabs[pan];
15114 if (typeof(pan) == 'string') {
15115 pan = this.getPanelByName(pan);
15117 if (pan.tabId == this.getActivePanel().tabId) {
15120 var cur = this.getActivePanel();
15122 if (false === cur.fireEvent('beforedeactivate')) {
15126 if(this.bullets > 0 && !Roo.isTouch){
15127 this.setActiveBullet(this.indexOfPanel(pan));
15130 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15132 this.transition = true;
15133 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15134 var lr = dir == 'next' ? 'left' : 'right';
15135 pan.el.addClass(dir); // or prev
15136 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15137 cur.el.addClass(lr); // or right
15138 pan.el.addClass(lr);
15141 cur.el.on('transitionend', function() {
15142 Roo.log("trans end?");
15144 pan.el.removeClass([lr,dir]);
15145 pan.setActive(true);
15147 cur.el.removeClass([lr]);
15148 cur.setActive(false);
15150 _this.transition = false;
15152 }, this, { single: true } );
15157 cur.setActive(false);
15158 pan.setActive(true);
15163 showPanelNext : function()
15165 var i = this.indexOfPanel(this.getActivePanel());
15167 if (i >= this.tabs.length - 1 && !this.autoslide) {
15171 if (i >= this.tabs.length - 1 && this.autoslide) {
15175 this.showPanel(this.tabs[i+1]);
15178 showPanelPrev : function()
15180 var i = this.indexOfPanel(this.getActivePanel());
15182 if (i < 1 && !this.autoslide) {
15186 if (i < 1 && this.autoslide) {
15187 i = this.tabs.length;
15190 this.showPanel(this.tabs[i-1]);
15193 initBullet : function()
15201 for (var i = 0; i < this.bullets; i++){
15202 var bullet = this.el.select('.bullet-' + i, true).first();
15208 bullet.on('click', (function(e, el, o, ii, t){
15210 e.preventDefault();
15212 _this.showPanel(ii);
15214 if(_this.autoslide && _this.slideFn){
15215 clearInterval(_this.slideFn);
15216 _this.slideFn = window.setInterval(function() {
15217 _this.showPanelNext();
15221 }).createDelegate(this, [i, bullet], true));
15225 setActiveBullet : function(i)
15231 Roo.each(this.el.select('.bullet', true).elements, function(el){
15232 el.removeClass('selected');
15235 var bullet = this.el.select('.bullet-' + i, true).first();
15241 bullet.addClass('selected');
15252 Roo.apply(Roo.bootstrap.TabGroup, {
15256 * register a Navigation Group
15257 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15259 register : function(navgrp)
15261 this.groups[navgrp.navId] = navgrp;
15265 * fetch a Navigation Group based on the navigation ID
15266 * if one does not exist , it will get created.
15267 * @param {string} the navgroup to add
15268 * @returns {Roo.bootstrap.NavGroup} the navgroup
15270 get: function(navId) {
15271 if (typeof(this.groups[navId]) == 'undefined') {
15272 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15274 return this.groups[navId] ;
15289 * @class Roo.bootstrap.TabPanel
15290 * @extends Roo.bootstrap.Component
15291 * Bootstrap TabPanel class
15292 * @cfg {Boolean} active panel active
15293 * @cfg {String} html panel content
15294 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15295 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15299 * Create a new TabPanel
15300 * @param {Object} config The config object
15303 Roo.bootstrap.TabPanel = function(config){
15304 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15308 * Fires when the active status changes
15309 * @param {Roo.bootstrap.TabPanel} this
15310 * @param {Boolean} state the new state
15315 * @event beforedeactivate
15316 * Fires before a tab is de-activated - can be used to do validation on a form.
15317 * @param {Roo.bootstrap.TabPanel} this
15318 * @return {Boolean} false if there is an error
15321 'beforedeactivate': true
15324 this.tabId = this.tabId || Roo.id();
15328 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15335 getAutoCreate : function(){
15338 // item is needed for carousel - not sure if it has any effect otherwise
15339 cls: 'tab-pane item',
15340 html: this.html || ''
15344 cfg.cls += ' active';
15348 cfg.tabId = this.tabId;
15355 initEvents: function()
15357 Roo.log('-------- init events on tab panel ---------');
15359 var p = this.parent();
15360 this.navId = this.navId || p.navId;
15362 if (typeof(this.navId) != 'undefined') {
15363 // not really needed.. but just in case.. parent should be a NavGroup.
15364 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15365 Roo.log(['register', tg, this]);
15368 var i = tg.tabs.length - 1;
15370 if(this.active && tg.bullets > 0 && i < tg.bullets){
15371 tg.setActiveBullet(i);
15378 onRender : function(ct, position)
15380 // Roo.log("Call onRender: " + this.xtype);
15382 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15390 setActive: function(state)
15392 Roo.log("panel - set active " + this.tabId + "=" + state);
15394 this.active = state;
15396 this.el.removeClass('active');
15398 } else if (!this.el.hasClass('active')) {
15399 this.el.addClass('active');
15402 this.fireEvent('changed', this, state);
15419 * @class Roo.bootstrap.DateField
15420 * @extends Roo.bootstrap.Input
15421 * Bootstrap DateField class
15422 * @cfg {Number} weekStart default 0
15423 * @cfg {String} viewMode default empty, (months|years)
15424 * @cfg {String} minViewMode default empty, (months|years)
15425 * @cfg {Number} startDate default -Infinity
15426 * @cfg {Number} endDate default Infinity
15427 * @cfg {Boolean} todayHighlight default false
15428 * @cfg {Boolean} todayBtn default false
15429 * @cfg {Boolean} calendarWeeks default false
15430 * @cfg {Object} daysOfWeekDisabled default empty
15431 * @cfg {Boolean} singleMode default false (true | false)
15433 * @cfg {Boolean} keyboardNavigation default true
15434 * @cfg {String} language default en
15437 * Create a new DateField
15438 * @param {Object} config The config object
15441 Roo.bootstrap.DateField = function(config){
15442 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15446 * Fires when this field show.
15447 * @param {Roo.bootstrap.DateField} this
15448 * @param {Mixed} date The date value
15453 * Fires when this field hide.
15454 * @param {Roo.bootstrap.DateField} this
15455 * @param {Mixed} date The date value
15460 * Fires when select a date.
15461 * @param {Roo.bootstrap.DateField} this
15462 * @param {Mixed} date The date value
15468 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15471 * @cfg {String} format
15472 * The default date format string which can be overriden for localization support. The format must be
15473 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15477 * @cfg {String} altFormats
15478 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15479 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15481 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15489 todayHighlight : false,
15495 keyboardNavigation: true,
15497 calendarWeeks: false,
15499 startDate: -Infinity,
15503 daysOfWeekDisabled: [],
15507 singleMode : false,
15509 UTCDate: function()
15511 return new Date(Date.UTC.apply(Date, arguments));
15514 UTCToday: function()
15516 var today = new Date();
15517 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15520 getDate: function() {
15521 var d = this.getUTCDate();
15522 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15525 getUTCDate: function() {
15529 setDate: function(d) {
15530 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15533 setUTCDate: function(d) {
15535 this.setValue(this.formatDate(this.date));
15538 onRender: function(ct, position)
15541 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15543 this.language = this.language || 'en';
15544 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15545 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15547 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15548 this.format = this.format || 'm/d/y';
15549 this.isInline = false;
15550 this.isInput = true;
15551 this.component = this.el.select('.add-on', true).first() || false;
15552 this.component = (this.component && this.component.length === 0) ? false : this.component;
15553 this.hasInput = this.component && this.inputEL().length;
15555 if (typeof(this.minViewMode === 'string')) {
15556 switch (this.minViewMode) {
15558 this.minViewMode = 1;
15561 this.minViewMode = 2;
15564 this.minViewMode = 0;
15569 if (typeof(this.viewMode === 'string')) {
15570 switch (this.viewMode) {
15583 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15585 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15587 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15589 this.picker().on('mousedown', this.onMousedown, this);
15590 this.picker().on('click', this.onClick, this);
15592 this.picker().addClass('datepicker-dropdown');
15594 this.startViewMode = this.viewMode;
15596 if(this.singleMode){
15597 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15598 v.setVisibilityMode(Roo.Element.DISPLAY)
15602 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15603 v.setStyle('width', '189px');
15607 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15608 if(!this.calendarWeeks){
15613 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15614 v.attr('colspan', function(i, val){
15615 return parseInt(val) + 1;
15620 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15622 this.setStartDate(this.startDate);
15623 this.setEndDate(this.endDate);
15625 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15632 if(this.isInline) {
15637 picker : function()
15639 return this.pickerEl;
15640 // return this.el.select('.datepicker', true).first();
15643 fillDow: function()
15645 var dowCnt = this.weekStart;
15654 if(this.calendarWeeks){
15662 while (dowCnt < this.weekStart + 7) {
15666 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15670 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15673 fillMonths: function()
15676 var months = this.picker().select('>.datepicker-months td', true).first();
15678 months.dom.innerHTML = '';
15684 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15687 months.createChild(month);
15694 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;
15696 if (this.date < this.startDate) {
15697 this.viewDate = new Date(this.startDate);
15698 } else if (this.date > this.endDate) {
15699 this.viewDate = new Date(this.endDate);
15701 this.viewDate = new Date(this.date);
15709 var d = new Date(this.viewDate),
15710 year = d.getUTCFullYear(),
15711 month = d.getUTCMonth(),
15712 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15713 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15714 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15715 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15716 currentDate = this.date && this.date.valueOf(),
15717 today = this.UTCToday();
15719 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15721 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15723 // this.picker.select('>tfoot th.today').
15724 // .text(dates[this.language].today)
15725 // .toggle(this.todayBtn !== false);
15727 this.updateNavArrows();
15730 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15732 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15734 prevMonth.setUTCDate(day);
15736 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15738 var nextMonth = new Date(prevMonth);
15740 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15742 nextMonth = nextMonth.valueOf();
15744 var fillMonths = false;
15746 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15748 while(prevMonth.valueOf() < nextMonth) {
15751 if (prevMonth.getUTCDay() === this.weekStart) {
15753 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15761 if(this.calendarWeeks){
15762 // ISO 8601: First week contains first thursday.
15763 // ISO also states week starts on Monday, but we can be more abstract here.
15765 // Start of current week: based on weekstart/current date
15766 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15767 // Thursday of this week
15768 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15769 // First Thursday of year, year from thursday
15770 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15771 // Calendar week: ms between thursdays, div ms per day, div 7 days
15772 calWeek = (th - yth) / 864e5 / 7 + 1;
15774 fillMonths.cn.push({
15782 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15784 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15787 if (this.todayHighlight &&
15788 prevMonth.getUTCFullYear() == today.getFullYear() &&
15789 prevMonth.getUTCMonth() == today.getMonth() &&
15790 prevMonth.getUTCDate() == today.getDate()) {
15791 clsName += ' today';
15794 if (currentDate && prevMonth.valueOf() === currentDate) {
15795 clsName += ' active';
15798 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15799 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15800 clsName += ' disabled';
15803 fillMonths.cn.push({
15805 cls: 'day ' + clsName,
15806 html: prevMonth.getDate()
15809 prevMonth.setDate(prevMonth.getDate()+1);
15812 var currentYear = this.date && this.date.getUTCFullYear();
15813 var currentMonth = this.date && this.date.getUTCMonth();
15815 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15817 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15818 v.removeClass('active');
15820 if(currentYear === year && k === currentMonth){
15821 v.addClass('active');
15824 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15825 v.addClass('disabled');
15831 year = parseInt(year/10, 10) * 10;
15833 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15835 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15838 for (var i = -1; i < 11; i++) {
15839 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15841 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15849 showMode: function(dir)
15852 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15855 Roo.each(this.picker().select('>div',true).elements, function(v){
15856 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15859 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15864 if(this.isInline) return;
15866 this.picker().removeClass(['bottom', 'top']);
15868 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15870 * place to the top of element!
15874 this.picker().addClass('top');
15875 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15880 this.picker().addClass('bottom');
15882 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15885 parseDate : function(value)
15887 if(!value || value instanceof Date){
15890 var v = Date.parseDate(value, this.format);
15891 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15892 v = Date.parseDate(value, 'Y-m-d');
15894 if(!v && this.altFormats){
15895 if(!this.altFormatsArray){
15896 this.altFormatsArray = this.altFormats.split("|");
15898 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15899 v = Date.parseDate(value, this.altFormatsArray[i]);
15905 formatDate : function(date, fmt)
15907 return (!date || !(date instanceof Date)) ?
15908 date : date.dateFormat(fmt || this.format);
15911 onFocus : function()
15913 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15917 onBlur : function()
15919 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15921 var d = this.inputEl().getValue();
15930 this.picker().show();
15934 this.fireEvent('show', this, this.date);
15939 if(this.isInline) return;
15940 this.picker().hide();
15941 this.viewMode = this.startViewMode;
15944 this.fireEvent('hide', this, this.date);
15948 onMousedown: function(e)
15950 e.stopPropagation();
15951 e.preventDefault();
15956 Roo.bootstrap.DateField.superclass.keyup.call(this);
15960 setValue: function(v)
15963 // v can be a string or a date..
15966 var d = new Date(this.parseDate(v) ).clearTime();
15968 if(isNaN(d.getTime())){
15969 this.date = this.viewDate = '';
15970 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15974 v = this.formatDate(d);
15976 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15978 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15982 this.fireEvent('select', this, this.date);
15986 getValue: function()
15988 return this.formatDate(this.date);
15991 fireKey: function(e)
15993 if (!this.picker().isVisible()){
15994 if (e.keyCode == 27) // allow escape to hide and re-show picker
15999 var dateChanged = false,
16001 newDate, newViewDate;
16006 e.preventDefault();
16010 if (!this.keyboardNavigation) break;
16011 dir = e.keyCode == 37 ? -1 : 1;
16014 newDate = this.moveYear(this.date, dir);
16015 newViewDate = this.moveYear(this.viewDate, dir);
16016 } else if (e.shiftKey){
16017 newDate = this.moveMonth(this.date, dir);
16018 newViewDate = this.moveMonth(this.viewDate, dir);
16020 newDate = new Date(this.date);
16021 newDate.setUTCDate(this.date.getUTCDate() + dir);
16022 newViewDate = new Date(this.viewDate);
16023 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16025 if (this.dateWithinRange(newDate)){
16026 this.date = newDate;
16027 this.viewDate = newViewDate;
16028 this.setValue(this.formatDate(this.date));
16030 e.preventDefault();
16031 dateChanged = true;
16036 if (!this.keyboardNavigation) break;
16037 dir = e.keyCode == 38 ? -1 : 1;
16039 newDate = this.moveYear(this.date, dir);
16040 newViewDate = this.moveYear(this.viewDate, dir);
16041 } else if (e.shiftKey){
16042 newDate = this.moveMonth(this.date, dir);
16043 newViewDate = this.moveMonth(this.viewDate, dir);
16045 newDate = new Date(this.date);
16046 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16047 newViewDate = new Date(this.viewDate);
16048 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16050 if (this.dateWithinRange(newDate)){
16051 this.date = newDate;
16052 this.viewDate = newViewDate;
16053 this.setValue(this.formatDate(this.date));
16055 e.preventDefault();
16056 dateChanged = true;
16060 this.setValue(this.formatDate(this.date));
16062 e.preventDefault();
16065 this.setValue(this.formatDate(this.date));
16079 onClick: function(e)
16081 e.stopPropagation();
16082 e.preventDefault();
16084 var target = e.getTarget();
16086 if(target.nodeName.toLowerCase() === 'i'){
16087 target = Roo.get(target).dom.parentNode;
16090 var nodeName = target.nodeName;
16091 var className = target.className;
16092 var html = target.innerHTML;
16093 //Roo.log(nodeName);
16095 switch(nodeName.toLowerCase()) {
16097 switch(className) {
16103 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16104 switch(this.viewMode){
16106 this.viewDate = this.moveMonth(this.viewDate, dir);
16110 this.viewDate = this.moveYear(this.viewDate, dir);
16116 var date = new Date();
16117 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16119 this.setValue(this.formatDate(this.date));
16126 if (className.indexOf('disabled') < 0) {
16127 this.viewDate.setUTCDate(1);
16128 if (className.indexOf('month') > -1) {
16129 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16131 var year = parseInt(html, 10) || 0;
16132 this.viewDate.setUTCFullYear(year);
16136 if(this.singleMode){
16137 this.setValue(this.formatDate(this.viewDate));
16148 //Roo.log(className);
16149 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16150 var day = parseInt(html, 10) || 1;
16151 var year = this.viewDate.getUTCFullYear(),
16152 month = this.viewDate.getUTCMonth();
16154 if (className.indexOf('old') > -1) {
16161 } else if (className.indexOf('new') > -1) {
16169 //Roo.log([year,month,day]);
16170 this.date = this.UTCDate(year, month, day,0,0,0,0);
16171 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16173 //Roo.log(this.formatDate(this.date));
16174 this.setValue(this.formatDate(this.date));
16181 setStartDate: function(startDate)
16183 this.startDate = startDate || -Infinity;
16184 if (this.startDate !== -Infinity) {
16185 this.startDate = this.parseDate(this.startDate);
16188 this.updateNavArrows();
16191 setEndDate: function(endDate)
16193 this.endDate = endDate || Infinity;
16194 if (this.endDate !== Infinity) {
16195 this.endDate = this.parseDate(this.endDate);
16198 this.updateNavArrows();
16201 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16203 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16204 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16205 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16207 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16208 return parseInt(d, 10);
16211 this.updateNavArrows();
16214 updateNavArrows: function()
16216 if(this.singleMode){
16220 var d = new Date(this.viewDate),
16221 year = d.getUTCFullYear(),
16222 month = d.getUTCMonth();
16224 Roo.each(this.picker().select('.prev', true).elements, function(v){
16226 switch (this.viewMode) {
16229 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16235 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16242 Roo.each(this.picker().select('.next', true).elements, function(v){
16244 switch (this.viewMode) {
16247 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16253 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16261 moveMonth: function(date, dir)
16263 if (!dir) return date;
16264 var new_date = new Date(date.valueOf()),
16265 day = new_date.getUTCDate(),
16266 month = new_date.getUTCMonth(),
16267 mag = Math.abs(dir),
16269 dir = dir > 0 ? 1 : -1;
16272 // If going back one month, make sure month is not current month
16273 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16275 return new_date.getUTCMonth() == month;
16277 // If going forward one month, make sure month is as expected
16278 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16280 return new_date.getUTCMonth() != new_month;
16282 new_month = month + dir;
16283 new_date.setUTCMonth(new_month);
16284 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16285 if (new_month < 0 || new_month > 11)
16286 new_month = (new_month + 12) % 12;
16288 // For magnitudes >1, move one month at a time...
16289 for (var i=0; i<mag; i++)
16290 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16291 new_date = this.moveMonth(new_date, dir);
16292 // ...then reset the day, keeping it in the new month
16293 new_month = new_date.getUTCMonth();
16294 new_date.setUTCDate(day);
16296 return new_month != new_date.getUTCMonth();
16299 // Common date-resetting loop -- if date is beyond end of month, make it
16302 new_date.setUTCDate(--day);
16303 new_date.setUTCMonth(new_month);
16308 moveYear: function(date, dir)
16310 return this.moveMonth(date, dir*12);
16313 dateWithinRange: function(date)
16315 return date >= this.startDate && date <= this.endDate;
16321 this.picker().remove();
16326 Roo.apply(Roo.bootstrap.DateField, {
16337 html: '<i class="fa fa-arrow-left"/>'
16347 html: '<i class="fa fa-arrow-right"/>'
16389 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16390 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16391 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16392 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16393 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16406 navFnc: 'FullYear',
16411 navFnc: 'FullYear',
16416 Roo.apply(Roo.bootstrap.DateField, {
16420 cls: 'datepicker dropdown-menu roo-dynamic',
16424 cls: 'datepicker-days',
16428 cls: 'table-condensed',
16430 Roo.bootstrap.DateField.head,
16434 Roo.bootstrap.DateField.footer
16441 cls: 'datepicker-months',
16445 cls: 'table-condensed',
16447 Roo.bootstrap.DateField.head,
16448 Roo.bootstrap.DateField.content,
16449 Roo.bootstrap.DateField.footer
16456 cls: 'datepicker-years',
16460 cls: 'table-condensed',
16462 Roo.bootstrap.DateField.head,
16463 Roo.bootstrap.DateField.content,
16464 Roo.bootstrap.DateField.footer
16483 * @class Roo.bootstrap.TimeField
16484 * @extends Roo.bootstrap.Input
16485 * Bootstrap DateField class
16489 * Create a new TimeField
16490 * @param {Object} config The config object
16493 Roo.bootstrap.TimeField = function(config){
16494 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16498 * Fires when this field show.
16499 * @param {Roo.bootstrap.DateField} thisthis
16500 * @param {Mixed} date The date value
16505 * Fires when this field hide.
16506 * @param {Roo.bootstrap.DateField} this
16507 * @param {Mixed} date The date value
16512 * Fires when select a date.
16513 * @param {Roo.bootstrap.DateField} this
16514 * @param {Mixed} date The date value
16520 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16523 * @cfg {String} format
16524 * The default time format string which can be overriden for localization support. The format must be
16525 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16529 onRender: function(ct, position)
16532 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16534 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16536 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16538 this.pop = this.picker().select('>.datepicker-time',true).first();
16539 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16541 this.picker().on('mousedown', this.onMousedown, this);
16542 this.picker().on('click', this.onClick, this);
16544 this.picker().addClass('datepicker-dropdown');
16549 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16550 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16551 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16552 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16553 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16554 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16558 fireKey: function(e){
16559 if (!this.picker().isVisible()){
16560 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16566 e.preventDefault();
16574 this.onTogglePeriod();
16577 this.onIncrementMinutes();
16580 this.onDecrementMinutes();
16589 onClick: function(e) {
16590 e.stopPropagation();
16591 e.preventDefault();
16594 picker : function()
16596 return this.el.select('.datepicker', true).first();
16599 fillTime: function()
16601 var time = this.pop.select('tbody', true).first();
16603 time.dom.innerHTML = '';
16618 cls: 'hours-up glyphicon glyphicon-chevron-up'
16638 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16659 cls: 'timepicker-hour',
16674 cls: 'timepicker-minute',
16689 cls: 'btn btn-primary period',
16711 cls: 'hours-down glyphicon glyphicon-chevron-down'
16731 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16749 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16756 var hours = this.time.getHours();
16757 var minutes = this.time.getMinutes();
16770 hours = hours - 12;
16774 hours = '0' + hours;
16778 minutes = '0' + minutes;
16781 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16782 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16783 this.pop.select('button', true).first().dom.innerHTML = period;
16789 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16791 var cls = ['bottom'];
16793 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16800 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16805 this.picker().addClass(cls.join('-'));
16809 Roo.each(cls, function(c){
16811 _this.picker().setTop(_this.inputEl().getHeight());
16815 _this.picker().setTop(0 - _this.picker().getHeight());
16820 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16824 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16831 onFocus : function()
16833 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16837 onBlur : function()
16839 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16845 this.picker().show();
16850 this.fireEvent('show', this, this.date);
16855 this.picker().hide();
16858 this.fireEvent('hide', this, this.date);
16861 setTime : function()
16864 this.setValue(this.time.format(this.format));
16866 this.fireEvent('select', this, this.date);
16871 onMousedown: function(e){
16872 e.stopPropagation();
16873 e.preventDefault();
16876 onIncrementHours: function()
16878 Roo.log('onIncrementHours');
16879 this.time = this.time.add(Date.HOUR, 1);
16884 onDecrementHours: function()
16886 Roo.log('onDecrementHours');
16887 this.time = this.time.add(Date.HOUR, -1);
16891 onIncrementMinutes: function()
16893 Roo.log('onIncrementMinutes');
16894 this.time = this.time.add(Date.MINUTE, 1);
16898 onDecrementMinutes: function()
16900 Roo.log('onDecrementMinutes');
16901 this.time = this.time.add(Date.MINUTE, -1);
16905 onTogglePeriod: function()
16907 Roo.log('onTogglePeriod');
16908 this.time = this.time.add(Date.HOUR, 12);
16915 Roo.apply(Roo.bootstrap.TimeField, {
16945 cls: 'btn btn-info ok',
16957 Roo.apply(Roo.bootstrap.TimeField, {
16961 cls: 'datepicker dropdown-menu',
16965 cls: 'datepicker-time',
16969 cls: 'table-condensed',
16971 Roo.bootstrap.TimeField.content,
16972 Roo.bootstrap.TimeField.footer
16991 * @class Roo.bootstrap.MonthField
16992 * @extends Roo.bootstrap.Input
16993 * Bootstrap MonthField class
16995 * @cfg {String} language default en
16998 * Create a new MonthField
16999 * @param {Object} config The config object
17002 Roo.bootstrap.MonthField = function(config){
17003 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
17008 * Fires when this field show.
17009 * @param {Roo.bootstrap.MonthField} this
17010 * @param {Mixed} date The date value
17015 * Fires when this field hide.
17016 * @param {Roo.bootstrap.MonthField} this
17017 * @param {Mixed} date The date value
17022 * Fires when select a date.
17023 * @param {Roo.bootstrap.MonthField} this
17024 * @param {String} oldvalue The old value
17025 * @param {String} newvalue The new value
17031 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17033 onRender: function(ct, position)
17036 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17038 this.language = this.language || 'en';
17039 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17040 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17042 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17043 this.isInline = false;
17044 this.isInput = true;
17045 this.component = this.el.select('.add-on', true).first() || false;
17046 this.component = (this.component && this.component.length === 0) ? false : this.component;
17047 this.hasInput = this.component && this.inputEL().length;
17049 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17051 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17053 this.picker().on('mousedown', this.onMousedown, this);
17054 this.picker().on('click', this.onClick, this);
17056 this.picker().addClass('datepicker-dropdown');
17058 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17059 v.setStyle('width', '189px');
17066 if(this.isInline) {
17072 setValue: function(v, suppressEvent)
17074 var o = this.getValue();
17076 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17080 if(suppressEvent !== true){
17081 this.fireEvent('select', this, o, v);
17086 getValue: function()
17091 onClick: function(e)
17093 e.stopPropagation();
17094 e.preventDefault();
17096 var target = e.getTarget();
17098 if(target.nodeName.toLowerCase() === 'i'){
17099 target = Roo.get(target).dom.parentNode;
17102 var nodeName = target.nodeName;
17103 var className = target.className;
17104 var html = target.innerHTML;
17106 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17110 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17112 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17118 picker : function()
17120 return this.pickerEl;
17123 fillMonths: function()
17126 var months = this.picker().select('>.datepicker-months td', true).first();
17128 months.dom.innerHTML = '';
17134 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17137 months.createChild(month);
17146 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17147 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17150 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17151 e.removeClass('active');
17153 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17154 e.addClass('active');
17161 if(this.isInline) return;
17163 this.picker().removeClass(['bottom', 'top']);
17165 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17167 * place to the top of element!
17171 this.picker().addClass('top');
17172 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17177 this.picker().addClass('bottom');
17179 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17182 onFocus : function()
17184 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17188 onBlur : function()
17190 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17192 var d = this.inputEl().getValue();
17201 this.picker().show();
17202 this.picker().select('>.datepicker-months', true).first().show();
17206 this.fireEvent('show', this, this.date);
17211 if(this.isInline) return;
17212 this.picker().hide();
17213 this.fireEvent('hide', this, this.date);
17217 onMousedown: function(e)
17219 e.stopPropagation();
17220 e.preventDefault();
17225 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17229 fireKey: function(e)
17231 if (!this.picker().isVisible()){
17232 if (e.keyCode == 27) // allow escape to hide and re-show picker
17242 e.preventDefault();
17246 dir = e.keyCode == 37 ? -1 : 1;
17248 this.vIndex = this.vIndex + dir;
17250 if(this.vIndex < 0){
17254 if(this.vIndex > 11){
17258 if(isNaN(this.vIndex)){
17262 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17268 dir = e.keyCode == 38 ? -1 : 1;
17270 this.vIndex = this.vIndex + dir * 4;
17272 if(this.vIndex < 0){
17276 if(this.vIndex > 11){
17280 if(isNaN(this.vIndex)){
17284 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17289 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17290 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17294 e.preventDefault();
17297 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17298 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17314 this.picker().remove();
17319 Roo.apply(Roo.bootstrap.MonthField, {
17338 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17339 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17344 Roo.apply(Roo.bootstrap.MonthField, {
17348 cls: 'datepicker dropdown-menu roo-dynamic',
17352 cls: 'datepicker-months',
17356 cls: 'table-condensed',
17358 Roo.bootstrap.DateField.content
17378 * @class Roo.bootstrap.CheckBox
17379 * @extends Roo.bootstrap.Input
17380 * Bootstrap CheckBox class
17382 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17383 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17384 * @cfg {String} boxLabel The text that appears beside the checkbox
17385 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17386 * @cfg {Boolean} checked initnal the element
17387 * @cfg {Boolean} inline inline the element (default false)
17388 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17391 * Create a new CheckBox
17392 * @param {Object} config The config object
17395 Roo.bootstrap.CheckBox = function(config){
17396 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17401 * Fires when the element is checked or unchecked.
17402 * @param {Roo.bootstrap.CheckBox} this This input
17403 * @param {Boolean} checked The new checked value
17410 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17412 inputType: 'checkbox',
17420 getAutoCreate : function()
17422 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17428 cfg.cls = 'form-group ' + this.inputType; //input-group
17431 cfg.cls += ' ' + this.inputType + '-inline';
17437 type : this.inputType,
17438 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17439 cls : 'roo-' + this.inputType, //'form-box',
17440 placeholder : this.placeholder || ''
17444 if (this.weight) { // Validity check?
17445 cfg.cls += " " + this.inputType + "-" + this.weight;
17448 if (this.disabled) {
17449 input.disabled=true;
17453 input.checked = this.checked;
17457 input.name = this.name;
17461 input.cls += ' input-' + this.size;
17466 ['xs','sm','md','lg'].map(function(size){
17467 if (settings[size]) {
17468 cfg.cls += ' col-' + size + '-' + settings[size];
17472 var inputblock = input;
17474 if (this.before || this.after) {
17477 cls : 'input-group',
17482 inputblock.cn.push({
17484 cls : 'input-group-addon',
17489 inputblock.cn.push(input);
17492 inputblock.cn.push({
17494 cls : 'input-group-addon',
17501 if (align ==='left' && this.fieldLabel.length) {
17502 Roo.log("left and has label");
17508 cls : 'control-label col-md-' + this.labelWidth,
17509 html : this.fieldLabel
17513 cls : "col-md-" + (12 - this.labelWidth),
17520 } else if ( this.fieldLabel.length) {
17525 tag: this.boxLabel ? 'span' : 'label',
17527 cls: 'control-label box-input-label',
17528 //cls : 'input-group-addon',
17529 html : this.fieldLabel
17539 Roo.log(" no label && no align");
17540 cfg.cn = [ inputblock ] ;
17545 var boxLabelCfg = {
17547 //'for': id, // box label is handled by onclick - so no for...
17549 html: this.boxLabel
17553 boxLabelCfg.tooltip = this.tooltip;
17556 cfg.cn.push(boxLabelCfg);
17566 * return the real input element.
17568 inputEl: function ()
17570 return this.el.select('input.roo-' + this.inputType,true).first();
17573 labelEl: function()
17575 return this.el.select('label.control-label',true).first();
17577 /* depricated... */
17581 return this.labelEl();
17584 initEvents : function()
17586 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17588 this.inputEl().on('click', this.onClick, this);
17590 if (this.boxLabel) {
17591 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17594 this.startValue = this.getValue();
17597 Roo.bootstrap.CheckBox.register(this);
17601 onClick : function()
17603 this.setChecked(!this.checked);
17606 setChecked : function(state,suppressEvent)
17608 this.startValue = this.getValue();
17610 if(this.inputType == 'radio'){
17612 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17613 e.dom.checked = false;
17616 this.inputEl().dom.checked = true;
17618 this.inputEl().dom.value = this.inputValue;
17620 if(suppressEvent !== true){
17621 this.fireEvent('check', this, true);
17629 this.checked = state;
17631 this.inputEl().dom.checked = state;
17633 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17635 if(suppressEvent !== true){
17636 this.fireEvent('check', this, state);
17642 getValue : function()
17644 if(this.inputType == 'radio'){
17645 return this.getGroupValue();
17648 return this.inputEl().getValue();
17652 getGroupValue : function()
17654 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17658 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17661 setValue : function(v,suppressEvent)
17663 if(this.inputType == 'radio'){
17664 this.setGroupValue(v, suppressEvent);
17668 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17673 setGroupValue : function(v, suppressEvent)
17675 this.startValue = this.getValue();
17677 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17678 e.dom.checked = false;
17680 if(e.dom.value == v){
17681 e.dom.checked = true;
17685 if(suppressEvent !== true){
17686 this.fireEvent('check', this, true);
17694 validate : function()
17698 (this.inputType == 'radio' && this.validateRadio()) ||
17699 (this.inputType == 'checkbox' && this.validateCheckbox())
17705 this.markInvalid();
17709 validateRadio : function()
17713 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17714 if(!e.dom.checked){
17726 validateCheckbox : function()
17729 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17732 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17740 for(var i in group){
17745 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17752 * Mark this field as valid
17754 markValid : function()
17756 if(this.allowBlank){
17762 this.fireEvent('valid', this);
17764 if(this.inputType == 'radio'){
17765 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17766 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17767 e.findParent('.form-group', false, true).addClass(_this.validClass);
17774 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17775 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17779 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17785 for(var i in group){
17786 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17787 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17792 * Mark this field as invalid
17793 * @param {String} msg The validation message
17795 markInvalid : function(msg)
17797 if(this.allowBlank){
17803 this.fireEvent('invalid', this, msg);
17805 if(this.inputType == 'radio'){
17806 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17807 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17808 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17815 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17816 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17820 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17826 for(var i in group){
17827 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17828 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17835 Roo.apply(Roo.bootstrap.CheckBox, {
17840 * register a CheckBox Group
17841 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17843 register : function(checkbox)
17845 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17846 this.groups[checkbox.groupId] = {};
17849 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17853 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17857 * fetch a CheckBox Group based on the group ID
17858 * @param {string} the group ID
17859 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17861 get: function(groupId) {
17862 if (typeof(this.groups[groupId]) == 'undefined') {
17866 return this.groups[groupId] ;
17878 *<div class="radio">
17880 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17881 Option one is this and that—be sure to include why it's great
17888 *<label class="radio-inline">fieldLabel</label>
17889 *<label class="radio-inline">
17890 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17898 * @class Roo.bootstrap.Radio
17899 * @extends Roo.bootstrap.CheckBox
17900 * Bootstrap Radio class
17903 * Create a new Radio
17904 * @param {Object} config The config object
17907 Roo.bootstrap.Radio = function(config){
17908 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17912 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17914 inputType: 'radio',
17918 getAutoCreate : function()
17920 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17921 align = align || 'left'; // default...
17928 tag : this.inline ? 'span' : 'div',
17933 var inline = this.inline ? ' radio-inline' : '';
17937 // does not need for, as we wrap the input with it..
17939 cls : 'control-label box-label' + inline,
17942 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17946 //cls : 'control-label' + inline,
17947 html : this.fieldLabel,
17948 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17957 type : this.inputType,
17958 //value : (!this.checked) ? this.valueOff : this.inputValue,
17959 value : this.inputValue,
17961 placeholder : this.placeholder || '' // ?? needed????
17964 if (this.weight) { // Validity check?
17965 input.cls += " radio-" + this.weight;
17967 if (this.disabled) {
17968 input.disabled=true;
17972 input.checked = this.checked;
17976 input.name = this.name;
17980 input.cls += ' input-' + this.size;
17983 //?? can span's inline have a width??
17986 ['xs','sm','md','lg'].map(function(size){
17987 if (settings[size]) {
17988 cfg.cls += ' col-' + size + '-' + settings[size];
17992 var inputblock = input;
17994 if (this.before || this.after) {
17997 cls : 'input-group',
18002 inputblock.cn.push({
18004 cls : 'input-group-addon',
18008 inputblock.cn.push(input);
18010 inputblock.cn.push({
18012 cls : 'input-group-addon',
18020 if (this.fieldLabel && this.fieldLabel.length) {
18021 cfg.cn.push(fieldLabel);
18024 // normal bootstrap puts the input inside the label.
18025 // however with our styled version - it has to go after the input.
18027 //lbl.cn.push(inputblock);
18031 cls: 'radio' + inline,
18038 cfg.cn.push( lblwrap);
18043 html: this.boxLabel
18052 initEvents : function()
18054 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18056 this.inputEl().on('click', this.onClick, this);
18057 if (this.boxLabel) {
18058 Roo.log('find label')
18059 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18064 inputEl: function ()
18066 return this.el.select('input.roo-radio',true).first();
18068 onClick : function()
18071 this.setChecked(true);
18074 setChecked : function(state,suppressEvent)
18077 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18078 v.dom.checked = false;
18081 Roo.log(this.inputEl().dom);
18082 this.checked = state;
18083 this.inputEl().dom.checked = state;
18085 if(suppressEvent !== true){
18086 this.fireEvent('check', this, state);
18089 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18093 getGroupValue : function()
18096 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18097 if(v.dom.checked == true){
18098 value = v.dom.value;
18106 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18107 * @return {Mixed} value The field value
18109 getValue : function(){
18110 return this.getGroupValue();
18116 //<script type="text/javascript">
18119 * Based Ext JS Library 1.1.1
18120 * Copyright(c) 2006-2007, Ext JS, LLC.
18126 * @class Roo.HtmlEditorCore
18127 * @extends Roo.Component
18128 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18130 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18133 Roo.HtmlEditorCore = function(config){
18136 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18141 * @event initialize
18142 * Fires when the editor is fully initialized (including the iframe)
18143 * @param {Roo.HtmlEditorCore} this
18148 * Fires when the editor is first receives the focus. Any insertion must wait
18149 * until after this event.
18150 * @param {Roo.HtmlEditorCore} this
18154 * @event beforesync
18155 * Fires before the textarea is updated with content from the editor iframe. Return false
18156 * to cancel the sync.
18157 * @param {Roo.HtmlEditorCore} this
18158 * @param {String} html
18162 * @event beforepush
18163 * Fires before the iframe editor is updated with content from the textarea. Return false
18164 * to cancel the push.
18165 * @param {Roo.HtmlEditorCore} this
18166 * @param {String} html
18171 * Fires when the textarea is updated with content from the editor iframe.
18172 * @param {Roo.HtmlEditorCore} this
18173 * @param {String} html
18178 * Fires when the iframe editor is updated with content from the textarea.
18179 * @param {Roo.HtmlEditorCore} this
18180 * @param {String} html
18185 * @event editorevent
18186 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18187 * @param {Roo.HtmlEditorCore} this
18193 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18195 // defaults : white / black...
18196 this.applyBlacklists();
18203 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18207 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18213 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18218 * @cfg {Number} height (in pixels)
18222 * @cfg {Number} width (in pixels)
18227 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18230 stylesheets: false,
18235 // private properties
18236 validationEvent : false,
18238 initialized : false,
18240 sourceEditMode : false,
18241 onFocus : Roo.emptyFn,
18243 hideMode:'offsets',
18247 // blacklist + whitelisted elements..
18254 * Protected method that will not generally be called directly. It
18255 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18256 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18258 getDocMarkup : function(){
18262 // inherit styels from page...??
18263 if (this.stylesheets === false) {
18265 Roo.get(document.head).select('style').each(function(node) {
18266 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18269 Roo.get(document.head).select('link').each(function(node) {
18270 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18273 } else if (!this.stylesheets.length) {
18275 st = '<style type="text/css">' +
18276 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18282 st += '<style type="text/css">' +
18283 'IMG { cursor: pointer } ' +
18287 return '<html><head>' + st +
18288 //<style type="text/css">' +
18289 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18291 ' </head><body class="roo-htmleditor-body"></body></html>';
18295 onRender : function(ct, position)
18298 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18299 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18302 this.el.dom.style.border = '0 none';
18303 this.el.dom.setAttribute('tabIndex', -1);
18304 this.el.addClass('x-hidden hide');
18308 if(Roo.isIE){ // fix IE 1px bogus margin
18309 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18313 this.frameId = Roo.id();
18317 var iframe = this.owner.wrap.createChild({
18319 cls: 'form-control', // bootstrap..
18321 name: this.frameId,
18322 frameBorder : 'no',
18323 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18328 this.iframe = iframe.dom;
18330 this.assignDocWin();
18332 this.doc.designMode = 'on';
18335 this.doc.write(this.getDocMarkup());
18339 var task = { // must defer to wait for browser to be ready
18341 //console.log("run task?" + this.doc.readyState);
18342 this.assignDocWin();
18343 if(this.doc.body || this.doc.readyState == 'complete'){
18345 this.doc.designMode="on";
18349 Roo.TaskMgr.stop(task);
18350 this.initEditor.defer(10, this);
18357 Roo.TaskMgr.start(task);
18362 onResize : function(w, h)
18364 Roo.log('resize: ' +w + ',' + h );
18365 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18369 if(typeof w == 'number'){
18371 this.iframe.style.width = w + 'px';
18373 if(typeof h == 'number'){
18375 this.iframe.style.height = h + 'px';
18377 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18384 * Toggles the editor between standard and source edit mode.
18385 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18387 toggleSourceEdit : function(sourceEditMode){
18389 this.sourceEditMode = sourceEditMode === true;
18391 if(this.sourceEditMode){
18393 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18396 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18397 //this.iframe.className = '';
18400 //this.setSize(this.owner.wrap.getSize());
18401 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18408 * Protected method that will not generally be called directly. If you need/want
18409 * custom HTML cleanup, this is the method you should override.
18410 * @param {String} html The HTML to be cleaned
18411 * return {String} The cleaned HTML
18413 cleanHtml : function(html){
18414 html = String(html);
18415 if(html.length > 5){
18416 if(Roo.isSafari){ // strip safari nonsense
18417 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18420 if(html == ' '){
18427 * HTML Editor -> Textarea
18428 * Protected method that will not generally be called directly. Syncs the contents
18429 * of the editor iframe with the textarea.
18431 syncValue : function(){
18432 if(this.initialized){
18433 var bd = (this.doc.body || this.doc.documentElement);
18434 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18435 var html = bd.innerHTML;
18437 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18438 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18440 html = '<div style="'+m[0]+'">' + html + '</div>';
18443 html = this.cleanHtml(html);
18444 // fix up the special chars.. normaly like back quotes in word...
18445 // however we do not want to do this with chinese..
18446 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18447 var cc = b.charCodeAt();
18449 (cc >= 0x4E00 && cc < 0xA000 ) ||
18450 (cc >= 0x3400 && cc < 0x4E00 ) ||
18451 (cc >= 0xf900 && cc < 0xfb00 )
18457 if(this.owner.fireEvent('beforesync', this, html) !== false){
18458 this.el.dom.value = html;
18459 this.owner.fireEvent('sync', this, html);
18465 * Protected method that will not generally be called directly. Pushes the value of the textarea
18466 * into the iframe editor.
18468 pushValue : function(){
18469 if(this.initialized){
18470 var v = this.el.dom.value.trim();
18472 // if(v.length < 1){
18476 if(this.owner.fireEvent('beforepush', this, v) !== false){
18477 var d = (this.doc.body || this.doc.documentElement);
18479 this.cleanUpPaste();
18480 this.el.dom.value = d.innerHTML;
18481 this.owner.fireEvent('push', this, v);
18487 deferFocus : function(){
18488 this.focus.defer(10, this);
18492 focus : function(){
18493 if(this.win && !this.sourceEditMode){
18500 assignDocWin: function()
18502 var iframe = this.iframe;
18505 this.doc = iframe.contentWindow.document;
18506 this.win = iframe.contentWindow;
18508 // if (!Roo.get(this.frameId)) {
18511 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18512 // this.win = Roo.get(this.frameId).dom.contentWindow;
18514 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18518 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18519 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18524 initEditor : function(){
18525 //console.log("INIT EDITOR");
18526 this.assignDocWin();
18530 this.doc.designMode="on";
18532 this.doc.write(this.getDocMarkup());
18535 var dbody = (this.doc.body || this.doc.documentElement);
18536 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18537 // this copies styles from the containing element into thsi one..
18538 // not sure why we need all of this..
18539 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18541 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18542 //ss['background-attachment'] = 'fixed'; // w3c
18543 dbody.bgProperties = 'fixed'; // ie
18544 //Roo.DomHelper.applyStyles(dbody, ss);
18545 Roo.EventManager.on(this.doc, {
18546 //'mousedown': this.onEditorEvent,
18547 'mouseup': this.onEditorEvent,
18548 'dblclick': this.onEditorEvent,
18549 'click': this.onEditorEvent,
18550 'keyup': this.onEditorEvent,
18555 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18557 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18558 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18560 this.initialized = true;
18562 this.owner.fireEvent('initialize', this);
18567 onDestroy : function(){
18573 //for (var i =0; i < this.toolbars.length;i++) {
18574 // // fixme - ask toolbars for heights?
18575 // this.toolbars[i].onDestroy();
18578 //this.wrap.dom.innerHTML = '';
18579 //this.wrap.remove();
18584 onFirstFocus : function(){
18586 this.assignDocWin();
18589 this.activated = true;
18592 if(Roo.isGecko){ // prevent silly gecko errors
18594 var s = this.win.getSelection();
18595 if(!s.focusNode || s.focusNode.nodeType != 3){
18596 var r = s.getRangeAt(0);
18597 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18602 this.execCmd('useCSS', true);
18603 this.execCmd('styleWithCSS', false);
18606 this.owner.fireEvent('activate', this);
18610 adjustFont: function(btn){
18611 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18612 //if(Roo.isSafari){ // safari
18615 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18616 if(Roo.isSafari){ // safari
18617 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18618 v = (v < 10) ? 10 : v;
18619 v = (v > 48) ? 48 : v;
18620 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18625 v = Math.max(1, v+adjust);
18627 this.execCmd('FontSize', v );
18630 onEditorEvent : function(e)
18632 this.owner.fireEvent('editorevent', this, e);
18633 // this.updateToolbar();
18634 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18637 insertTag : function(tg)
18639 // could be a bit smarter... -> wrap the current selected tRoo..
18640 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18642 range = this.createRange(this.getSelection());
18643 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18644 wrappingNode.appendChild(range.extractContents());
18645 range.insertNode(wrappingNode);
18652 this.execCmd("formatblock", tg);
18656 insertText : function(txt)
18660 var range = this.createRange();
18661 range.deleteContents();
18662 //alert(Sender.getAttribute('label'));
18664 range.insertNode(this.doc.createTextNode(txt));
18670 * Executes a Midas editor command on the editor document and performs necessary focus and
18671 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18672 * @param {String} cmd The Midas command
18673 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18675 relayCmd : function(cmd, value){
18677 this.execCmd(cmd, value);
18678 this.owner.fireEvent('editorevent', this);
18679 //this.updateToolbar();
18680 this.owner.deferFocus();
18684 * Executes a Midas editor command directly on the editor document.
18685 * For visual commands, you should use {@link #relayCmd} instead.
18686 * <b>This should only be called after the editor is initialized.</b>
18687 * @param {String} cmd The Midas command
18688 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18690 execCmd : function(cmd, value){
18691 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18698 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18700 * @param {String} text | dom node..
18702 insertAtCursor : function(text)
18707 if(!this.activated){
18713 var r = this.doc.selection.createRange();
18724 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18728 // from jquery ui (MIT licenced)
18730 var win = this.win;
18732 if (win.getSelection && win.getSelection().getRangeAt) {
18733 range = win.getSelection().getRangeAt(0);
18734 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18735 range.insertNode(node);
18736 } else if (win.document.selection && win.document.selection.createRange) {
18737 // no firefox support
18738 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18739 win.document.selection.createRange().pasteHTML(txt);
18741 // no firefox support
18742 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18743 this.execCmd('InsertHTML', txt);
18752 mozKeyPress : function(e){
18754 var c = e.getCharCode(), cmd;
18757 c = String.fromCharCode(c).toLowerCase();
18771 this.cleanUpPaste.defer(100, this);
18779 e.preventDefault();
18787 fixKeys : function(){ // load time branching for fastest keydown performance
18789 return function(e){
18790 var k = e.getKey(), r;
18793 r = this.doc.selection.createRange();
18796 r.pasteHTML('    ');
18803 r = this.doc.selection.createRange();
18805 var target = r.parentElement();
18806 if(!target || target.tagName.toLowerCase() != 'li'){
18808 r.pasteHTML('<br />');
18814 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18815 this.cleanUpPaste.defer(100, this);
18821 }else if(Roo.isOpera){
18822 return function(e){
18823 var k = e.getKey();
18827 this.execCmd('InsertHTML','    ');
18830 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18831 this.cleanUpPaste.defer(100, this);
18836 }else if(Roo.isSafari){
18837 return function(e){
18838 var k = e.getKey();
18842 this.execCmd('InsertText','\t');
18846 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18847 this.cleanUpPaste.defer(100, this);
18855 getAllAncestors: function()
18857 var p = this.getSelectedNode();
18860 a.push(p); // push blank onto stack..
18861 p = this.getParentElement();
18865 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18869 a.push(this.doc.body);
18873 lastSelNode : false,
18876 getSelection : function()
18878 this.assignDocWin();
18879 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18882 getSelectedNode: function()
18884 // this may only work on Gecko!!!
18886 // should we cache this!!!!
18891 var range = this.createRange(this.getSelection()).cloneRange();
18894 var parent = range.parentElement();
18896 var testRange = range.duplicate();
18897 testRange.moveToElementText(parent);
18898 if (testRange.inRange(range)) {
18901 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18904 parent = parent.parentElement;
18909 // is ancestor a text element.
18910 var ac = range.commonAncestorContainer;
18911 if (ac.nodeType == 3) {
18912 ac = ac.parentNode;
18915 var ar = ac.childNodes;
18918 var other_nodes = [];
18919 var has_other_nodes = false;
18920 for (var i=0;i<ar.length;i++) {
18921 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18924 // fullly contained node.
18926 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18931 // probably selected..
18932 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18933 other_nodes.push(ar[i]);
18937 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18942 has_other_nodes = true;
18944 if (!nodes.length && other_nodes.length) {
18945 nodes= other_nodes;
18947 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18953 createRange: function(sel)
18955 // this has strange effects when using with
18956 // top toolbar - not sure if it's a great idea.
18957 //this.editor.contentWindow.focus();
18958 if (typeof sel != "undefined") {
18960 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18962 return this.doc.createRange();
18965 return this.doc.createRange();
18968 getParentElement: function()
18971 this.assignDocWin();
18972 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18974 var range = this.createRange(sel);
18977 var p = range.commonAncestorContainer;
18978 while (p.nodeType == 3) { // text node
18989 * Range intersection.. the hard stuff...
18993 * [ -- selected range --- ]
18997 * if end is before start or hits it. fail.
18998 * if start is after end or hits it fail.
19000 * if either hits (but other is outside. - then it's not
19006 // @see http://www.thismuchiknow.co.uk/?p=64.
19007 rangeIntersectsNode : function(range, node)
19009 var nodeRange = node.ownerDocument.createRange();
19011 nodeRange.selectNode(node);
19013 nodeRange.selectNodeContents(node);
19016 var rangeStartRange = range.cloneRange();
19017 rangeStartRange.collapse(true);
19019 var rangeEndRange = range.cloneRange();
19020 rangeEndRange.collapse(false);
19022 var nodeStartRange = nodeRange.cloneRange();
19023 nodeStartRange.collapse(true);
19025 var nodeEndRange = nodeRange.cloneRange();
19026 nodeEndRange.collapse(false);
19028 return rangeStartRange.compareBoundaryPoints(
19029 Range.START_TO_START, nodeEndRange) == -1 &&
19030 rangeEndRange.compareBoundaryPoints(
19031 Range.START_TO_START, nodeStartRange) == 1;
19035 rangeCompareNode : function(range, node)
19037 var nodeRange = node.ownerDocument.createRange();
19039 nodeRange.selectNode(node);
19041 nodeRange.selectNodeContents(node);
19045 range.collapse(true);
19047 nodeRange.collapse(true);
19049 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19050 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19052 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19054 var nodeIsBefore = ss == 1;
19055 var nodeIsAfter = ee == -1;
19057 if (nodeIsBefore && nodeIsAfter)
19059 if (!nodeIsBefore && nodeIsAfter)
19060 return 1; //right trailed.
19062 if (nodeIsBefore && !nodeIsAfter)
19063 return 2; // left trailed.
19068 // private? - in a new class?
19069 cleanUpPaste : function()
19071 // cleans up the whole document..
19072 Roo.log('cleanuppaste');
19074 this.cleanUpChildren(this.doc.body);
19075 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19076 if (clean != this.doc.body.innerHTML) {
19077 this.doc.body.innerHTML = clean;
19082 cleanWordChars : function(input) {// change the chars to hex code
19083 var he = Roo.HtmlEditorCore;
19085 var output = input;
19086 Roo.each(he.swapCodes, function(sw) {
19087 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19089 output = output.replace(swapper, sw[1]);
19096 cleanUpChildren : function (n)
19098 if (!n.childNodes.length) {
19101 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19102 this.cleanUpChild(n.childNodes[i]);
19109 cleanUpChild : function (node)
19112 //console.log(node);
19113 if (node.nodeName == "#text") {
19114 // clean up silly Windows -- stuff?
19117 if (node.nodeName == "#comment") {
19118 node.parentNode.removeChild(node);
19119 // clean up silly Windows -- stuff?
19122 var lcname = node.tagName.toLowerCase();
19123 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19124 // whitelist of tags..
19126 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19128 node.parentNode.removeChild(node);
19133 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19135 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19136 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19138 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19139 // remove_keep_children = true;
19142 if (remove_keep_children) {
19143 this.cleanUpChildren(node);
19144 // inserts everything just before this node...
19145 while (node.childNodes.length) {
19146 var cn = node.childNodes[0];
19147 node.removeChild(cn);
19148 node.parentNode.insertBefore(cn, node);
19150 node.parentNode.removeChild(node);
19154 if (!node.attributes || !node.attributes.length) {
19155 this.cleanUpChildren(node);
19159 function cleanAttr(n,v)
19162 if (v.match(/^\./) || v.match(/^\//)) {
19165 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19168 if (v.match(/^#/)) {
19171 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19172 node.removeAttribute(n);
19176 var cwhite = this.cwhite;
19177 var cblack = this.cblack;
19179 function cleanStyle(n,v)
19181 if (v.match(/expression/)) { //XSS?? should we even bother..
19182 node.removeAttribute(n);
19186 var parts = v.split(/;/);
19189 Roo.each(parts, function(p) {
19190 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19194 var l = p.split(':').shift().replace(/\s+/g,'');
19195 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19197 if ( cwhite.length && cblack.indexOf(l) > -1) {
19198 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19199 //node.removeAttribute(n);
19203 // only allow 'c whitelisted system attributes'
19204 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19205 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19206 //node.removeAttribute(n);
19216 if (clean.length) {
19217 node.setAttribute(n, clean.join(';'));
19219 node.removeAttribute(n);
19225 for (var i = node.attributes.length-1; i > -1 ; i--) {
19226 var a = node.attributes[i];
19229 if (a.name.toLowerCase().substr(0,2)=='on') {
19230 node.removeAttribute(a.name);
19233 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19234 node.removeAttribute(a.name);
19237 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19238 cleanAttr(a.name,a.value); // fixme..
19241 if (a.name == 'style') {
19242 cleanStyle(a.name,a.value);
19245 /// clean up MS crap..
19246 // tecnically this should be a list of valid class'es..
19249 if (a.name == 'class') {
19250 if (a.value.match(/^Mso/)) {
19251 node.className = '';
19254 if (a.value.match(/body/)) {
19255 node.className = '';
19266 this.cleanUpChildren(node);
19272 * Clean up MS wordisms...
19274 cleanWord : function(node)
19279 this.cleanWord(this.doc.body);
19282 if (node.nodeName == "#text") {
19283 // clean up silly Windows -- stuff?
19286 if (node.nodeName == "#comment") {
19287 node.parentNode.removeChild(node);
19288 // clean up silly Windows -- stuff?
19292 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19293 node.parentNode.removeChild(node);
19297 // remove - but keep children..
19298 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19299 while (node.childNodes.length) {
19300 var cn = node.childNodes[0];
19301 node.removeChild(cn);
19302 node.parentNode.insertBefore(cn, node);
19304 node.parentNode.removeChild(node);
19305 this.iterateChildren(node, this.cleanWord);
19309 if (node.className.length) {
19311 var cn = node.className.split(/\W+/);
19313 Roo.each(cn, function(cls) {
19314 if (cls.match(/Mso[a-zA-Z]+/)) {
19319 node.className = cna.length ? cna.join(' ') : '';
19321 node.removeAttribute("class");
19325 if (node.hasAttribute("lang")) {
19326 node.removeAttribute("lang");
19329 if (node.hasAttribute("style")) {
19331 var styles = node.getAttribute("style").split(";");
19333 Roo.each(styles, function(s) {
19334 if (!s.match(/:/)) {
19337 var kv = s.split(":");
19338 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19341 // what ever is left... we allow.
19344 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19345 if (!nstyle.length) {
19346 node.removeAttribute('style');
19349 this.iterateChildren(node, this.cleanWord);
19355 * iterateChildren of a Node, calling fn each time, using this as the scole..
19356 * @param {DomNode} node node to iterate children of.
19357 * @param {Function} fn method of this class to call on each item.
19359 iterateChildren : function(node, fn)
19361 if (!node.childNodes.length) {
19364 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19365 fn.call(this, node.childNodes[i])
19371 * cleanTableWidths.
19373 * Quite often pasting from word etc.. results in tables with column and widths.
19374 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19377 cleanTableWidths : function(node)
19382 this.cleanTableWidths(this.doc.body);
19387 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19390 Roo.log(node.tagName);
19391 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19392 this.iterateChildren(node, this.cleanTableWidths);
19395 if (node.hasAttribute('width')) {
19396 node.removeAttribute('width');
19400 if (node.hasAttribute("style")) {
19403 var styles = node.getAttribute("style").split(";");
19405 Roo.each(styles, function(s) {
19406 if (!s.match(/:/)) {
19409 var kv = s.split(":");
19410 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
19413 // what ever is left... we allow.
19416 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19417 if (!nstyle.length) {
19418 node.removeAttribute('style');
19422 this.iterateChildren(node, this.cleanTableWidths);
19430 domToHTML : function(currentElement, depth, nopadtext) {
19432 depth = depth || 0;
19433 nopadtext = nopadtext || false;
19435 if (!currentElement) {
19436 return this.domToHTML(this.doc.body);
19439 //Roo.log(currentElement);
19441 var allText = false;
19442 var nodeName = currentElement.nodeName;
19443 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19445 if (nodeName == '#text') {
19447 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19452 if (nodeName != 'BODY') {
19455 // Prints the node tagName, such as <A>, <IMG>, etc
19458 for(i = 0; i < currentElement.attributes.length;i++) {
19460 var aname = currentElement.attributes.item(i).name;
19461 if (!currentElement.attributes.item(i).value.length) {
19464 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19467 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19476 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19479 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19484 // Traverse the tree
19486 var currentElementChild = currentElement.childNodes.item(i);
19487 var allText = true;
19488 var innerHTML = '';
19490 while (currentElementChild) {
19491 // Formatting code (indent the tree so it looks nice on the screen)
19492 var nopad = nopadtext;
19493 if (lastnode == 'SPAN') {
19497 if (currentElementChild.nodeName == '#text') {
19498 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19499 toadd = nopadtext ? toadd : toadd.trim();
19500 if (!nopad && toadd.length > 80) {
19501 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19503 innerHTML += toadd;
19506 currentElementChild = currentElement.childNodes.item(i);
19512 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19514 // Recursively traverse the tree structure of the child node
19515 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19516 lastnode = currentElementChild.nodeName;
19518 currentElementChild=currentElement.childNodes.item(i);
19524 // The remaining code is mostly for formatting the tree
19525 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19530 ret+= "</"+tagName+">";
19536 applyBlacklists : function()
19538 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19539 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19543 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19544 if (b.indexOf(tag) > -1) {
19547 this.white.push(tag);
19551 Roo.each(w, function(tag) {
19552 if (b.indexOf(tag) > -1) {
19555 if (this.white.indexOf(tag) > -1) {
19558 this.white.push(tag);
19563 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19564 if (w.indexOf(tag) > -1) {
19567 this.black.push(tag);
19571 Roo.each(b, function(tag) {
19572 if (w.indexOf(tag) > -1) {
19575 if (this.black.indexOf(tag) > -1) {
19578 this.black.push(tag);
19583 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19584 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19588 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19589 if (b.indexOf(tag) > -1) {
19592 this.cwhite.push(tag);
19596 Roo.each(w, function(tag) {
19597 if (b.indexOf(tag) > -1) {
19600 if (this.cwhite.indexOf(tag) > -1) {
19603 this.cwhite.push(tag);
19608 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19609 if (w.indexOf(tag) > -1) {
19612 this.cblack.push(tag);
19616 Roo.each(b, function(tag) {
19617 if (w.indexOf(tag) > -1) {
19620 if (this.cblack.indexOf(tag) > -1) {
19623 this.cblack.push(tag);
19628 setStylesheets : function(stylesheets)
19630 if(typeof(stylesheets) == 'string'){
19631 Roo.get(this.iframe.contentDocument.head).createChild({
19633 rel : 'stylesheet',
19642 Roo.each(stylesheets, function(s) {
19647 Roo.get(_this.iframe.contentDocument.head).createChild({
19649 rel : 'stylesheet',
19658 removeStylesheets : function()
19662 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19667 // hide stuff that is not compatible
19681 * @event specialkey
19685 * @cfg {String} fieldClass @hide
19688 * @cfg {String} focusClass @hide
19691 * @cfg {String} autoCreate @hide
19694 * @cfg {String} inputType @hide
19697 * @cfg {String} invalidClass @hide
19700 * @cfg {String} invalidText @hide
19703 * @cfg {String} msgFx @hide
19706 * @cfg {String} validateOnBlur @hide
19710 Roo.HtmlEditorCore.white = [
19711 'area', 'br', 'img', 'input', 'hr', 'wbr',
19713 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19714 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19715 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19716 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19717 'table', 'ul', 'xmp',
19719 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19722 'dir', 'menu', 'ol', 'ul', 'dl',
19728 Roo.HtmlEditorCore.black = [
19729 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19731 'base', 'basefont', 'bgsound', 'blink', 'body',
19732 'frame', 'frameset', 'head', 'html', 'ilayer',
19733 'iframe', 'layer', 'link', 'meta', 'object',
19734 'script', 'style' ,'title', 'xml' // clean later..
19736 Roo.HtmlEditorCore.clean = [
19737 'script', 'style', 'title', 'xml'
19739 Roo.HtmlEditorCore.remove = [
19744 Roo.HtmlEditorCore.ablack = [
19748 Roo.HtmlEditorCore.aclean = [
19749 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19753 Roo.HtmlEditorCore.pwhite= [
19754 'http', 'https', 'mailto'
19757 // white listed style attributes.
19758 Roo.HtmlEditorCore.cwhite= [
19759 // 'text-align', /// default is to allow most things..
19765 // black listed style attributes.
19766 Roo.HtmlEditorCore.cblack= [
19767 // 'font-size' -- this can be set by the project
19771 Roo.HtmlEditorCore.swapCodes =[
19790 * @class Roo.bootstrap.HtmlEditor
19791 * @extends Roo.bootstrap.TextArea
19792 * Bootstrap HtmlEditor class
19795 * Create a new HtmlEditor
19796 * @param {Object} config The config object
19799 Roo.bootstrap.HtmlEditor = function(config){
19800 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19801 if (!this.toolbars) {
19802 this.toolbars = [];
19804 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19807 * @event initialize
19808 * Fires when the editor is fully initialized (including the iframe)
19809 * @param {HtmlEditor} this
19814 * Fires when the editor is first receives the focus. Any insertion must wait
19815 * until after this event.
19816 * @param {HtmlEditor} this
19820 * @event beforesync
19821 * Fires before the textarea is updated with content from the editor iframe. Return false
19822 * to cancel the sync.
19823 * @param {HtmlEditor} this
19824 * @param {String} html
19828 * @event beforepush
19829 * Fires before the iframe editor is updated with content from the textarea. Return false
19830 * to cancel the push.
19831 * @param {HtmlEditor} this
19832 * @param {String} html
19837 * Fires when the textarea is updated with content from the editor iframe.
19838 * @param {HtmlEditor} this
19839 * @param {String} html
19844 * Fires when the iframe editor is updated with content from the textarea.
19845 * @param {HtmlEditor} this
19846 * @param {String} html
19850 * @event editmodechange
19851 * Fires when the editor switches edit modes
19852 * @param {HtmlEditor} this
19853 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19855 editmodechange: true,
19857 * @event editorevent
19858 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19859 * @param {HtmlEditor} this
19863 * @event firstfocus
19864 * Fires when on first focus - needed by toolbars..
19865 * @param {HtmlEditor} this
19870 * Auto save the htmlEditor value as a file into Events
19871 * @param {HtmlEditor} this
19875 * @event savedpreview
19876 * preview the saved version of htmlEditor
19877 * @param {HtmlEditor} this
19884 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19888 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19893 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19898 * @cfg {Number} height (in pixels)
19902 * @cfg {Number} width (in pixels)
19907 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19910 stylesheets: false,
19915 // private properties
19916 validationEvent : false,
19918 initialized : false,
19921 onFocus : Roo.emptyFn,
19923 hideMode:'offsets',
19926 tbContainer : false,
19928 toolbarContainer :function() {
19929 return this.wrap.select('.x-html-editor-tb',true).first();
19933 * Protected method that will not generally be called directly. It
19934 * is called when the editor creates its toolbar. Override this method if you need to
19935 * add custom toolbar buttons.
19936 * @param {HtmlEditor} editor
19938 createToolbar : function(){
19940 Roo.log("create toolbars");
19942 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19943 this.toolbars[0].render(this.toolbarContainer());
19947 // if (!editor.toolbars || !editor.toolbars.length) {
19948 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19951 // for (var i =0 ; i < editor.toolbars.length;i++) {
19952 // editor.toolbars[i] = Roo.factory(
19953 // typeof(editor.toolbars[i]) == 'string' ?
19954 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19955 // Roo.bootstrap.HtmlEditor);
19956 // editor.toolbars[i].init(editor);
19962 onRender : function(ct, position)
19964 // Roo.log("Call onRender: " + this.xtype);
19966 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19968 this.wrap = this.inputEl().wrap({
19969 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19972 this.editorcore.onRender(ct, position);
19974 if (this.resizable) {
19975 this.resizeEl = new Roo.Resizable(this.wrap, {
19979 minHeight : this.height,
19980 height: this.height,
19981 handles : this.resizable,
19984 resize : function(r, w, h) {
19985 _t.onResize(w,h); // -something
19991 this.createToolbar(this);
19994 if(!this.width && this.resizable){
19995 this.setSize(this.wrap.getSize());
19997 if (this.resizeEl) {
19998 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19999 // should trigger onReize..
20005 onResize : function(w, h)
20007 Roo.log('resize: ' +w + ',' + h );
20008 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20012 if(this.inputEl() ){
20013 if(typeof w == 'number'){
20014 var aw = w - this.wrap.getFrameWidth('lr');
20015 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20018 if(typeof h == 'number'){
20019 var tbh = -11; // fixme it needs to tool bar size!
20020 for (var i =0; i < this.toolbars.length;i++) {
20021 // fixme - ask toolbars for heights?
20022 tbh += this.toolbars[i].el.getHeight();
20023 //if (this.toolbars[i].footer) {
20024 // tbh += this.toolbars[i].footer.el.getHeight();
20032 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20033 ah -= 5; // knock a few pixes off for look..
20034 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20038 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20039 this.editorcore.onResize(ew,eh);
20044 * Toggles the editor between standard and source edit mode.
20045 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20047 toggleSourceEdit : function(sourceEditMode)
20049 this.editorcore.toggleSourceEdit(sourceEditMode);
20051 if(this.editorcore.sourceEditMode){
20052 Roo.log('editor - showing textarea');
20055 // Roo.log(this.syncValue());
20057 this.inputEl().removeClass(['hide', 'x-hidden']);
20058 this.inputEl().dom.removeAttribute('tabIndex');
20059 this.inputEl().focus();
20061 Roo.log('editor - hiding textarea');
20063 // Roo.log(this.pushValue());
20066 this.inputEl().addClass(['hide', 'x-hidden']);
20067 this.inputEl().dom.setAttribute('tabIndex', -1);
20068 //this.deferFocus();
20071 if(this.resizable){
20072 this.setSize(this.wrap.getSize());
20075 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20078 // private (for BoxComponent)
20079 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20081 // private (for BoxComponent)
20082 getResizeEl : function(){
20086 // private (for BoxComponent)
20087 getPositionEl : function(){
20092 initEvents : function(){
20093 this.originalValue = this.getValue();
20097 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20100 // markInvalid : Roo.emptyFn,
20102 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20105 // clearInvalid : Roo.emptyFn,
20107 setValue : function(v){
20108 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20109 this.editorcore.pushValue();
20114 deferFocus : function(){
20115 this.focus.defer(10, this);
20119 focus : function(){
20120 this.editorcore.focus();
20126 onDestroy : function(){
20132 for (var i =0; i < this.toolbars.length;i++) {
20133 // fixme - ask toolbars for heights?
20134 this.toolbars[i].onDestroy();
20137 this.wrap.dom.innerHTML = '';
20138 this.wrap.remove();
20143 onFirstFocus : function(){
20144 //Roo.log("onFirstFocus");
20145 this.editorcore.onFirstFocus();
20146 for (var i =0; i < this.toolbars.length;i++) {
20147 this.toolbars[i].onFirstFocus();
20153 syncValue : function()
20155 this.editorcore.syncValue();
20158 pushValue : function()
20160 this.editorcore.pushValue();
20164 // hide stuff that is not compatible
20178 * @event specialkey
20182 * @cfg {String} fieldClass @hide
20185 * @cfg {String} focusClass @hide
20188 * @cfg {String} autoCreate @hide
20191 * @cfg {String} inputType @hide
20194 * @cfg {String} invalidClass @hide
20197 * @cfg {String} invalidText @hide
20200 * @cfg {String} msgFx @hide
20203 * @cfg {String} validateOnBlur @hide
20212 Roo.namespace('Roo.bootstrap.htmleditor');
20214 * @class Roo.bootstrap.HtmlEditorToolbar1
20219 new Roo.bootstrap.HtmlEditor({
20222 new Roo.bootstrap.HtmlEditorToolbar1({
20223 disable : { fonts: 1 , format: 1, ..., ... , ...],
20229 * @cfg {Object} disable List of elements to disable..
20230 * @cfg {Array} btns List of additional buttons.
20234 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20237 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20240 Roo.apply(this, config);
20242 // default disabled, based on 'good practice'..
20243 this.disable = this.disable || {};
20244 Roo.applyIf(this.disable, {
20247 specialElements : true
20249 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20251 this.editor = config.editor;
20252 this.editorcore = config.editor.editorcore;
20254 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20256 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20257 // dont call parent... till later.
20259 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20264 editorcore : false,
20269 "h1","h2","h3","h4","h5","h6",
20271 "abbr", "acronym", "address", "cite", "samp", "var",
20275 onRender : function(ct, position)
20277 // Roo.log("Call onRender: " + this.xtype);
20279 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20281 this.el.dom.style.marginBottom = '0';
20283 var editorcore = this.editorcore;
20284 var editor= this.editor;
20287 var btn = function(id,cmd , toggle, handler){
20289 var event = toggle ? 'toggle' : 'click';
20294 xns: Roo.bootstrap,
20297 enableToggle:toggle !== false,
20299 pressed : toggle ? false : null,
20302 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20303 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20312 xns: Roo.bootstrap,
20313 glyphicon : 'font',
20317 xns: Roo.bootstrap,
20321 Roo.each(this.formats, function(f) {
20322 style.menu.items.push({
20324 xns: Roo.bootstrap,
20325 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20330 editorcore.insertTag(this.tagname);
20337 children.push(style);
20340 btn('bold',false,true);
20341 btn('italic',false,true);
20342 btn('align-left', 'justifyleft',true);
20343 btn('align-center', 'justifycenter',true);
20344 btn('align-right' , 'justifyright',true);
20345 btn('link', false, false, function(btn) {
20346 //Roo.log("create link?");
20347 var url = prompt(this.createLinkText, this.defaultLinkValue);
20348 if(url && url != 'http:/'+'/'){
20349 this.editorcore.relayCmd('createlink', url);
20352 btn('list','insertunorderedlist',true);
20353 btn('pencil', false,true, function(btn){
20356 this.toggleSourceEdit(btn.pressed);
20362 xns: Roo.bootstrap,
20367 xns: Roo.bootstrap,
20372 cog.menu.items.push({
20374 xns: Roo.bootstrap,
20375 html : Clean styles,
20380 editorcore.insertTag(this.tagname);
20389 this.xtype = 'NavSimplebar';
20391 for(var i=0;i< children.length;i++) {
20393 this.buttons.add(this.addxtypeChild(children[i]));
20397 editor.on('editorevent', this.updateToolbar, this);
20399 onBtnClick : function(id)
20401 this.editorcore.relayCmd(id);
20402 this.editorcore.focus();
20406 * Protected method that will not generally be called directly. It triggers
20407 * a toolbar update by reading the markup state of the current selection in the editor.
20409 updateToolbar: function(){
20411 if(!this.editorcore.activated){
20412 this.editor.onFirstFocus(); // is this neeed?
20416 var btns = this.buttons;
20417 var doc = this.editorcore.doc;
20418 btns.get('bold').setActive(doc.queryCommandState('bold'));
20419 btns.get('italic').setActive(doc.queryCommandState('italic'));
20420 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20422 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20423 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20424 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20426 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20427 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20430 var ans = this.editorcore.getAllAncestors();
20431 if (this.formatCombo) {
20434 var store = this.formatCombo.store;
20435 this.formatCombo.setValue("");
20436 for (var i =0; i < ans.length;i++) {
20437 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20439 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20447 // hides menus... - so this cant be on a menu...
20448 Roo.bootstrap.MenuMgr.hideAll();
20450 Roo.bootstrap.MenuMgr.hideAll();
20451 //this.editorsyncValue();
20453 onFirstFocus: function() {
20454 this.buttons.each(function(item){
20458 toggleSourceEdit : function(sourceEditMode){
20461 if(sourceEditMode){
20462 Roo.log("disabling buttons");
20463 this.buttons.each( function(item){
20464 if(item.cmd != 'pencil'){
20470 Roo.log("enabling buttons");
20471 if(this.editorcore.initialized){
20472 this.buttons.each( function(item){
20478 Roo.log("calling toggole on editor");
20479 // tell the editor that it's been pressed..
20480 this.editor.toggleSourceEdit(sourceEditMode);
20490 * @class Roo.bootstrap.Table.AbstractSelectionModel
20491 * @extends Roo.util.Observable
20492 * Abstract base class for grid SelectionModels. It provides the interface that should be
20493 * implemented by descendant classes. This class should not be directly instantiated.
20496 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20497 this.locked = false;
20498 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20502 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20503 /** @ignore Called by the grid automatically. Do not call directly. */
20504 init : function(grid){
20510 * Locks the selections.
20513 this.locked = true;
20517 * Unlocks the selections.
20519 unlock : function(){
20520 this.locked = false;
20524 * Returns true if the selections are locked.
20525 * @return {Boolean}
20527 isLocked : function(){
20528 return this.locked;
20532 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20533 * @class Roo.bootstrap.Table.RowSelectionModel
20534 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20535 * It supports multiple selections and keyboard selection/navigation.
20537 * @param {Object} config
20540 Roo.bootstrap.Table.RowSelectionModel = function(config){
20541 Roo.apply(this, config);
20542 this.selections = new Roo.util.MixedCollection(false, function(o){
20547 this.lastActive = false;
20551 * @event selectionchange
20552 * Fires when the selection changes
20553 * @param {SelectionModel} this
20555 "selectionchange" : true,
20557 * @event afterselectionchange
20558 * Fires after the selection changes (eg. by key press or clicking)
20559 * @param {SelectionModel} this
20561 "afterselectionchange" : true,
20563 * @event beforerowselect
20564 * Fires when a row is selected being selected, return false to cancel.
20565 * @param {SelectionModel} this
20566 * @param {Number} rowIndex The selected index
20567 * @param {Boolean} keepExisting False if other selections will be cleared
20569 "beforerowselect" : true,
20572 * Fires when a row is selected.
20573 * @param {SelectionModel} this
20574 * @param {Number} rowIndex The selected index
20575 * @param {Roo.data.Record} r The record
20577 "rowselect" : true,
20579 * @event rowdeselect
20580 * Fires when a row is deselected.
20581 * @param {SelectionModel} this
20582 * @param {Number} rowIndex The selected index
20584 "rowdeselect" : true
20586 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20587 this.locked = false;
20590 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20592 * @cfg {Boolean} singleSelect
20593 * True to allow selection of only one row at a time (defaults to false)
20595 singleSelect : false,
20598 initEvents : function(){
20600 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20601 this.grid.on("mousedown", this.handleMouseDown, this);
20602 }else{ // allow click to work like normal
20603 this.grid.on("rowclick", this.handleDragableRowClick, this);
20606 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20607 "up" : function(e){
20609 this.selectPrevious(e.shiftKey);
20610 }else if(this.last !== false && this.lastActive !== false){
20611 var last = this.last;
20612 this.selectRange(this.last, this.lastActive-1);
20613 this.grid.getView().focusRow(this.lastActive);
20614 if(last !== false){
20618 this.selectFirstRow();
20620 this.fireEvent("afterselectionchange", this);
20622 "down" : function(e){
20624 this.selectNext(e.shiftKey);
20625 }else if(this.last !== false && this.lastActive !== false){
20626 var last = this.last;
20627 this.selectRange(this.last, this.lastActive+1);
20628 this.grid.getView().focusRow(this.lastActive);
20629 if(last !== false){
20633 this.selectFirstRow();
20635 this.fireEvent("afterselectionchange", this);
20640 var view = this.grid.view;
20641 view.on("refresh", this.onRefresh, this);
20642 view.on("rowupdated", this.onRowUpdated, this);
20643 view.on("rowremoved", this.onRemove, this);
20647 onRefresh : function(){
20648 var ds = this.grid.dataSource, i, v = this.grid.view;
20649 var s = this.selections;
20650 s.each(function(r){
20651 if((i = ds.indexOfId(r.id)) != -1){
20660 onRemove : function(v, index, r){
20661 this.selections.remove(r);
20665 onRowUpdated : function(v, index, r){
20666 if(this.isSelected(r)){
20667 v.onRowSelect(index);
20673 * @param {Array} records The records to select
20674 * @param {Boolean} keepExisting (optional) True to keep existing selections
20676 selectRecords : function(records, keepExisting){
20678 this.clearSelections();
20680 var ds = this.grid.dataSource;
20681 for(var i = 0, len = records.length; i < len; i++){
20682 this.selectRow(ds.indexOf(records[i]), true);
20687 * Gets the number of selected rows.
20690 getCount : function(){
20691 return this.selections.length;
20695 * Selects the first row in the grid.
20697 selectFirstRow : function(){
20702 * Select the last row.
20703 * @param {Boolean} keepExisting (optional) True to keep existing selections
20705 selectLastRow : function(keepExisting){
20706 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20710 * Selects the row immediately following the last selected row.
20711 * @param {Boolean} keepExisting (optional) True to keep existing selections
20713 selectNext : function(keepExisting){
20714 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20715 this.selectRow(this.last+1, keepExisting);
20716 this.grid.getView().focusRow(this.last);
20721 * Selects the row that precedes the last selected row.
20722 * @param {Boolean} keepExisting (optional) True to keep existing selections
20724 selectPrevious : function(keepExisting){
20726 this.selectRow(this.last-1, keepExisting);
20727 this.grid.getView().focusRow(this.last);
20732 * Returns the selected records
20733 * @return {Array} Array of selected records
20735 getSelections : function(){
20736 return [].concat(this.selections.items);
20740 * Returns the first selected record.
20743 getSelected : function(){
20744 return this.selections.itemAt(0);
20749 * Clears all selections.
20751 clearSelections : function(fast){
20752 if(this.locked) return;
20754 var ds = this.grid.dataSource;
20755 var s = this.selections;
20756 s.each(function(r){
20757 this.deselectRow(ds.indexOfId(r.id));
20761 this.selections.clear();
20768 * Selects all rows.
20770 selectAll : function(){
20771 if(this.locked) return;
20772 this.selections.clear();
20773 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20774 this.selectRow(i, true);
20779 * Returns True if there is a selection.
20780 * @return {Boolean}
20782 hasSelection : function(){
20783 return this.selections.length > 0;
20787 * Returns True if the specified row is selected.
20788 * @param {Number/Record} record The record or index of the record to check
20789 * @return {Boolean}
20791 isSelected : function(index){
20792 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20793 return (r && this.selections.key(r.id) ? true : false);
20797 * Returns True if the specified record id is selected.
20798 * @param {String} id The id of record to check
20799 * @return {Boolean}
20801 isIdSelected : function(id){
20802 return (this.selections.key(id) ? true : false);
20806 handleMouseDown : function(e, t){
20807 var view = this.grid.getView(), rowIndex;
20808 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20811 if(e.shiftKey && this.last !== false){
20812 var last = this.last;
20813 this.selectRange(last, rowIndex, e.ctrlKey);
20814 this.last = last; // reset the last
20815 view.focusRow(rowIndex);
20817 var isSelected = this.isSelected(rowIndex);
20818 if(e.button !== 0 && isSelected){
20819 view.focusRow(rowIndex);
20820 }else if(e.ctrlKey && isSelected){
20821 this.deselectRow(rowIndex);
20822 }else if(!isSelected){
20823 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20824 view.focusRow(rowIndex);
20827 this.fireEvent("afterselectionchange", this);
20830 handleDragableRowClick : function(grid, rowIndex, e)
20832 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20833 this.selectRow(rowIndex, false);
20834 grid.view.focusRow(rowIndex);
20835 this.fireEvent("afterselectionchange", this);
20840 * Selects multiple rows.
20841 * @param {Array} rows Array of the indexes of the row to select
20842 * @param {Boolean} keepExisting (optional) True to keep existing selections
20844 selectRows : function(rows, keepExisting){
20846 this.clearSelections();
20848 for(var i = 0, len = rows.length; i < len; i++){
20849 this.selectRow(rows[i], true);
20854 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20855 * @param {Number} startRow The index of the first row in the range
20856 * @param {Number} endRow The index of the last row in the range
20857 * @param {Boolean} keepExisting (optional) True to retain existing selections
20859 selectRange : function(startRow, endRow, keepExisting){
20860 if(this.locked) return;
20862 this.clearSelections();
20864 if(startRow <= endRow){
20865 for(var i = startRow; i <= endRow; i++){
20866 this.selectRow(i, true);
20869 for(var i = startRow; i >= endRow; i--){
20870 this.selectRow(i, true);
20876 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20877 * @param {Number} startRow The index of the first row in the range
20878 * @param {Number} endRow The index of the last row in the range
20880 deselectRange : function(startRow, endRow, preventViewNotify){
20881 if(this.locked) return;
20882 for(var i = startRow; i <= endRow; i++){
20883 this.deselectRow(i, preventViewNotify);
20889 * @param {Number} row The index of the row to select
20890 * @param {Boolean} keepExisting (optional) True to keep existing selections
20892 selectRow : function(index, keepExisting, preventViewNotify){
20893 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20894 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20895 if(!keepExisting || this.singleSelect){
20896 this.clearSelections();
20898 var r = this.grid.dataSource.getAt(index);
20899 this.selections.add(r);
20900 this.last = this.lastActive = index;
20901 if(!preventViewNotify){
20902 this.grid.getView().onRowSelect(index);
20904 this.fireEvent("rowselect", this, index, r);
20905 this.fireEvent("selectionchange", this);
20911 * @param {Number} row The index of the row to deselect
20913 deselectRow : function(index, preventViewNotify){
20914 if(this.locked) return;
20915 if(this.last == index){
20918 if(this.lastActive == index){
20919 this.lastActive = false;
20921 var r = this.grid.dataSource.getAt(index);
20922 this.selections.remove(r);
20923 if(!preventViewNotify){
20924 this.grid.getView().onRowDeselect(index);
20926 this.fireEvent("rowdeselect", this, index);
20927 this.fireEvent("selectionchange", this);
20931 restoreLast : function(){
20933 this.last = this._last;
20938 acceptsNav : function(row, col, cm){
20939 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20943 onEditorKey : function(field, e){
20944 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20949 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20951 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20953 }else if(k == e.ENTER && !e.ctrlKey){
20957 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20959 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20961 }else if(k == e.ESC){
20965 g.startEditing(newCell[0], newCell[1]);
20970 * Ext JS Library 1.1.1
20971 * Copyright(c) 2006-2007, Ext JS, LLC.
20973 * Originally Released Under LGPL - original licence link has changed is not relivant.
20976 * <script type="text/javascript">
20980 * @class Roo.bootstrap.PagingToolbar
20982 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20984 * Create a new PagingToolbar
20985 * @param {Object} config The config object
20987 Roo.bootstrap.PagingToolbar = function(config)
20989 // old args format still supported... - xtype is prefered..
20990 // created from xtype...
20991 var ds = config.dataSource;
20992 this.toolbarItems = [];
20993 if (config.items) {
20994 this.toolbarItems = config.items;
20995 // config.items = [];
20998 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
21005 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21009 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21011 * @cfg {Roo.data.Store} dataSource
21012 * The underlying data store providing the paged data
21015 * @cfg {String/HTMLElement/Element} container
21016 * container The id or element that will contain the toolbar
21019 * @cfg {Boolean} displayInfo
21020 * True to display the displayMsg (defaults to false)
21023 * @cfg {Number} pageSize
21024 * The number of records to display per page (defaults to 20)
21028 * @cfg {String} displayMsg
21029 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21031 displayMsg : 'Displaying {0} - {1} of {2}',
21033 * @cfg {String} emptyMsg
21034 * The message to display when no records are found (defaults to "No data to display")
21036 emptyMsg : 'No data to display',
21038 * Customizable piece of the default paging text (defaults to "Page")
21041 beforePageText : "Page",
21043 * Customizable piece of the default paging text (defaults to "of %0")
21046 afterPageText : "of {0}",
21048 * Customizable piece of the default paging text (defaults to "First Page")
21051 firstText : "First Page",
21053 * Customizable piece of the default paging text (defaults to "Previous Page")
21056 prevText : "Previous Page",
21058 * Customizable piece of the default paging text (defaults to "Next Page")
21061 nextText : "Next Page",
21063 * Customizable piece of the default paging text (defaults to "Last Page")
21066 lastText : "Last Page",
21068 * Customizable piece of the default paging text (defaults to "Refresh")
21071 refreshText : "Refresh",
21075 onRender : function(ct, position)
21077 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21078 this.navgroup.parentId = this.id;
21079 this.navgroup.onRender(this.el, null);
21080 // add the buttons to the navgroup
21082 if(this.displayInfo){
21083 Roo.log(this.el.select('ul.navbar-nav',true).first());
21084 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21085 this.displayEl = this.el.select('.x-paging-info', true).first();
21086 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21087 // this.displayEl = navel.el.select('span',true).first();
21093 Roo.each(_this.buttons, function(e){
21094 Roo.factory(e).onRender(_this.el, null);
21098 Roo.each(_this.toolbarItems, function(e) {
21099 _this.navgroup.addItem(e);
21103 this.first = this.navgroup.addItem({
21104 tooltip: this.firstText,
21106 icon : 'fa fa-backward',
21108 preventDefault: true,
21109 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21112 this.prev = this.navgroup.addItem({
21113 tooltip: this.prevText,
21115 icon : 'fa fa-step-backward',
21117 preventDefault: true,
21118 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21120 //this.addSeparator();
21123 var field = this.navgroup.addItem( {
21125 cls : 'x-paging-position',
21127 html : this.beforePageText +
21128 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21129 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21132 this.field = field.el.select('input', true).first();
21133 this.field.on("keydown", this.onPagingKeydown, this);
21134 this.field.on("focus", function(){this.dom.select();});
21137 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21138 //this.field.setHeight(18);
21139 //this.addSeparator();
21140 this.next = this.navgroup.addItem({
21141 tooltip: this.nextText,
21143 html : ' <i class="fa fa-step-forward">',
21145 preventDefault: true,
21146 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21148 this.last = this.navgroup.addItem({
21149 tooltip: this.lastText,
21150 icon : 'fa fa-forward',
21153 preventDefault: true,
21154 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21156 //this.addSeparator();
21157 this.loading = this.navgroup.addItem({
21158 tooltip: this.refreshText,
21159 icon: 'fa fa-refresh',
21160 preventDefault: true,
21161 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21167 updateInfo : function(){
21168 if(this.displayEl){
21169 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21170 var msg = count == 0 ?
21174 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21176 this.displayEl.update(msg);
21181 onLoad : function(ds, r, o){
21182 this.cursor = o.params ? o.params.start : 0;
21183 var d = this.getPageData(),
21187 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21188 this.field.dom.value = ap;
21189 this.first.setDisabled(ap == 1);
21190 this.prev.setDisabled(ap == 1);
21191 this.next.setDisabled(ap == ps);
21192 this.last.setDisabled(ap == ps);
21193 this.loading.enable();
21198 getPageData : function(){
21199 var total = this.ds.getTotalCount();
21202 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21203 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21208 onLoadError : function(){
21209 this.loading.enable();
21213 onPagingKeydown : function(e){
21214 var k = e.getKey();
21215 var d = this.getPageData();
21217 var v = this.field.dom.value, pageNum;
21218 if(!v || isNaN(pageNum = parseInt(v, 10))){
21219 this.field.dom.value = d.activePage;
21222 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21223 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21226 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))
21228 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21229 this.field.dom.value = pageNum;
21230 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21233 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21235 var v = this.field.dom.value, pageNum;
21236 var increment = (e.shiftKey) ? 10 : 1;
21237 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21239 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21240 this.field.dom.value = d.activePage;
21243 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21245 this.field.dom.value = parseInt(v, 10) + increment;
21246 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21247 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21254 beforeLoad : function(){
21256 this.loading.disable();
21261 onClick : function(which){
21270 ds.load({params:{start: 0, limit: this.pageSize}});
21273 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21276 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21279 var total = ds.getTotalCount();
21280 var extra = total % this.pageSize;
21281 var lastStart = extra ? (total - extra) : total-this.pageSize;
21282 ds.load({params:{start: lastStart, limit: this.pageSize}});
21285 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21291 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21292 * @param {Roo.data.Store} store The data store to unbind
21294 unbind : function(ds){
21295 ds.un("beforeload", this.beforeLoad, this);
21296 ds.un("load", this.onLoad, this);
21297 ds.un("loadexception", this.onLoadError, this);
21298 ds.un("remove", this.updateInfo, this);
21299 ds.un("add", this.updateInfo, this);
21300 this.ds = undefined;
21304 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21305 * @param {Roo.data.Store} store The data store to bind
21307 bind : function(ds){
21308 ds.on("beforeload", this.beforeLoad, this);
21309 ds.on("load", this.onLoad, this);
21310 ds.on("loadexception", this.onLoadError, this);
21311 ds.on("remove", this.updateInfo, this);
21312 ds.on("add", this.updateInfo, this);
21323 * @class Roo.bootstrap.MessageBar
21324 * @extends Roo.bootstrap.Component
21325 * Bootstrap MessageBar class
21326 * @cfg {String} html contents of the MessageBar
21327 * @cfg {String} weight (info | success | warning | danger) default info
21328 * @cfg {String} beforeClass insert the bar before the given class
21329 * @cfg {Boolean} closable (true | false) default false
21330 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21333 * Create a new Element
21334 * @param {Object} config The config object
21337 Roo.bootstrap.MessageBar = function(config){
21338 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21341 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21347 beforeClass: 'bootstrap-sticky-wrap',
21349 getAutoCreate : function(){
21353 cls: 'alert alert-dismissable alert-' + this.weight,
21358 html: this.html || ''
21364 cfg.cls += ' alert-messages-fixed';
21378 onRender : function(ct, position)
21380 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21383 var cfg = Roo.apply({}, this.getAutoCreate());
21387 cfg.cls += ' ' + this.cls;
21390 cfg.style = this.style;
21392 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21394 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21397 this.el.select('>button.close').on('click', this.hide, this);
21403 if (!this.rendered) {
21409 this.fireEvent('show', this);
21415 if (!this.rendered) {
21421 this.fireEvent('hide', this);
21424 update : function()
21426 // var e = this.el.dom.firstChild;
21428 // if(this.closable){
21429 // e = e.nextSibling;
21432 // e.data = this.html || '';
21434 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21450 * @class Roo.bootstrap.Graph
21451 * @extends Roo.bootstrap.Component
21452 * Bootstrap Graph class
21456 @cfg {String} graphtype bar | vbar | pie
21457 @cfg {number} g_x coodinator | centre x (pie)
21458 @cfg {number} g_y coodinator | centre y (pie)
21459 @cfg {number} g_r radius (pie)
21460 @cfg {number} g_height height of the chart (respected by all elements in the set)
21461 @cfg {number} g_width width of the chart (respected by all elements in the set)
21462 @cfg {Object} title The title of the chart
21465 -opts (object) options for the chart
21467 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21468 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21470 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.
21471 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21473 o stretch (boolean)
21475 -opts (object) options for the pie
21478 o startAngle (number)
21479 o endAngle (number)
21483 * Create a new Input
21484 * @param {Object} config The config object
21487 Roo.bootstrap.Graph = function(config){
21488 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21494 * The img click event for the img.
21495 * @param {Roo.EventObject} e
21501 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21512 //g_colors: this.colors,
21519 getAutoCreate : function(){
21530 onRender : function(ct,position){
21531 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21532 this.raphael = Raphael(this.el.dom);
21534 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21535 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21536 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21537 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21539 r.text(160, 10, "Single Series Chart").attr(txtattr);
21540 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21541 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21542 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21544 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21545 r.barchart(330, 10, 300, 220, data1);
21546 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21547 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21550 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21551 // r.barchart(30, 30, 560, 250, xdata, {
21552 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21553 // axis : "0 0 1 1",
21554 // axisxlabels : xdata
21555 // //yvalues : cols,
21558 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21560 // this.load(null,xdata,{
21561 // axis : "0 0 1 1",
21562 // axisxlabels : xdata
21567 load : function(graphtype,xdata,opts){
21568 this.raphael.clear();
21570 graphtype = this.graphtype;
21575 var r = this.raphael,
21576 fin = function () {
21577 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21579 fout = function () {
21580 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21582 pfin = function() {
21583 this.sector.stop();
21584 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21587 this.label[0].stop();
21588 this.label[0].attr({ r: 7.5 });
21589 this.label[1].attr({ "font-weight": 800 });
21592 pfout = function() {
21593 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21596 this.label[0].animate({ r: 5 }, 500, "bounce");
21597 this.label[1].attr({ "font-weight": 400 });
21603 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21606 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21609 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21610 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21612 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21619 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21624 setTitle: function(o)
21629 initEvents: function() {
21632 this.el.on('click', this.onClick, this);
21636 onClick : function(e)
21638 Roo.log('img onclick');
21639 this.fireEvent('click', this, e);
21651 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21654 * @class Roo.bootstrap.dash.NumberBox
21655 * @extends Roo.bootstrap.Component
21656 * Bootstrap NumberBox class
21657 * @cfg {String} headline Box headline
21658 * @cfg {String} content Box content
21659 * @cfg {String} icon Box icon
21660 * @cfg {String} footer Footer text
21661 * @cfg {String} fhref Footer href
21664 * Create a new NumberBox
21665 * @param {Object} config The config object
21669 Roo.bootstrap.dash.NumberBox = function(config){
21670 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21674 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21683 getAutoCreate : function(){
21687 cls : 'small-box ',
21695 cls : 'roo-headline',
21696 html : this.headline
21700 cls : 'roo-content',
21701 html : this.content
21715 cls : 'ion ' + this.icon
21724 cls : 'small-box-footer',
21725 href : this.fhref || '#',
21729 cfg.cn.push(footer);
21736 onRender : function(ct,position){
21737 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21744 setHeadline: function (value)
21746 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21749 setFooter: function (value, href)
21751 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21754 this.el.select('a.small-box-footer',true).first().attr('href', href);
21759 setContent: function (value)
21761 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21764 initEvents: function()
21778 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21781 * @class Roo.bootstrap.dash.TabBox
21782 * @extends Roo.bootstrap.Component
21783 * Bootstrap TabBox class
21784 * @cfg {String} title Title of the TabBox
21785 * @cfg {String} icon Icon of the TabBox
21786 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21787 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21790 * Create a new TabBox
21791 * @param {Object} config The config object
21795 Roo.bootstrap.dash.TabBox = function(config){
21796 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21801 * When a pane is added
21802 * @param {Roo.bootstrap.dash.TabPane} pane
21806 * @event activatepane
21807 * When a pane is activated
21808 * @param {Roo.bootstrap.dash.TabPane} pane
21810 "activatepane" : true
21818 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21823 tabScrollable : false,
21825 getChildContainer : function()
21827 return this.el.select('.tab-content', true).first();
21830 getAutoCreate : function(){
21834 cls: 'pull-left header',
21842 cls: 'fa ' + this.icon
21848 cls: 'nav nav-tabs pull-right',
21854 if(this.tabScrollable){
21861 cls: 'nav nav-tabs pull-right',
21872 cls: 'nav-tabs-custom',
21877 cls: 'tab-content no-padding',
21885 initEvents : function()
21887 //Roo.log('add add pane handler');
21888 this.on('addpane', this.onAddPane, this);
21891 * Updates the box title
21892 * @param {String} html to set the title to.
21894 setTitle : function(value)
21896 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21898 onAddPane : function(pane)
21900 this.panes.push(pane);
21901 //Roo.log('addpane');
21903 // tabs are rendere left to right..
21904 if(!this.showtabs){
21908 var ctr = this.el.select('.nav-tabs', true).first();
21911 var existing = ctr.select('.nav-tab',true);
21912 var qty = existing.getCount();;
21915 var tab = ctr.createChild({
21917 cls : 'nav-tab' + (qty ? '' : ' active'),
21925 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21928 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21930 pane.el.addClass('active');
21935 onTabClick : function(ev,un,ob,pane)
21937 //Roo.log('tab - prev default');
21938 ev.preventDefault();
21941 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21942 pane.tab.addClass('active');
21943 //Roo.log(pane.title);
21944 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21945 // technically we should have a deactivate event.. but maybe add later.
21946 // and it should not de-activate the selected tab...
21947 this.fireEvent('activatepane', pane);
21948 pane.el.addClass('active');
21949 pane.fireEvent('activate');
21954 getActivePane : function()
21957 Roo.each(this.panes, function(p) {
21958 if(p.el.hasClass('active')){
21979 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21981 * @class Roo.bootstrap.TabPane
21982 * @extends Roo.bootstrap.Component
21983 * Bootstrap TabPane class
21984 * @cfg {Boolean} active (false | true) Default false
21985 * @cfg {String} title title of panel
21989 * Create a new TabPane
21990 * @param {Object} config The config object
21993 Roo.bootstrap.dash.TabPane = function(config){
21994 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
22000 * When a pane is activated
22001 * @param {Roo.bootstrap.dash.TabPane} pane
22008 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22013 // the tabBox that this is attached to.
22016 getAutoCreate : function()
22024 cfg.cls += ' active';
22029 initEvents : function()
22031 //Roo.log('trigger add pane handler');
22032 this.parent().fireEvent('addpane', this)
22036 * Updates the tab title
22037 * @param {String} html to set the title to.
22039 setTitle: function(str)
22045 this.tab.select('a', true).first().dom.innerHTML = str;
22062 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22065 * @class Roo.bootstrap.menu.Menu
22066 * @extends Roo.bootstrap.Component
22067 * Bootstrap Menu class - container for Menu
22068 * @cfg {String} html Text of the menu
22069 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22070 * @cfg {String} icon Font awesome icon
22071 * @cfg {String} pos Menu align to (top | bottom) default bottom
22075 * Create a new Menu
22076 * @param {Object} config The config object
22080 Roo.bootstrap.menu.Menu = function(config){
22081 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22085 * @event beforeshow
22086 * Fires before this menu is displayed
22087 * @param {Roo.bootstrap.menu.Menu} this
22091 * @event beforehide
22092 * Fires before this menu is hidden
22093 * @param {Roo.bootstrap.menu.Menu} this
22098 * Fires after this menu is displayed
22099 * @param {Roo.bootstrap.menu.Menu} this
22104 * Fires after this menu is hidden
22105 * @param {Roo.bootstrap.menu.Menu} this
22110 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22111 * @param {Roo.bootstrap.menu.Menu} this
22112 * @param {Roo.EventObject} e
22119 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22123 weight : 'default',
22128 getChildContainer : function() {
22129 if(this.isSubMenu){
22133 return this.el.select('ul.dropdown-menu', true).first();
22136 getAutoCreate : function()
22141 cls : 'roo-menu-text',
22149 cls : 'fa ' + this.icon
22160 cls : 'dropdown-button btn btn-' + this.weight,
22165 cls : 'dropdown-toggle btn btn-' + this.weight,
22175 cls : 'dropdown-menu'
22181 if(this.pos == 'top'){
22182 cfg.cls += ' dropup';
22185 if(this.isSubMenu){
22188 cls : 'dropdown-menu'
22195 onRender : function(ct, position)
22197 this.isSubMenu = ct.hasClass('dropdown-submenu');
22199 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22202 initEvents : function()
22204 if(this.isSubMenu){
22208 this.hidden = true;
22210 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22211 this.triggerEl.on('click', this.onTriggerPress, this);
22213 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22214 this.buttonEl.on('click', this.onClick, this);
22220 if(this.isSubMenu){
22224 return this.el.select('ul.dropdown-menu', true).first();
22227 onClick : function(e)
22229 this.fireEvent("click", this, e);
22232 onTriggerPress : function(e)
22234 if (this.isVisible()) {
22241 isVisible : function(){
22242 return !this.hidden;
22247 this.fireEvent("beforeshow", this);
22249 this.hidden = false;
22250 this.el.addClass('open');
22252 Roo.get(document).on("mouseup", this.onMouseUp, this);
22254 this.fireEvent("show", this);
22261 this.fireEvent("beforehide", this);
22263 this.hidden = true;
22264 this.el.removeClass('open');
22266 Roo.get(document).un("mouseup", this.onMouseUp);
22268 this.fireEvent("hide", this);
22271 onMouseUp : function()
22285 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22288 * @class Roo.bootstrap.menu.Item
22289 * @extends Roo.bootstrap.Component
22290 * Bootstrap MenuItem class
22291 * @cfg {Boolean} submenu (true | false) default false
22292 * @cfg {String} html text of the item
22293 * @cfg {String} href the link
22294 * @cfg {Boolean} disable (true | false) default false
22295 * @cfg {Boolean} preventDefault (true | false) default true
22296 * @cfg {String} icon Font awesome icon
22297 * @cfg {String} pos Submenu align to (left | right) default right
22301 * Create a new Item
22302 * @param {Object} config The config object
22306 Roo.bootstrap.menu.Item = function(config){
22307 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22311 * Fires when the mouse is hovering over this menu
22312 * @param {Roo.bootstrap.menu.Item} this
22313 * @param {Roo.EventObject} e
22318 * Fires when the mouse exits this menu
22319 * @param {Roo.bootstrap.menu.Item} this
22320 * @param {Roo.EventObject} e
22326 * The raw click event for the entire grid.
22327 * @param {Roo.EventObject} e
22333 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22338 preventDefault: true,
22343 getAutoCreate : function()
22348 cls : 'roo-menu-item-text',
22356 cls : 'fa ' + this.icon
22365 href : this.href || '#',
22372 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22376 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22378 if(this.pos == 'left'){
22379 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22386 initEvents : function()
22388 this.el.on('mouseover', this.onMouseOver, this);
22389 this.el.on('mouseout', this.onMouseOut, this);
22391 this.el.select('a', true).first().on('click', this.onClick, this);
22395 onClick : function(e)
22397 if(this.preventDefault){
22398 e.preventDefault();
22401 this.fireEvent("click", this, e);
22404 onMouseOver : function(e)
22406 if(this.submenu && this.pos == 'left'){
22407 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22410 this.fireEvent("mouseover", this, e);
22413 onMouseOut : function(e)
22415 this.fireEvent("mouseout", this, e);
22427 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22430 * @class Roo.bootstrap.menu.Separator
22431 * @extends Roo.bootstrap.Component
22432 * Bootstrap Separator class
22435 * Create a new Separator
22436 * @param {Object} config The config object
22440 Roo.bootstrap.menu.Separator = function(config){
22441 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22444 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22446 getAutoCreate : function(){
22467 * @class Roo.bootstrap.Tooltip
22468 * Bootstrap Tooltip class
22469 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22470 * to determine which dom element triggers the tooltip.
22472 * It needs to add support for additional attributes like tooltip-position
22475 * Create a new Toolti
22476 * @param {Object} config The config object
22479 Roo.bootstrap.Tooltip = function(config){
22480 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22483 Roo.apply(Roo.bootstrap.Tooltip, {
22485 * @function init initialize tooltip monitoring.
22489 currentTip : false,
22490 currentRegion : false,
22496 Roo.get(document).on('mouseover', this.enter ,this);
22497 Roo.get(document).on('mouseout', this.leave, this);
22500 this.currentTip = new Roo.bootstrap.Tooltip();
22503 enter : function(ev)
22505 var dom = ev.getTarget();
22507 //Roo.log(['enter',dom]);
22508 var el = Roo.fly(dom);
22509 if (this.currentEl) {
22511 //Roo.log(this.currentEl);
22512 //Roo.log(this.currentEl.contains(dom));
22513 if (this.currentEl == el) {
22516 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22524 if (this.currentTip.el) {
22525 this.currentTip.el.hide(); // force hiding...
22530 // you can not look for children, as if el is the body.. then everythign is the child..
22531 if (!el.attr('tooltip')) { //
22532 if (!el.select("[tooltip]").elements.length) {
22535 // is the mouse over this child...?
22536 bindEl = el.select("[tooltip]").first();
22537 var xy = ev.getXY();
22538 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22539 //Roo.log("not in region.");
22542 //Roo.log("child element over..");
22545 this.currentEl = bindEl;
22546 this.currentTip.bind(bindEl);
22547 this.currentRegion = Roo.lib.Region.getRegion(dom);
22548 this.currentTip.enter();
22551 leave : function(ev)
22553 var dom = ev.getTarget();
22554 //Roo.log(['leave',dom]);
22555 if (!this.currentEl) {
22560 if (dom != this.currentEl.dom) {
22563 var xy = ev.getXY();
22564 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22567 // only activate leave if mouse cursor is outside... bounding box..
22572 if (this.currentTip) {
22573 this.currentTip.leave();
22575 //Roo.log('clear currentEl');
22576 this.currentEl = false;
22581 'left' : ['r-l', [-2,0], 'right'],
22582 'right' : ['l-r', [2,0], 'left'],
22583 'bottom' : ['t-b', [0,2], 'top'],
22584 'top' : [ 'b-t', [0,-2], 'bottom']
22590 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22595 delay : null, // can be { show : 300 , hide: 500}
22599 hoverState : null, //???
22601 placement : 'bottom',
22603 getAutoCreate : function(){
22610 cls : 'tooltip-arrow'
22613 cls : 'tooltip-inner'
22620 bind : function(el)
22626 enter : function () {
22628 if (this.timeout != null) {
22629 clearTimeout(this.timeout);
22632 this.hoverState = 'in';
22633 //Roo.log("enter - show");
22634 if (!this.delay || !this.delay.show) {
22639 this.timeout = setTimeout(function () {
22640 if (_t.hoverState == 'in') {
22643 }, this.delay.show);
22647 clearTimeout(this.timeout);
22649 this.hoverState = 'out';
22650 if (!this.delay || !this.delay.hide) {
22656 this.timeout = setTimeout(function () {
22657 //Roo.log("leave - timeout");
22659 if (_t.hoverState == 'out') {
22661 Roo.bootstrap.Tooltip.currentEl = false;
22669 this.render(document.body);
22672 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22674 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22676 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22678 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22680 var placement = typeof this.placement == 'function' ?
22681 this.placement.call(this, this.el, on_el) :
22684 var autoToken = /\s?auto?\s?/i;
22685 var autoPlace = autoToken.test(placement);
22687 placement = placement.replace(autoToken, '') || 'top';
22691 //this.el.setXY([0,0]);
22693 //this.el.dom.style.display='block';
22694 this.el.addClass(placement);
22696 //this.el.appendTo(on_el);
22698 var p = this.getPosition();
22699 var box = this.el.getBox();
22704 var align = Roo.bootstrap.Tooltip.alignment[placement];
22705 this.el.alignTo(this.bindEl, align[0],align[1]);
22706 //var arrow = this.el.select('.arrow',true).first();
22707 //arrow.set(align[2],
22709 this.el.addClass('in fade');
22710 this.hoverState = null;
22712 if (this.el.hasClass('fade')) {
22723 //this.el.setXY([0,0]);
22724 this.el.removeClass('in');
22740 * @class Roo.bootstrap.LocationPicker
22741 * @extends Roo.bootstrap.Component
22742 * Bootstrap LocationPicker class
22743 * @cfg {Number} latitude Position when init default 0
22744 * @cfg {Number} longitude Position when init default 0
22745 * @cfg {Number} zoom default 15
22746 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22747 * @cfg {Boolean} mapTypeControl default false
22748 * @cfg {Boolean} disableDoubleClickZoom default false
22749 * @cfg {Boolean} scrollwheel default true
22750 * @cfg {Boolean} streetViewControl default false
22751 * @cfg {Number} radius default 0
22752 * @cfg {String} locationName
22753 * @cfg {Boolean} draggable default true
22754 * @cfg {Boolean} enableAutocomplete default false
22755 * @cfg {Boolean} enableReverseGeocode default true
22756 * @cfg {String} markerTitle
22759 * Create a new LocationPicker
22760 * @param {Object} config The config object
22764 Roo.bootstrap.LocationPicker = function(config){
22766 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22771 * Fires when the picker initialized.
22772 * @param {Roo.bootstrap.LocationPicker} this
22773 * @param {Google Location} location
22777 * @event positionchanged
22778 * Fires when the picker position changed.
22779 * @param {Roo.bootstrap.LocationPicker} this
22780 * @param {Google Location} location
22782 positionchanged : true,
22785 * Fires when the map resize.
22786 * @param {Roo.bootstrap.LocationPicker} this
22791 * Fires when the map show.
22792 * @param {Roo.bootstrap.LocationPicker} this
22797 * Fires when the map hide.
22798 * @param {Roo.bootstrap.LocationPicker} this
22803 * Fires when click the map.
22804 * @param {Roo.bootstrap.LocationPicker} this
22805 * @param {Map event} e
22809 * @event mapRightClick
22810 * Fires when right click the map.
22811 * @param {Roo.bootstrap.LocationPicker} this
22812 * @param {Map event} e
22814 mapRightClick : true,
22816 * @event markerClick
22817 * Fires when click the marker.
22818 * @param {Roo.bootstrap.LocationPicker} this
22819 * @param {Map event} e
22821 markerClick : true,
22823 * @event markerRightClick
22824 * Fires when right click the marker.
22825 * @param {Roo.bootstrap.LocationPicker} this
22826 * @param {Map event} e
22828 markerRightClick : true,
22830 * @event OverlayViewDraw
22831 * Fires when OverlayView Draw
22832 * @param {Roo.bootstrap.LocationPicker} this
22834 OverlayViewDraw : true,
22836 * @event OverlayViewOnAdd
22837 * Fires when OverlayView Draw
22838 * @param {Roo.bootstrap.LocationPicker} this
22840 OverlayViewOnAdd : true,
22842 * @event OverlayViewOnRemove
22843 * Fires when OverlayView Draw
22844 * @param {Roo.bootstrap.LocationPicker} this
22846 OverlayViewOnRemove : true,
22848 * @event OverlayViewShow
22849 * Fires when OverlayView Draw
22850 * @param {Roo.bootstrap.LocationPicker} this
22851 * @param {Pixel} cpx
22853 OverlayViewShow : true,
22855 * @event OverlayViewHide
22856 * Fires when OverlayView Draw
22857 * @param {Roo.bootstrap.LocationPicker} this
22859 OverlayViewHide : true
22864 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22866 gMapContext: false,
22872 mapTypeControl: false,
22873 disableDoubleClickZoom: false,
22875 streetViewControl: false,
22879 enableAutocomplete: false,
22880 enableReverseGeocode: true,
22883 getAutoCreate: function()
22888 cls: 'roo-location-picker'
22894 initEvents: function(ct, position)
22896 if(!this.el.getWidth() || this.isApplied()){
22900 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22905 initial: function()
22907 if(!this.mapTypeId){
22908 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22911 this.gMapContext = this.GMapContext();
22913 this.initOverlayView();
22915 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22919 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22920 _this.setPosition(_this.gMapContext.marker.position);
22923 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22924 _this.fireEvent('mapClick', this, event);
22928 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22929 _this.fireEvent('mapRightClick', this, event);
22933 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22934 _this.fireEvent('markerClick', this, event);
22938 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22939 _this.fireEvent('markerRightClick', this, event);
22943 this.setPosition(this.gMapContext.location);
22945 this.fireEvent('initial', this, this.gMapContext.location);
22948 initOverlayView: function()
22952 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22956 _this.fireEvent('OverlayViewDraw', _this);
22961 _this.fireEvent('OverlayViewOnAdd', _this);
22964 onRemove: function()
22966 _this.fireEvent('OverlayViewOnRemove', _this);
22969 show: function(cpx)
22971 _this.fireEvent('OverlayViewShow', _this, cpx);
22976 _this.fireEvent('OverlayViewHide', _this);
22982 fromLatLngToContainerPixel: function(event)
22984 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22987 isApplied: function()
22989 return this.getGmapContext() == false ? false : true;
22992 getGmapContext: function()
22994 return this.gMapContext
22997 GMapContext: function()
22999 var position = new google.maps.LatLng(this.latitude, this.longitude);
23001 var _map = new google.maps.Map(this.el.dom, {
23004 mapTypeId: this.mapTypeId,
23005 mapTypeControl: this.mapTypeControl,
23006 disableDoubleClickZoom: this.disableDoubleClickZoom,
23007 scrollwheel: this.scrollwheel,
23008 streetViewControl: this.streetViewControl,
23009 locationName: this.locationName,
23010 draggable: this.draggable,
23011 enableAutocomplete: this.enableAutocomplete,
23012 enableReverseGeocode: this.enableReverseGeocode
23015 var _marker = new google.maps.Marker({
23016 position: position,
23018 title: this.markerTitle,
23019 draggable: this.draggable
23026 location: position,
23027 radius: this.radius,
23028 locationName: this.locationName,
23029 addressComponents: {
23030 formatted_address: null,
23031 addressLine1: null,
23032 addressLine2: null,
23034 streetNumber: null,
23038 stateOrProvince: null
23041 domContainer: this.el.dom,
23042 geodecoder: new google.maps.Geocoder()
23046 drawCircle: function(center, radius, options)
23048 if (this.gMapContext.circle != null) {
23049 this.gMapContext.circle.setMap(null);
23053 options = Roo.apply({}, options, {
23054 strokeColor: "#0000FF",
23055 strokeOpacity: .35,
23057 fillColor: "#0000FF",
23061 options.map = this.gMapContext.map;
23062 options.radius = radius;
23063 options.center = center;
23064 this.gMapContext.circle = new google.maps.Circle(options);
23065 return this.gMapContext.circle;
23071 setPosition: function(location)
23073 this.gMapContext.location = location;
23074 this.gMapContext.marker.setPosition(location);
23075 this.gMapContext.map.panTo(location);
23076 this.drawCircle(location, this.gMapContext.radius, {});
23080 if (this.gMapContext.settings.enableReverseGeocode) {
23081 this.gMapContext.geodecoder.geocode({
23082 latLng: this.gMapContext.location
23083 }, function(results, status) {
23085 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23086 _this.gMapContext.locationName = results[0].formatted_address;
23087 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23089 _this.fireEvent('positionchanged', this, location);
23096 this.fireEvent('positionchanged', this, location);
23101 google.maps.event.trigger(this.gMapContext.map, "resize");
23103 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23105 this.fireEvent('resize', this);
23108 setPositionByLatLng: function(latitude, longitude)
23110 this.setPosition(new google.maps.LatLng(latitude, longitude));
23113 getCurrentPosition: function()
23116 latitude: this.gMapContext.location.lat(),
23117 longitude: this.gMapContext.location.lng()
23121 getAddressName: function()
23123 return this.gMapContext.locationName;
23126 getAddressComponents: function()
23128 return this.gMapContext.addressComponents;
23131 address_component_from_google_geocode: function(address_components)
23135 for (var i = 0; i < address_components.length; i++) {
23136 var component = address_components[i];
23137 if (component.types.indexOf("postal_code") >= 0) {
23138 result.postalCode = component.short_name;
23139 } else if (component.types.indexOf("street_number") >= 0) {
23140 result.streetNumber = component.short_name;
23141 } else if (component.types.indexOf("route") >= 0) {
23142 result.streetName = component.short_name;
23143 } else if (component.types.indexOf("neighborhood") >= 0) {
23144 result.city = component.short_name;
23145 } else if (component.types.indexOf("locality") >= 0) {
23146 result.city = component.short_name;
23147 } else if (component.types.indexOf("sublocality") >= 0) {
23148 result.district = component.short_name;
23149 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23150 result.stateOrProvince = component.short_name;
23151 } else if (component.types.indexOf("country") >= 0) {
23152 result.country = component.short_name;
23156 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23157 result.addressLine2 = "";
23161 setZoomLevel: function(zoom)
23163 this.gMapContext.map.setZoom(zoom);
23176 this.fireEvent('show', this);
23187 this.fireEvent('hide', this);
23192 Roo.apply(Roo.bootstrap.LocationPicker, {
23194 OverlayView : function(map, options)
23196 options = options || {};
23210 * @class Roo.bootstrap.Alert
23211 * @extends Roo.bootstrap.Component
23212 * Bootstrap Alert class
23213 * @cfg {String} title The title of alert
23214 * @cfg {String} html The content of alert
23215 * @cfg {String} weight ( success | info | warning | danger )
23216 * @cfg {String} faicon font-awesomeicon
23219 * Create a new alert
23220 * @param {Object} config The config object
23224 Roo.bootstrap.Alert = function(config){
23225 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23229 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23236 getAutoCreate : function()
23245 cls : 'roo-alert-icon'
23250 cls : 'roo-alert-title',
23255 cls : 'roo-alert-text',
23262 cfg.cn[0].cls += ' fa ' + this.faicon;
23266 cfg.cls += ' alert-' + this.weight;
23272 initEvents: function()
23274 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23277 setTitle : function(str)
23279 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23282 setText : function(str)
23284 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23287 setWeight : function(weight)
23290 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23293 this.weight = weight;
23295 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23298 setIcon : function(icon)
23301 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23306 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);