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 Roo.log('run?????????????????????');
1370 return this.createSingleImg();
1375 cls: 'roo-image-responsive-group',
1378 Roo.log('run?????????????????????');
1379 Roo.each(['xsUrl', 'smUrl', 'mdUrl', 'lgUrl'], function(size){
1380 Roo.log(this[size]);
1387 cls: (this.imgResponsive) ? 'img-responsive' : '',
1388 html: this.html || cfg.html,
1392 img.cls += ' roo-image-responsive-' + size;
1394 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1395 cfg.cls += ' img-' + this.border;
1412 a.target = this.target;
1416 cfg.cn.push((this.href) ? a : img);
1423 createSingleImg : function()
1427 cls: (this.imgResponsive) ? 'img-responsive' : '',
1431 cfg.html = this.html || cfg.html;
1433 cfg.src = this.src || cfg.src;
1435 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1436 cfg.cls += ' img-' + this.border;
1453 a.target = this.target;
1458 return (this.href) ? a : cfg;
1461 initEvents: function() {
1464 this.el.on('click', this.onClick, this);
1468 onClick : function(e)
1470 Roo.log('img onclick');
1471 this.fireEvent('click', this, e);
1485 * @class Roo.bootstrap.Link
1486 * @extends Roo.bootstrap.Component
1487 * Bootstrap Link Class
1488 * @cfg {String} alt image alternative text
1489 * @cfg {String} href a tag href
1490 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1491 * @cfg {String} html the content of the link.
1492 * @cfg {String} anchor name for the anchor link
1494 * @cfg {Boolean} preventDefault (true | false) default false
1498 * Create a new Input
1499 * @param {Object} config The config object
1502 Roo.bootstrap.Link = function(config){
1503 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1509 * The img click event for the img.
1510 * @param {Roo.EventObject} e
1516 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1520 preventDefault: false,
1524 getAutoCreate : function()
1530 // anchor's do not require html/href...
1531 if (this.anchor === false) {
1532 cfg.html = this.html || '';
1533 cfg.href = this.href || '#';
1535 cfg.name = this.anchor;
1536 if (this.html !== false) {
1537 cfg.html = this.html;
1539 if (this.href !== false) {
1540 cfg.href = this.href;
1544 if(this.alt !== false){
1549 if(this.target !== false) {
1550 cfg.target = this.target;
1556 initEvents: function() {
1558 if(!this.href || this.preventDefault){
1559 this.el.on('click', this.onClick, this);
1563 onClick : function(e)
1565 if(this.preventDefault){
1568 //Roo.log('img onclick');
1569 this.fireEvent('click', this, e);
1582 * @class Roo.bootstrap.Header
1583 * @extends Roo.bootstrap.Component
1584 * Bootstrap Header class
1585 * @cfg {String} html content of header
1586 * @cfg {Number} level (1|2|3|4|5|6) default 1
1589 * Create a new Header
1590 * @param {Object} config The config object
1594 Roo.bootstrap.Header = function(config){
1595 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1598 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1606 getAutoCreate : function(){
1611 tag: 'h' + (1 *this.level),
1612 html: this.html || ''
1624 * Ext JS Library 1.1.1
1625 * Copyright(c) 2006-2007, Ext JS, LLC.
1627 * Originally Released Under LGPL - original licence link has changed is not relivant.
1630 * <script type="text/javascript">
1634 * @class Roo.bootstrap.MenuMgr
1635 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1638 Roo.bootstrap.MenuMgr = function(){
1639 var menus, active, groups = {}, attached = false, lastShow = new Date();
1641 // private - called when first menu is created
1644 active = new Roo.util.MixedCollection();
1645 Roo.get(document).addKeyListener(27, function(){
1646 if(active.length > 0){
1654 if(active && active.length > 0){
1655 var c = active.clone();
1665 if(active.length < 1){
1666 Roo.get(document).un("mouseup", onMouseDown);
1674 var last = active.last();
1675 lastShow = new Date();
1678 Roo.get(document).on("mouseup", onMouseDown);
1683 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1684 m.parentMenu.activeChild = m;
1685 }else if(last && last.isVisible()){
1686 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1691 function onBeforeHide(m){
1693 m.activeChild.hide();
1695 if(m.autoHideTimer){
1696 clearTimeout(m.autoHideTimer);
1697 delete m.autoHideTimer;
1702 function onBeforeShow(m){
1703 var pm = m.parentMenu;
1704 if(!pm && !m.allowOtherMenus){
1706 }else if(pm && pm.activeChild && active != m){
1707 pm.activeChild.hide();
1711 // private this should really trigger on mouseup..
1712 function onMouseDown(e){
1713 Roo.log("on Mouse Up");
1714 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1724 function onBeforeCheck(mi, state){
1726 var g = groups[mi.group];
1727 for(var i = 0, l = g.length; i < l; i++){
1729 g[i].setChecked(false);
1738 * Hides all menus that are currently visible
1740 hideAll : function(){
1745 register : function(menu){
1749 menus[menu.id] = menu;
1750 menu.on("beforehide", onBeforeHide);
1751 menu.on("hide", onHide);
1752 menu.on("beforeshow", onBeforeShow);
1753 menu.on("show", onShow);
1755 if(g && menu.events["checkchange"]){
1759 groups[g].push(menu);
1760 menu.on("checkchange", onCheck);
1765 * Returns a {@link Roo.menu.Menu} object
1766 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1767 * be used to generate and return a new Menu instance.
1769 get : function(menu){
1770 if(typeof menu == "string"){ // menu id
1772 }else if(menu.events){ // menu instance
1775 /*else if(typeof menu.length == 'number'){ // array of menu items?
1776 return new Roo.bootstrap.Menu({items:menu});
1777 }else{ // otherwise, must be a config
1778 return new Roo.bootstrap.Menu(menu);
1785 unregister : function(menu){
1786 delete menus[menu.id];
1787 menu.un("beforehide", onBeforeHide);
1788 menu.un("hide", onHide);
1789 menu.un("beforeshow", onBeforeShow);
1790 menu.un("show", onShow);
1792 if(g && menu.events["checkchange"]){
1793 groups[g].remove(menu);
1794 menu.un("checkchange", onCheck);
1799 registerCheckable : function(menuItem){
1800 var g = menuItem.group;
1805 groups[g].push(menuItem);
1806 menuItem.on("beforecheckchange", onBeforeCheck);
1811 unregisterCheckable : function(menuItem){
1812 var g = menuItem.group;
1814 groups[g].remove(menuItem);
1815 menuItem.un("beforecheckchange", onBeforeCheck);
1827 * @class Roo.bootstrap.Menu
1828 * @extends Roo.bootstrap.Component
1829 * Bootstrap Menu class - container for MenuItems
1830 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1834 * @param {Object} config The config object
1838 Roo.bootstrap.Menu = function(config){
1839 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1840 if (this.registerMenu) {
1841 Roo.bootstrap.MenuMgr.register(this);
1846 * Fires before this menu is displayed
1847 * @param {Roo.menu.Menu} this
1852 * Fires before this menu is hidden
1853 * @param {Roo.menu.Menu} this
1858 * Fires after this menu is displayed
1859 * @param {Roo.menu.Menu} this
1864 * Fires after this menu is hidden
1865 * @param {Roo.menu.Menu} this
1870 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1871 * @param {Roo.menu.Menu} this
1872 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1873 * @param {Roo.EventObject} e
1878 * Fires when the mouse is hovering over this menu
1879 * @param {Roo.menu.Menu} this
1880 * @param {Roo.EventObject} e
1881 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1886 * Fires when the mouse exits 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 a menu item contained in this menu is clicked
1895 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1896 * @param {Roo.EventObject} e
1900 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1903 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1907 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1910 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1912 registerMenu : true,
1914 menuItems :false, // stores the menu items..
1920 getChildContainer : function() {
1924 getAutoCreate : function(){
1926 //if (['right'].indexOf(this.align)!==-1) {
1927 // cfg.cn[1].cls += ' pull-right'
1933 cls : 'dropdown-menu' ,
1934 style : 'z-index:1000'
1938 if (this.type === 'submenu') {
1939 cfg.cls = 'submenu active';
1941 if (this.type === 'treeview') {
1942 cfg.cls = 'treeview-menu';
1947 initEvents : function() {
1949 // Roo.log("ADD event");
1950 // Roo.log(this.triggerEl.dom);
1951 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1953 this.triggerEl.addClass('dropdown-toggle');
1954 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1956 this.el.on("mouseover", this.onMouseOver, this);
1957 this.el.on("mouseout", this.onMouseOut, this);
1961 findTargetItem : function(e){
1962 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1966 //Roo.log(t); Roo.log(t.id);
1968 //Roo.log(this.menuitems);
1969 return this.menuitems.get(t.id);
1971 //return this.items.get(t.menuItemId);
1976 onClick : function(e){
1977 Roo.log("menu.onClick");
1978 var t = this.findTargetItem(e);
1979 if(!t || t.isContainer){
1984 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1985 if(t == this.activeItem && t.shouldDeactivate(e)){
1986 this.activeItem.deactivate();
1987 delete this.activeItem;
1991 this.setActiveItem(t, true);
1999 Roo.log('pass click event');
2003 this.fireEvent("click", this, t, e);
2007 onMouseOver : function(e){
2008 var t = this.findTargetItem(e);
2011 // if(t.canActivate && !t.disabled){
2012 // this.setActiveItem(t, true);
2016 this.fireEvent("mouseover", this, e, t);
2018 isVisible : function(){
2019 return !this.hidden;
2021 onMouseOut : function(e){
2022 var t = this.findTargetItem(e);
2025 // if(t == this.activeItem && t.shouldDeactivate(e)){
2026 // this.activeItem.deactivate();
2027 // delete this.activeItem;
2030 this.fireEvent("mouseout", this, e, t);
2035 * Displays this menu relative to another element
2036 * @param {String/HTMLElement/Roo.Element} element The element to align to
2037 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2038 * the element (defaults to this.defaultAlign)
2039 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2041 show : function(el, pos, parentMenu){
2042 this.parentMenu = parentMenu;
2046 this.fireEvent("beforeshow", this);
2047 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2050 * Displays this menu at a specific xy position
2051 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2052 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2054 showAt : function(xy, parentMenu, /* private: */_e){
2055 this.parentMenu = parentMenu;
2060 this.fireEvent("beforeshow", this);
2061 //xy = this.el.adjustForConstraints(xy);
2065 this.hideMenuItems();
2066 this.hidden = false;
2067 this.triggerEl.addClass('open');
2069 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2070 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2075 this.fireEvent("show", this);
2081 this.doFocus.defer(50, this);
2085 doFocus : function(){
2087 this.focusEl.focus();
2092 * Hides this menu and optionally all parent menus
2093 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2095 hide : function(deep){
2097 this.hideMenuItems();
2098 if(this.el && this.isVisible()){
2099 this.fireEvent("beforehide", this);
2100 if(this.activeItem){
2101 this.activeItem.deactivate();
2102 this.activeItem = null;
2104 this.triggerEl.removeClass('open');;
2106 this.fireEvent("hide", this);
2108 if(deep === true && this.parentMenu){
2109 this.parentMenu.hide(true);
2113 onTriggerPress : function(e)
2116 Roo.log('trigger press');
2117 //Roo.log(e.getTarget());
2118 // Roo.log(this.triggerEl.dom);
2119 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2123 if (this.isVisible()) {
2128 this.show(this.triggerEl, false, false);
2137 hideMenuItems : function()
2139 //$(backdrop).remove()
2140 Roo.select('.open',true).each(function(aa) {
2142 aa.removeClass('open');
2143 //var parent = getParent($(this))
2144 //var relatedTarget = { relatedTarget: this }
2146 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2147 //if (e.isDefaultPrevented()) return
2148 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2151 addxtypeChild : function (tree, cntr) {
2152 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2154 this.menuitems.add(comp);
2175 * @class Roo.bootstrap.MenuItem
2176 * @extends Roo.bootstrap.Component
2177 * Bootstrap MenuItem class
2178 * @cfg {String} html the menu label
2179 * @cfg {String} href the link
2180 * @cfg {Boolean} preventDefault (true | false) default true
2181 * @cfg {Boolean} isContainer (true | false) default false
2185 * Create a new MenuItem
2186 * @param {Object} config The config object
2190 Roo.bootstrap.MenuItem = function(config){
2191 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2196 * The raw click event for the entire grid.
2197 * @param {Roo.bootstrap.MenuItem} this
2198 * @param {Roo.EventObject} e
2204 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2208 preventDefault: true,
2209 isContainer : false,
2211 getAutoCreate : function(){
2213 if(this.isContainer){
2216 cls: 'dropdown-menu-item'
2222 cls: 'dropdown-menu-item',
2231 if (this.parent().type == 'treeview') {
2232 cfg.cls = 'treeview-menu';
2235 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2236 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2240 initEvents: function() {
2242 //this.el.select('a').on('click', this.onClick, this);
2245 onClick : function(e)
2247 Roo.log('item on click ');
2248 //if(this.preventDefault){
2249 // e.preventDefault();
2251 //this.parent().hideMenuItems();
2253 this.fireEvent('click', this, e);
2272 * @class Roo.bootstrap.MenuSeparator
2273 * @extends Roo.bootstrap.Component
2274 * Bootstrap MenuSeparator class
2277 * Create a new MenuItem
2278 * @param {Object} config The config object
2282 Roo.bootstrap.MenuSeparator = function(config){
2283 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2286 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2288 getAutoCreate : function(){
2307 * @class Roo.bootstrap.Modal
2308 * @extends Roo.bootstrap.Component
2309 * Bootstrap Modal class
2310 * @cfg {String} title Title of dialog
2311 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2312 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2313 * @cfg {Boolean} specificTitle default false
2314 * @cfg {Array} buttons Array of buttons or standard button set..
2315 * @cfg {String} buttonPosition (left|right|center) default right
2316 * @cfg {Boolean} animate default true
2317 * @cfg {Boolean} allow_close default true
2320 * Create a new Modal Dialog
2321 * @param {Object} config The config object
2324 Roo.bootstrap.Modal = function(config){
2325 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2330 * The raw btnclick event for the button
2331 * @param {Roo.EventObject} e
2335 this.buttons = this.buttons || [];
2338 this.tmpl = Roo.factory(this.tmpl);
2343 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2345 title : 'test dialog',
2355 specificTitle: false,
2357 buttonPosition: 'right',
2371 onRender : function(ct, position)
2373 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2376 var cfg = Roo.apply({}, this.getAutoCreate());
2379 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2381 //if (!cfg.name.length) {
2385 cfg.cls += ' ' + this.cls;
2388 cfg.style = this.style;
2390 this.el = Roo.get(document.body).createChild(cfg, position);
2392 //var type = this.el.dom.type;
2397 if(this.tabIndex !== undefined){
2398 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2402 this.bodyEl = this.el.select('.modal-body',true).first();
2403 this.closeEl = this.el.select('.modal-header .close', true).first();
2404 this.footerEl = this.el.select('.modal-footer',true).first();
2405 this.titleEl = this.el.select('.modal-title',true).first();
2409 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2410 this.maskEl.enableDisplayMode("block");
2412 //this.el.addClass("x-dlg-modal");
2414 if (this.buttons.length) {
2415 Roo.each(this.buttons, function(bb) {
2416 b = Roo.apply({}, bb);
2417 b.xns = b.xns || Roo.bootstrap;
2418 b.xtype = b.xtype || 'Button';
2419 if (typeof(b.listeners) == 'undefined') {
2420 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2423 var btn = Roo.factory(b);
2425 btn.onRender(this.el.select('.modal-footer div').first());
2429 // render the children.
2432 if(typeof(this.items) != 'undefined'){
2433 var items = this.items;
2436 for(var i =0;i < items.length;i++) {
2437 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2441 this.items = nitems;
2443 // where are these used - they used to be body/close/footer
2447 //this.el.addClass([this.fieldClass, this.cls]);
2450 getAutoCreate : function(){
2455 html : this.html || ''
2460 cls : 'modal-title',
2464 if(this.specificTitle){
2470 if (this.allow_close) {
2481 style : 'display: none',
2484 cls: "modal-dialog",
2487 cls : "modal-content",
2490 cls : 'modal-header',
2495 cls : 'modal-footer',
2499 cls: 'btn-' + this.buttonPosition
2516 modal.cls += ' fade';
2522 getChildContainer : function() {
2527 getButtonContainer : function() {
2528 return this.el.select('.modal-footer div',true).first();
2531 initEvents : function()
2533 if (this.allow_close) {
2534 this.closeEl.on('click', this.hide, this);
2540 if (!this.rendered) {
2544 this.el.setStyle('display', 'block');
2548 (function(){ _this.el.addClass('in'); }).defer(50);
2550 this.el.addClass('in');
2553 // not sure how we can show data in here..
2555 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2558 Roo.get(document.body).addClass("x-body-masked");
2559 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2561 this.el.setStyle('zIndex', '10001');
2563 this.fireEvent('show', this);
2570 Roo.get(document.body).removeClass("x-body-masked");
2571 this.el.removeClass('in');
2575 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2577 this.el.setStyle('display', 'none');
2580 this.fireEvent('hide', this);
2583 addButton : function(str, cb)
2587 var b = Roo.apply({}, { html : str } );
2588 b.xns = b.xns || Roo.bootstrap;
2589 b.xtype = b.xtype || 'Button';
2590 if (typeof(b.listeners) == 'undefined') {
2591 b.listeners = { click : cb.createDelegate(this) };
2594 var btn = Roo.factory(b);
2596 btn.onRender(this.el.select('.modal-footer div').first());
2602 setDefaultButton : function(btn)
2604 //this.el.select('.modal-footer').()
2606 resizeTo: function(w,h)
2610 setContentSize : function(w, h)
2614 onButtonClick: function(btn,e)
2617 this.fireEvent('btnclick', btn.name, e);
2620 * Set the title of the Dialog
2621 * @param {String} str new Title
2623 setTitle: function(str) {
2624 this.titleEl.dom.innerHTML = str;
2627 * Set the body of the Dialog
2628 * @param {String} str new Title
2630 setBody: function(str) {
2631 this.bodyEl.dom.innerHTML = str;
2634 * Set the body of the Dialog using the template
2635 * @param {Obj} data - apply this data to the template and replace the body contents.
2637 applyBody: function(obj)
2640 Roo.log("Error - using apply Body without a template");
2643 this.tmpl.overwrite(this.bodyEl, obj);
2649 Roo.apply(Roo.bootstrap.Modal, {
2651 * Button config that displays a single OK button
2660 * Button config that displays Yes and No buttons
2676 * Button config that displays OK and Cancel buttons
2691 * Button config that displays Yes, No and Cancel buttons
2714 * messagebox - can be used as a replace
2718 * @class Roo.MessageBox
2719 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2723 Roo.Msg.alert('Status', 'Changes saved successfully.');
2725 // Prompt for user data:
2726 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2728 // process text value...
2732 // Show a dialog using config options:
2734 title:'Save Changes?',
2735 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2736 buttons: Roo.Msg.YESNOCANCEL,
2743 Roo.bootstrap.MessageBox = function(){
2744 var dlg, opt, mask, waitTimer;
2745 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2746 var buttons, activeTextEl, bwidth;
2750 var handleButton = function(button){
2752 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2756 var handleHide = function(){
2758 dlg.el.removeClass(opt.cls);
2761 // Roo.TaskMgr.stop(waitTimer);
2762 // waitTimer = null;
2767 var updateButtons = function(b){
2770 buttons["ok"].hide();
2771 buttons["cancel"].hide();
2772 buttons["yes"].hide();
2773 buttons["no"].hide();
2774 //dlg.footer.dom.style.display = 'none';
2777 dlg.footerEl.dom.style.display = '';
2778 for(var k in buttons){
2779 if(typeof buttons[k] != "function"){
2782 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2783 width += buttons[k].el.getWidth()+15;
2793 var handleEsc = function(d, k, e){
2794 if(opt && opt.closable !== false){
2804 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2805 * @return {Roo.BasicDialog} The BasicDialog element
2807 getDialog : function(){
2809 dlg = new Roo.bootstrap.Modal( {
2812 //constraintoviewport:false,
2814 //collapsible : false,
2819 //buttonAlign:"center",
2820 closeClick : function(){
2821 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2824 handleButton("cancel");
2829 dlg.on("hide", handleHide);
2831 //dlg.addKeyListener(27, handleEsc);
2833 this.buttons = buttons;
2834 var bt = this.buttonText;
2835 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2836 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2837 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2838 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2840 bodyEl = dlg.bodyEl.createChild({
2842 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2843 '<textarea class="roo-mb-textarea"></textarea>' +
2844 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2846 msgEl = bodyEl.dom.firstChild;
2847 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2848 textboxEl.enableDisplayMode();
2849 textboxEl.addKeyListener([10,13], function(){
2850 if(dlg.isVisible() && opt && opt.buttons){
2853 }else if(opt.buttons.yes){
2854 handleButton("yes");
2858 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2859 textareaEl.enableDisplayMode();
2860 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2861 progressEl.enableDisplayMode();
2862 var pf = progressEl.dom.firstChild;
2864 pp = Roo.get(pf.firstChild);
2865 pp.setHeight(pf.offsetHeight);
2873 * Updates the message box body text
2874 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2875 * the XHTML-compliant non-breaking space character '&#160;')
2876 * @return {Roo.MessageBox} This message box
2878 updateText : function(text){
2879 if(!dlg.isVisible() && !opt.width){
2880 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2882 msgEl.innerHTML = text || ' ';
2884 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2885 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2887 Math.min(opt.width || cw , this.maxWidth),
2888 Math.max(opt.minWidth || this.minWidth, bwidth)
2891 activeTextEl.setWidth(w);
2893 if(dlg.isVisible()){
2894 dlg.fixedcenter = false;
2896 // to big, make it scroll. = But as usual stupid IE does not support
2899 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2900 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2901 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2903 bodyEl.dom.style.height = '';
2904 bodyEl.dom.style.overflowY = '';
2907 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2909 bodyEl.dom.style.overflowX = '';
2912 dlg.setContentSize(w, bodyEl.getHeight());
2913 if(dlg.isVisible()){
2914 dlg.fixedcenter = true;
2920 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2921 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2922 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2923 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2924 * @return {Roo.MessageBox} This message box
2926 updateProgress : function(value, text){
2928 this.updateText(text);
2930 if (pp) { // weird bug on my firefox - for some reason this is not defined
2931 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2937 * Returns true if the message box is currently displayed
2938 * @return {Boolean} True if the message box is visible, else false
2940 isVisible : function(){
2941 return dlg && dlg.isVisible();
2945 * Hides the message box if it is displayed
2948 if(this.isVisible()){
2954 * Displays a new message box, or reinitializes an existing message box, based on the config options
2955 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2956 * The following config object properties are supported:
2958 Property Type Description
2959 ---------- --------------- ------------------------------------------------------------------------------------
2960 animEl String/Element An id or Element from which the message box should animate as it opens and
2961 closes (defaults to undefined)
2962 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2963 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2964 closable Boolean False to hide the top-right close button (defaults to true). Note that
2965 progress and wait dialogs will ignore this property and always hide the
2966 close button as they can only be closed programmatically.
2967 cls String A custom CSS class to apply to the message box element
2968 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2969 displayed (defaults to 75)
2970 fn Function A callback function to execute after closing the dialog. The arguments to the
2971 function will be btn (the name of the button that was clicked, if applicable,
2972 e.g. "ok"), and text (the value of the active text field, if applicable).
2973 Progress and wait dialogs will ignore this option since they do not respond to
2974 user actions and can only be closed programmatically, so any required function
2975 should be called by the same code after it closes the dialog.
2976 icon String A CSS class that provides a background image to be used as an icon for
2977 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2978 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2979 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2980 modal Boolean False to allow user interaction with the page while the message box is
2981 displayed (defaults to true)
2982 msg String A string that will replace the existing message box body text (defaults
2983 to the XHTML-compliant non-breaking space character ' ')
2984 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2985 progress Boolean True to display a progress bar (defaults to false)
2986 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2987 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2988 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2989 title String The title text
2990 value String The string value to set into the active textbox element if displayed
2991 wait Boolean True to display a progress bar (defaults to false)
2992 width Number The width of the dialog in pixels
2999 msg: 'Please enter your address:',
3001 buttons: Roo.MessageBox.OKCANCEL,
3004 animEl: 'addAddressBtn'
3007 * @param {Object} config Configuration options
3008 * @return {Roo.MessageBox} This message box
3010 show : function(options)
3013 // this causes nightmares if you show one dialog after another
3014 // especially on callbacks..
3016 if(this.isVisible()){
3019 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3020 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3021 Roo.log("New Dialog Message:" + options.msg )
3022 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3023 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3026 var d = this.getDialog();
3028 d.setTitle(opt.title || " ");
3029 d.closeEl.setDisplayed(opt.closable !== false);
3030 activeTextEl = textboxEl;
3031 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3036 textareaEl.setHeight(typeof opt.multiline == "number" ?
3037 opt.multiline : this.defaultTextHeight);
3038 activeTextEl = textareaEl;
3047 progressEl.setDisplayed(opt.progress === true);
3048 this.updateProgress(0);
3049 activeTextEl.dom.value = opt.value || "";
3051 dlg.setDefaultButton(activeTextEl);
3053 var bs = opt.buttons;
3057 }else if(bs && bs.yes){
3058 db = buttons["yes"];
3060 dlg.setDefaultButton(db);
3062 bwidth = updateButtons(opt.buttons);
3063 this.updateText(opt.msg);
3065 d.el.addClass(opt.cls);
3067 d.proxyDrag = opt.proxyDrag === true;
3068 d.modal = opt.modal !== false;
3069 d.mask = opt.modal !== false ? mask : false;
3071 // force it to the end of the z-index stack so it gets a cursor in FF
3072 document.body.appendChild(dlg.el.dom);
3073 d.animateTarget = null;
3074 d.show(options.animEl);
3080 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3081 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3082 * and closing the message box when the process is complete.
3083 * @param {String} title The title bar text
3084 * @param {String} msg The message box body text
3085 * @return {Roo.MessageBox} This message box
3087 progress : function(title, msg){
3094 minWidth: this.minProgressWidth,
3101 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3102 * If a callback function is passed it will be called after the user clicks the button, and the
3103 * id of the button that was clicked will be passed as the only parameter to the callback
3104 * (could also be the top-right close button).
3105 * @param {String} title The title bar text
3106 * @param {String} msg The message box body text
3107 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3108 * @param {Object} scope (optional) The scope of the callback function
3109 * @return {Roo.MessageBox} This message box
3111 alert : function(title, msg, fn, scope){
3124 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3125 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3126 * You are responsible for closing the message box when the process is complete.
3127 * @param {String} msg The message box body text
3128 * @param {String} title (optional) The title bar text
3129 * @return {Roo.MessageBox} This message box
3131 wait : function(msg, title){
3142 waitTimer = Roo.TaskMgr.start({
3144 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3152 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3153 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3154 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3155 * @param {String} title The title bar text
3156 * @param {String} msg The message box body text
3157 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3158 * @param {Object} scope (optional) The scope of the callback function
3159 * @return {Roo.MessageBox} This message box
3161 confirm : function(title, msg, fn, scope){
3165 buttons: this.YESNO,
3174 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3175 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3176 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3177 * (could also be the top-right close button) and the text that was entered will be passed as the two
3178 * parameters to the callback.
3179 * @param {String} title The title bar text
3180 * @param {String} msg The message box body text
3181 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3182 * @param {Object} scope (optional) The scope of the callback function
3183 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3184 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3185 * @return {Roo.MessageBox} This message box
3187 prompt : function(title, msg, fn, scope, multiline){
3191 buttons: this.OKCANCEL,
3196 multiline: multiline,
3203 * Button config that displays a single OK button
3208 * Button config that displays Yes and No buttons
3211 YESNO : {yes:true, no:true},
3213 * Button config that displays OK and Cancel buttons
3216 OKCANCEL : {ok:true, cancel:true},
3218 * Button config that displays Yes, No and Cancel buttons
3221 YESNOCANCEL : {yes:true, no:true, cancel:true},
3224 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3227 defaultTextHeight : 75,
3229 * The maximum width in pixels of the message box (defaults to 600)
3234 * The minimum width in pixels of the message box (defaults to 100)
3239 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3240 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3243 minProgressWidth : 250,
3245 * An object containing the default button text strings that can be overriden for localized language support.
3246 * Supported properties are: ok, cancel, yes and no.
3247 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3260 * Shorthand for {@link Roo.MessageBox}
3262 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3263 Roo.Msg = Roo.Msg || Roo.MessageBox;
3272 * @class Roo.bootstrap.Navbar
3273 * @extends Roo.bootstrap.Component
3274 * Bootstrap Navbar class
3277 * Create a new Navbar
3278 * @param {Object} config The config object
3282 Roo.bootstrap.Navbar = function(config){
3283 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3287 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3296 getAutoCreate : function(){
3299 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3303 initEvents :function ()
3305 //Roo.log(this.el.select('.navbar-toggle',true));
3306 this.el.select('.navbar-toggle',true).on('click', function() {
3307 // Roo.log('click');
3308 this.el.select('.navbar-collapse',true).toggleClass('in');
3316 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3318 var size = this.el.getSize();
3319 this.maskEl.setSize(size.width, size.height);
3320 this.maskEl.enableDisplayMode("block");
3329 getChildContainer : function()
3331 if (this.el.select('.collapse').getCount()) {
3332 return this.el.select('.collapse',true).first();
3365 * @class Roo.bootstrap.NavSimplebar
3366 * @extends Roo.bootstrap.Navbar
3367 * Bootstrap Sidebar class
3369 * @cfg {Boolean} inverse is inverted color
3371 * @cfg {String} type (nav | pills | tabs)
3372 * @cfg {Boolean} arrangement stacked | justified
3373 * @cfg {String} align (left | right) alignment
3375 * @cfg {Boolean} main (true|false) main nav bar? default false
3376 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3378 * @cfg {String} tag (header|footer|nav|div) default is nav
3384 * Create a new Sidebar
3385 * @param {Object} config The config object
3389 Roo.bootstrap.NavSimplebar = function(config){
3390 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3393 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3409 getAutoCreate : function(){
3413 tag : this.tag || 'div',
3426 this.type = this.type || 'nav';
3427 if (['tabs','pills'].indexOf(this.type)!==-1) {
3428 cfg.cn[0].cls += ' nav-' + this.type
3432 if (this.type!=='nav') {
3433 Roo.log('nav type must be nav/tabs/pills')
3435 cfg.cn[0].cls += ' navbar-nav'
3441 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3442 cfg.cn[0].cls += ' nav-' + this.arrangement;
3446 if (this.align === 'right') {
3447 cfg.cn[0].cls += ' navbar-right';
3451 cfg.cls += ' navbar-inverse';
3478 * @class Roo.bootstrap.NavHeaderbar
3479 * @extends Roo.bootstrap.NavSimplebar
3480 * Bootstrap Sidebar class
3482 * @cfg {String} brand what is brand
3483 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3484 * @cfg {String} brand_href href of the brand
3485 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3486 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3487 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3488 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3491 * Create a new Sidebar
3492 * @param {Object} config The config object
3496 Roo.bootstrap.NavHeaderbar = function(config){
3497 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3501 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3508 desktopCenter : false,
3511 getAutoCreate : function(){
3514 tag: this.nav || 'nav',
3521 if (this.desktopCenter) {
3522 cn.push({cls : 'container', cn : []});
3529 cls: 'navbar-header',
3534 cls: 'navbar-toggle',
3535 'data-toggle': 'collapse',
3540 html: 'Toggle navigation'
3562 cls: 'collapse navbar-collapse',
3566 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3568 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3569 cfg.cls += ' navbar-' + this.position;
3571 // tag can override this..
3573 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3576 if (this.brand !== '') {
3579 href: this.brand_href ? this.brand_href : '#',
3580 cls: 'navbar-brand',
3588 cfg.cls += ' main-nav';
3596 getHeaderChildContainer : function()
3598 if (this.el.select('.navbar-header').getCount()) {
3599 return this.el.select('.navbar-header',true).first();
3602 return this.getChildContainer();
3606 initEvents : function()
3608 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3610 if (this.autohide) {
3615 Roo.get(document).on('scroll',function(e) {
3616 var ns = Roo.get(document).getScroll().top;
3617 var os = prevScroll;
3621 ft.removeClass('slideDown');
3622 ft.addClass('slideUp');
3625 ft.removeClass('slideUp');
3626 ft.addClass('slideDown');
3647 * @class Roo.bootstrap.NavSidebar
3648 * @extends Roo.bootstrap.Navbar
3649 * Bootstrap Sidebar class
3652 * Create a new Sidebar
3653 * @param {Object} config The config object
3657 Roo.bootstrap.NavSidebar = function(config){
3658 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3661 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3663 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3665 getAutoCreate : function(){
3670 cls: 'sidebar sidebar-nav'
3692 * @class Roo.bootstrap.NavGroup
3693 * @extends Roo.bootstrap.Component
3694 * Bootstrap NavGroup class
3695 * @cfg {String} align (left|right)
3696 * @cfg {Boolean} inverse
3697 * @cfg {String} type (nav|pills|tab) default nav
3698 * @cfg {String} navId - reference Id for navbar.
3702 * Create a new nav group
3703 * @param {Object} config The config object
3706 Roo.bootstrap.NavGroup = function(config){
3707 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3710 Roo.bootstrap.NavGroup.register(this);
3714 * Fires when the active item changes
3715 * @param {Roo.bootstrap.NavGroup} this
3716 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3717 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3724 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3735 getAutoCreate : function()
3737 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3744 if (['tabs','pills'].indexOf(this.type)!==-1) {
3745 cfg.cls += ' nav-' + this.type
3747 if (this.type!=='nav') {
3748 Roo.log('nav type must be nav/tabs/pills')
3750 cfg.cls += ' navbar-nav'
3753 if (this.parent().sidebar) {
3756 cls: 'dashboard-menu sidebar-menu'
3762 if (this.form === true) {
3768 if (this.align === 'right') {
3769 cfg.cls += ' navbar-right';
3771 cfg.cls += ' navbar-left';
3775 if (this.align === 'right') {
3776 cfg.cls += ' navbar-right';
3780 cfg.cls += ' navbar-inverse';
3788 * sets the active Navigation item
3789 * @param {Roo.bootstrap.NavItem} the new current navitem
3791 setActiveItem : function(item)
3794 Roo.each(this.navItems, function(v){
3799 v.setActive(false, true);
3806 item.setActive(true, true);
3807 this.fireEvent('changed', this, item, prev);
3812 * gets the active Navigation item
3813 * @return {Roo.bootstrap.NavItem} the current navitem
3815 getActive : function()
3819 Roo.each(this.navItems, function(v){
3830 indexOfNav : function()
3834 Roo.each(this.navItems, function(v,i){
3845 * adds a Navigation item
3846 * @param {Roo.bootstrap.NavItem} the navitem to add
3848 addItem : function(cfg)
3850 var cn = new Roo.bootstrap.NavItem(cfg);
3852 cn.parentId = this.id;
3853 cn.onRender(this.el, null);
3857 * register a Navigation item
3858 * @param {Roo.bootstrap.NavItem} the navitem to add
3860 register : function(item)
3862 this.navItems.push( item);
3863 item.navId = this.navId;
3868 * clear all the Navigation item
3871 clearAll : function()
3874 this.el.dom.innerHTML = '';
3877 getNavItem: function(tabId)
3880 Roo.each(this.navItems, function(e) {
3881 if (e.tabId == tabId) {
3891 setActiveNext : function()
3893 var i = this.indexOfNav(this.getActive());
3894 if (i > this.navItems.length) {
3897 this.setActiveItem(this.navItems[i+1]);
3899 setActivePrev : function()
3901 var i = this.indexOfNav(this.getActive());
3905 this.setActiveItem(this.navItems[i-1]);
3907 clearWasActive : function(except) {
3908 Roo.each(this.navItems, function(e) {
3909 if (e.tabId != except.tabId && e.was_active) {
3910 e.was_active = false;
3917 getWasActive : function ()
3920 Roo.each(this.navItems, function(e) {
3935 Roo.apply(Roo.bootstrap.NavGroup, {
3939 * register a Navigation Group
3940 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3942 register : function(navgrp)
3944 this.groups[navgrp.navId] = navgrp;
3948 * fetch a Navigation Group based on the navigation ID
3949 * @param {string} the navgroup to add
3950 * @returns {Roo.bootstrap.NavGroup} the navgroup
3952 get: function(navId) {
3953 if (typeof(this.groups[navId]) == 'undefined') {
3955 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3957 return this.groups[navId] ;
3972 * @class Roo.bootstrap.NavItem
3973 * @extends Roo.bootstrap.Component
3974 * Bootstrap Navbar.NavItem class
3975 * @cfg {String} href link to
3976 * @cfg {String} html content of button
3977 * @cfg {String} badge text inside badge
3978 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3979 * @cfg {String} glyphicon name of glyphicon
3980 * @cfg {String} icon name of font awesome icon
3981 * @cfg {Boolean} active Is item active
3982 * @cfg {Boolean} disabled Is item disabled
3984 * @cfg {Boolean} preventDefault (true | false) default false
3985 * @cfg {String} tabId the tab that this item activates.
3986 * @cfg {String} tagtype (a|span) render as a href or span?
3987 * @cfg {Boolean} animateRef (true|false) link to element default false
3990 * Create a new Navbar Item
3991 * @param {Object} config The config object
3993 Roo.bootstrap.NavItem = function(config){
3994 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3999 * The raw click event for the entire grid.
4000 * @param {Roo.EventObject} e
4005 * Fires when the active item active state changes
4006 * @param {Roo.bootstrap.NavItem} this
4007 * @param {boolean} state the new state
4013 * Fires when scroll to element
4014 * @param {Roo.bootstrap.NavItem} this
4015 * @param {Object} options
4016 * @param {Roo.EventObject} e
4024 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4032 preventDefault : false,
4039 getAutoCreate : function(){
4047 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4049 if (this.disabled) {
4050 cfg.cls += ' disabled';
4053 if (this.href || this.html || this.glyphicon || this.icon) {
4057 href : this.href || "#",
4058 html: this.html || ''
4063 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4066 if(this.glyphicon) {
4067 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4072 cfg.cn[0].html += " <span class='caret'></span>";
4076 if (this.badge !== '') {
4078 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4086 initEvents: function()
4088 if (typeof (this.menu) != 'undefined') {
4089 this.menu.parentType = this.xtype;
4090 this.menu.triggerEl = this.el;
4091 this.menu = this.addxtype(Roo.apply({}, this.menu));
4094 this.el.select('a',true).on('click', this.onClick, this);
4096 if(this.tagtype == 'span'){
4097 this.el.select('span',true).on('click', this.onClick, this);
4100 // at this point parent should be available..
4101 this.parent().register(this);
4104 onClick : function(e)
4107 this.preventDefault ||
4114 if (this.disabled) {
4118 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4119 if (tg && tg.transition) {
4120 Roo.log("waiting for the transitionend");
4126 //Roo.log("fire event clicked");
4127 if(this.fireEvent('click', this, e) === false){
4131 if(this.tagtype == 'span'){
4135 //Roo.log(this.href);
4136 var ael = this.el.select('a',true).first();
4139 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4140 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4141 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4142 return; // ignore... - it's a 'hash' to another page.
4146 this.scrollToElement(e);
4150 var p = this.parent();
4152 if (['tabs','pills'].indexOf(p.type)!==-1) {
4153 if (typeof(p.setActiveItem) !== 'undefined') {
4154 p.setActiveItem(this);
4158 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4159 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4160 // remove the collapsed menu expand...
4161 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4165 isActive: function () {
4168 setActive : function(state, fire, is_was_active)
4170 if (this.active && !state & this.navId) {
4171 this.was_active = true;
4172 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4174 nv.clearWasActive(this);
4178 this.active = state;
4181 this.el.removeClass('active');
4182 } else if (!this.el.hasClass('active')) {
4183 this.el.addClass('active');
4186 this.fireEvent('changed', this, state);
4189 // show a panel if it's registered and related..
4191 if (!this.navId || !this.tabId || !state || is_was_active) {
4195 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4199 var pan = tg.getPanelByName(this.tabId);
4203 // if we can not flip to new panel - go back to old nav highlight..
4204 if (false == tg.showPanel(pan)) {
4205 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4207 var onav = nv.getWasActive();
4209 onav.setActive(true, false, true);
4218 // this should not be here...
4219 setDisabled : function(state)
4221 this.disabled = state;
4223 this.el.removeClass('disabled');
4224 } else if (!this.el.hasClass('disabled')) {
4225 this.el.addClass('disabled');
4231 * Fetch the element to display the tooltip on.
4232 * @return {Roo.Element} defaults to this.el
4234 tooltipEl : function()
4236 return this.el.select('' + this.tagtype + '', true).first();
4239 scrollToElement : function(e)
4241 var c = document.body;
4244 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4246 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4247 c = document.documentElement;
4250 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4256 var o = target.calcOffsetsTo(c);
4263 this.fireEvent('scrollto', this, options, e);
4265 Roo.get(c).scrollTo('top', options.value, true);
4278 * <span> icon </span>
4279 * <span> text </span>
4280 * <span>badge </span>
4284 * @class Roo.bootstrap.NavSidebarItem
4285 * @extends Roo.bootstrap.NavItem
4286 * Bootstrap Navbar.NavSidebarItem class
4288 * Create a new Navbar Button
4289 * @param {Object} config The config object
4291 Roo.bootstrap.NavSidebarItem = function(config){
4292 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4297 * The raw click event for the entire grid.
4298 * @param {Roo.EventObject} e
4303 * Fires when the active item active state changes
4304 * @param {Roo.bootstrap.NavSidebarItem} this
4305 * @param {boolean} state the new state
4313 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4316 getAutoCreate : function(){
4321 href : this.href || '#',
4333 html : this.html || ''
4338 cfg.cls += ' active';
4342 if (this.glyphicon || this.icon) {
4343 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4344 a.cn.push({ tag : 'i', cls : c }) ;
4349 if (this.badge !== '') {
4350 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4354 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4355 a.cls += 'dropdown-toggle treeview' ;
4379 * @class Roo.bootstrap.Row
4380 * @extends Roo.bootstrap.Component
4381 * Bootstrap Row class (contains columns...)
4385 * @param {Object} config The config object
4388 Roo.bootstrap.Row = function(config){
4389 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4392 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4394 getAutoCreate : function(){
4413 * @class Roo.bootstrap.Element
4414 * @extends Roo.bootstrap.Component
4415 * Bootstrap Element class
4416 * @cfg {String} html contents of the element
4417 * @cfg {String} tag tag of the element
4418 * @cfg {String} cls class of the element
4419 * @cfg {Boolean} preventDefault (true|false) default false
4420 * @cfg {Boolean} clickable (true|false) default false
4423 * Create a new Element
4424 * @param {Object} config The config object
4427 Roo.bootstrap.Element = function(config){
4428 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4434 * When a element is chick
4435 * @param {Roo.bootstrap.Element} this
4436 * @param {Roo.EventObject} e
4442 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4447 preventDefault: false,
4450 getAutoCreate : function(){
4461 initEvents: function()
4463 Roo.bootstrap.Element.superclass.initEvents.call(this);
4466 this.el.on('click', this.onClick, this);
4471 onClick : function(e)
4473 if(this.preventDefault){
4477 this.fireEvent('click', this, e);
4480 getValue : function()
4482 return this.el.dom.innerHTML;
4485 setValue : function(value)
4487 this.el.dom.innerHTML = value;
4502 * @class Roo.bootstrap.Pagination
4503 * @extends Roo.bootstrap.Component
4504 * Bootstrap Pagination class
4505 * @cfg {String} size xs | sm | md | lg
4506 * @cfg {Boolean} inverse false | true
4509 * Create a new Pagination
4510 * @param {Object} config The config object
4513 Roo.bootstrap.Pagination = function(config){
4514 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4517 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4523 getAutoCreate : function(){
4529 cfg.cls += ' inverse';
4535 cfg.cls += " " + this.cls;
4553 * @class Roo.bootstrap.PaginationItem
4554 * @extends Roo.bootstrap.Component
4555 * Bootstrap PaginationItem class
4556 * @cfg {String} html text
4557 * @cfg {String} href the link
4558 * @cfg {Boolean} preventDefault (true | false) default true
4559 * @cfg {Boolean} active (true | false) default false
4560 * @cfg {Boolean} disabled default false
4564 * Create a new PaginationItem
4565 * @param {Object} config The config object
4569 Roo.bootstrap.PaginationItem = function(config){
4570 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4575 * The raw click event for the entire grid.
4576 * @param {Roo.EventObject} e
4582 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4586 preventDefault: true,
4591 getAutoCreate : function(){
4597 href : this.href ? this.href : '#',
4598 html : this.html ? this.html : ''
4608 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4612 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4618 initEvents: function() {
4620 this.el.on('click', this.onClick, this);
4623 onClick : function(e)
4625 Roo.log('PaginationItem on click ');
4626 if(this.preventDefault){
4634 this.fireEvent('click', this, e);
4650 * @class Roo.bootstrap.Slider
4651 * @extends Roo.bootstrap.Component
4652 * Bootstrap Slider class
4655 * Create a new Slider
4656 * @param {Object} config The config object
4659 Roo.bootstrap.Slider = function(config){
4660 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4663 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4665 getAutoCreate : function(){
4669 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4673 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4685 * Ext JS Library 1.1.1
4686 * Copyright(c) 2006-2007, Ext JS, LLC.
4688 * Originally Released Under LGPL - original licence link has changed is not relivant.
4691 * <script type="text/javascript">
4696 * @class Roo.grid.ColumnModel
4697 * @extends Roo.util.Observable
4698 * This is the default implementation of a ColumnModel used by the Grid. It defines
4699 * the columns in the grid.
4702 var colModel = new Roo.grid.ColumnModel([
4703 {header: "Ticker", width: 60, sortable: true, locked: true},
4704 {header: "Company Name", width: 150, sortable: true},
4705 {header: "Market Cap.", width: 100, sortable: true},
4706 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4707 {header: "Employees", width: 100, sortable: true, resizable: false}
4712 * The config options listed for this class are options which may appear in each
4713 * individual column definition.
4714 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4716 * @param {Object} config An Array of column config objects. See this class's
4717 * config objects for details.
4719 Roo.grid.ColumnModel = function(config){
4721 * The config passed into the constructor
4723 this.config = config;
4726 // if no id, create one
4727 // if the column does not have a dataIndex mapping,
4728 // map it to the order it is in the config
4729 for(var i = 0, len = config.length; i < len; i++){
4731 if(typeof c.dataIndex == "undefined"){
4734 if(typeof c.renderer == "string"){
4735 c.renderer = Roo.util.Format[c.renderer];
4737 if(typeof c.id == "undefined"){
4740 if(c.editor && c.editor.xtype){
4741 c.editor = Roo.factory(c.editor, Roo.grid);
4743 if(c.editor && c.editor.isFormField){
4744 c.editor = new Roo.grid.GridEditor(c.editor);
4746 this.lookup[c.id] = c;
4750 * The width of columns which have no width specified (defaults to 100)
4753 this.defaultWidth = 100;
4756 * Default sortable of columns which have no sortable specified (defaults to false)
4759 this.defaultSortable = false;
4763 * @event widthchange
4764 * Fires when the width of a column changes.
4765 * @param {ColumnModel} this
4766 * @param {Number} columnIndex The column index
4767 * @param {Number} newWidth The new width
4769 "widthchange": true,
4771 * @event headerchange
4772 * Fires when the text of a header changes.
4773 * @param {ColumnModel} this
4774 * @param {Number} columnIndex The column index
4775 * @param {Number} newText The new header text
4777 "headerchange": true,
4779 * @event hiddenchange
4780 * Fires when a column is hidden or "unhidden".
4781 * @param {ColumnModel} this
4782 * @param {Number} columnIndex The column index
4783 * @param {Boolean} hidden true if hidden, false otherwise
4785 "hiddenchange": true,
4787 * @event columnmoved
4788 * Fires when a column is moved.
4789 * @param {ColumnModel} this
4790 * @param {Number} oldIndex
4791 * @param {Number} newIndex
4793 "columnmoved" : true,
4795 * @event columlockchange
4796 * Fires when a column's locked state is changed
4797 * @param {ColumnModel} this
4798 * @param {Number} colIndex
4799 * @param {Boolean} locked true if locked
4801 "columnlockchange" : true
4803 Roo.grid.ColumnModel.superclass.constructor.call(this);
4805 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4807 * @cfg {String} header The header text to display in the Grid view.
4810 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4811 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4812 * specified, the column's index is used as an index into the Record's data Array.
4815 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4816 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4819 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4820 * Defaults to the value of the {@link #defaultSortable} property.
4821 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4824 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4827 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4830 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4833 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4836 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4837 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4838 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4839 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4842 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4845 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4848 * @cfg {String} cursor (Optional)
4851 * @cfg {String} tooltip (Optional)
4854 * Returns the id of the column at the specified index.
4855 * @param {Number} index The column index
4856 * @return {String} the id
4858 getColumnId : function(index){
4859 return this.config[index].id;
4863 * Returns the column for a specified id.
4864 * @param {String} id The column id
4865 * @return {Object} the column
4867 getColumnById : function(id){
4868 return this.lookup[id];
4873 * Returns the column for a specified dataIndex.
4874 * @param {String} dataIndex The column dataIndex
4875 * @return {Object|Boolean} the column or false if not found
4877 getColumnByDataIndex: function(dataIndex){
4878 var index = this.findColumnIndex(dataIndex);
4879 return index > -1 ? this.config[index] : false;
4883 * Returns the index for a specified column id.
4884 * @param {String} id The column id
4885 * @return {Number} the index, or -1 if not found
4887 getIndexById : function(id){
4888 for(var i = 0, len = this.config.length; i < len; i++){
4889 if(this.config[i].id == id){
4897 * Returns the index for a specified column dataIndex.
4898 * @param {String} dataIndex The column dataIndex
4899 * @return {Number} the index, or -1 if not found
4902 findColumnIndex : function(dataIndex){
4903 for(var i = 0, len = this.config.length; i < len; i++){
4904 if(this.config[i].dataIndex == dataIndex){
4912 moveColumn : function(oldIndex, newIndex){
4913 var c = this.config[oldIndex];
4914 this.config.splice(oldIndex, 1);
4915 this.config.splice(newIndex, 0, c);
4916 this.dataMap = null;
4917 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4920 isLocked : function(colIndex){
4921 return this.config[colIndex].locked === true;
4924 setLocked : function(colIndex, value, suppressEvent){
4925 if(this.isLocked(colIndex) == value){
4928 this.config[colIndex].locked = value;
4930 this.fireEvent("columnlockchange", this, colIndex, value);
4934 getTotalLockedWidth : function(){
4936 for(var i = 0; i < this.config.length; i++){
4937 if(this.isLocked(i) && !this.isHidden(i)){
4938 this.totalWidth += this.getColumnWidth(i);
4944 getLockedCount : function(){
4945 for(var i = 0, len = this.config.length; i < len; i++){
4946 if(!this.isLocked(i)){
4953 * Returns the number of columns.
4956 getColumnCount : function(visibleOnly){
4957 if(visibleOnly === true){
4959 for(var i = 0, len = this.config.length; i < len; i++){
4960 if(!this.isHidden(i)){
4966 return this.config.length;
4970 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4971 * @param {Function} fn
4972 * @param {Object} scope (optional)
4973 * @return {Array} result
4975 getColumnsBy : function(fn, scope){
4977 for(var i = 0, len = this.config.length; i < len; i++){
4978 var c = this.config[i];
4979 if(fn.call(scope||this, c, i) === true){
4987 * Returns true if the specified column is sortable.
4988 * @param {Number} col The column index
4991 isSortable : function(col){
4992 if(typeof this.config[col].sortable == "undefined"){
4993 return this.defaultSortable;
4995 return this.config[col].sortable;
4999 * Returns the rendering (formatting) function defined for the column.
5000 * @param {Number} col The column index.
5001 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5003 getRenderer : function(col){
5004 if(!this.config[col].renderer){
5005 return Roo.grid.ColumnModel.defaultRenderer;
5007 return this.config[col].renderer;
5011 * Sets the rendering (formatting) function for a column.
5012 * @param {Number} col The column index
5013 * @param {Function} fn The function to use to process the cell's raw data
5014 * to return HTML markup for the grid view. The render function is called with
5015 * the following parameters:<ul>
5016 * <li>Data value.</li>
5017 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5018 * <li>css A CSS style string to apply to the table cell.</li>
5019 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5020 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5021 * <li>Row index</li>
5022 * <li>Column index</li>
5023 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5025 setRenderer : function(col, fn){
5026 this.config[col].renderer = fn;
5030 * Returns the width for the specified column.
5031 * @param {Number} col The column index
5034 getColumnWidth : function(col){
5035 return this.config[col].width * 1 || this.defaultWidth;
5039 * Sets the width for a column.
5040 * @param {Number} col The column index
5041 * @param {Number} width The new width
5043 setColumnWidth : function(col, width, suppressEvent){
5044 this.config[col].width = width;
5045 this.totalWidth = null;
5047 this.fireEvent("widthchange", this, col, width);
5052 * Returns the total width of all columns.
5053 * @param {Boolean} includeHidden True to include hidden column widths
5056 getTotalWidth : function(includeHidden){
5057 if(!this.totalWidth){
5058 this.totalWidth = 0;
5059 for(var i = 0, len = this.config.length; i < len; i++){
5060 if(includeHidden || !this.isHidden(i)){
5061 this.totalWidth += this.getColumnWidth(i);
5065 return this.totalWidth;
5069 * Returns the header for the specified column.
5070 * @param {Number} col The column index
5073 getColumnHeader : function(col){
5074 return this.config[col].header;
5078 * Sets the header for a column.
5079 * @param {Number} col The column index
5080 * @param {String} header The new header
5082 setColumnHeader : function(col, header){
5083 this.config[col].header = header;
5084 this.fireEvent("headerchange", this, col, header);
5088 * Returns the tooltip for the specified column.
5089 * @param {Number} col The column index
5092 getColumnTooltip : function(col){
5093 return this.config[col].tooltip;
5096 * Sets the tooltip for a column.
5097 * @param {Number} col The column index
5098 * @param {String} tooltip The new tooltip
5100 setColumnTooltip : function(col, tooltip){
5101 this.config[col].tooltip = tooltip;
5105 * Returns the dataIndex for the specified column.
5106 * @param {Number} col The column index
5109 getDataIndex : function(col){
5110 return this.config[col].dataIndex;
5114 * Sets the dataIndex for a column.
5115 * @param {Number} col The column index
5116 * @param {Number} dataIndex The new dataIndex
5118 setDataIndex : function(col, dataIndex){
5119 this.config[col].dataIndex = dataIndex;
5125 * Returns true if the cell is editable.
5126 * @param {Number} colIndex The column index
5127 * @param {Number} rowIndex The row index
5130 isCellEditable : function(colIndex, rowIndex){
5131 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5135 * Returns the editor defined for the cell/column.
5136 * return false or null to disable editing.
5137 * @param {Number} colIndex The column index
5138 * @param {Number} rowIndex The row index
5141 getCellEditor : function(colIndex, rowIndex){
5142 return this.config[colIndex].editor;
5146 * Sets if a column is editable.
5147 * @param {Number} col The column index
5148 * @param {Boolean} editable True if the column is editable
5150 setEditable : function(col, editable){
5151 this.config[col].editable = editable;
5156 * Returns true if the column is hidden.
5157 * @param {Number} colIndex The column index
5160 isHidden : function(colIndex){
5161 return this.config[colIndex].hidden;
5166 * Returns true if the column width cannot be changed
5168 isFixed : function(colIndex){
5169 return this.config[colIndex].fixed;
5173 * Returns true if the column can be resized
5176 isResizable : function(colIndex){
5177 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5180 * Sets if a column is hidden.
5181 * @param {Number} colIndex The column index
5182 * @param {Boolean} hidden True if the column is hidden
5184 setHidden : function(colIndex, hidden){
5185 this.config[colIndex].hidden = hidden;
5186 this.totalWidth = null;
5187 this.fireEvent("hiddenchange", this, colIndex, hidden);
5191 * Sets the editor for a column.
5192 * @param {Number} col The column index
5193 * @param {Object} editor The editor object
5195 setEditor : function(col, editor){
5196 this.config[col].editor = editor;
5200 Roo.grid.ColumnModel.defaultRenderer = function(value){
5201 if(typeof value == "string" && value.length < 1){
5207 // Alias for backwards compatibility
5208 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5211 * Ext JS Library 1.1.1
5212 * Copyright(c) 2006-2007, Ext JS, LLC.
5214 * Originally Released Under LGPL - original licence link has changed is not relivant.
5217 * <script type="text/javascript">
5221 * @class Roo.LoadMask
5222 * A simple utility class for generically masking elements while loading data. If the element being masked has
5223 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5224 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5225 * element's UpdateManager load indicator and will be destroyed after the initial load.
5227 * Create a new LoadMask
5228 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5229 * @param {Object} config The config object
5231 Roo.LoadMask = function(el, config){
5232 this.el = Roo.get(el);
5233 Roo.apply(this, config);
5235 this.store.on('beforeload', this.onBeforeLoad, this);
5236 this.store.on('load', this.onLoad, this);
5237 this.store.on('loadexception', this.onLoadException, this);
5238 this.removeMask = false;
5240 var um = this.el.getUpdateManager();
5241 um.showLoadIndicator = false; // disable the default indicator
5242 um.on('beforeupdate', this.onBeforeLoad, this);
5243 um.on('update', this.onLoad, this);
5244 um.on('failure', this.onLoad, this);
5245 this.removeMask = true;
5249 Roo.LoadMask.prototype = {
5251 * @cfg {Boolean} removeMask
5252 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5253 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5257 * The text to display in a centered loading message box (defaults to 'Loading...')
5261 * @cfg {String} msgCls
5262 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5264 msgCls : 'x-mask-loading',
5267 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5273 * Disables the mask to prevent it from being displayed
5275 disable : function(){
5276 this.disabled = true;
5280 * Enables the mask so that it can be displayed
5282 enable : function(){
5283 this.disabled = false;
5286 onLoadException : function()
5290 if (typeof(arguments[3]) != 'undefined') {
5291 Roo.MessageBox.alert("Error loading",arguments[3]);
5295 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5296 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5305 this.el.unmask(this.removeMask);
5310 this.el.unmask(this.removeMask);
5314 onBeforeLoad : function(){
5316 this.el.mask(this.msg, this.msgCls);
5321 destroy : function(){
5323 this.store.un('beforeload', this.onBeforeLoad, this);
5324 this.store.un('load', this.onLoad, this);
5325 this.store.un('loadexception', this.onLoadException, this);
5327 var um = this.el.getUpdateManager();
5328 um.un('beforeupdate', this.onBeforeLoad, this);
5329 um.un('update', this.onLoad, this);
5330 um.un('failure', this.onLoad, this);
5341 * @class Roo.bootstrap.Table
5342 * @extends Roo.bootstrap.Component
5343 * Bootstrap Table class
5344 * @cfg {String} cls table class
5345 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5346 * @cfg {String} bgcolor Specifies the background color for a table
5347 * @cfg {Number} border Specifies whether the table cells should have borders or not
5348 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5349 * @cfg {Number} cellspacing Specifies the space between cells
5350 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5351 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5352 * @cfg {String} sortable Specifies that the table should be sortable
5353 * @cfg {String} summary Specifies a summary of the content of a table
5354 * @cfg {Number} width Specifies the width of a table
5355 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5357 * @cfg {boolean} striped Should the rows be alternative striped
5358 * @cfg {boolean} bordered Add borders to the table
5359 * @cfg {boolean} hover Add hover highlighting
5360 * @cfg {boolean} condensed Format condensed
5361 * @cfg {boolean} responsive Format condensed
5362 * @cfg {Boolean} loadMask (true|false) default false
5363 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5364 * @cfg {Boolean} thead (true|false) generate thead, default true
5365 * @cfg {Boolean} RowSelection (true|false) default false
5366 * @cfg {Boolean} CellSelection (true|false) default false
5367 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5371 * Create a new Table
5372 * @param {Object} config The config object
5375 Roo.bootstrap.Table = function(config){
5376 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5379 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5380 this.sm = this.selModel;
5381 this.sm.xmodule = this.xmodule || false;
5383 if (this.cm && typeof(this.cm.config) == 'undefined') {
5384 this.colModel = new Roo.grid.ColumnModel(this.cm);
5385 this.cm = this.colModel;
5386 this.cm.xmodule = this.xmodule || false;
5389 this.store= Roo.factory(this.store, Roo.data);
5390 this.ds = this.store;
5391 this.ds.xmodule = this.xmodule || false;
5394 if (this.footer && this.store) {
5395 this.footer.dataSource = this.ds;
5396 this.footer = Roo.factory(this.footer);
5403 * Fires when a cell is clicked
5404 * @param {Roo.bootstrap.Table} this
5405 * @param {Roo.Element} el
5406 * @param {Number} rowIndex
5407 * @param {Number} columnIndex
5408 * @param {Roo.EventObject} e
5412 * @event celldblclick
5413 * Fires when a cell is double clicked
5414 * @param {Roo.bootstrap.Table} this
5415 * @param {Roo.Element} el
5416 * @param {Number} rowIndex
5417 * @param {Number} columnIndex
5418 * @param {Roo.EventObject} e
5420 "celldblclick" : true,
5423 * Fires when a row is clicked
5424 * @param {Roo.bootstrap.Table} this
5425 * @param {Roo.Element} el
5426 * @param {Number} rowIndex
5427 * @param {Roo.EventObject} e
5431 * @event rowdblclick
5432 * Fires when a row is double clicked
5433 * @param {Roo.bootstrap.Table} this
5434 * @param {Roo.Element} el
5435 * @param {Number} rowIndex
5436 * @param {Roo.EventObject} e
5438 "rowdblclick" : true,
5441 * Fires when a mouseover occur
5442 * @param {Roo.bootstrap.Table} this
5443 * @param {Roo.Element} el
5444 * @param {Number} rowIndex
5445 * @param {Number} columnIndex
5446 * @param {Roo.EventObject} e
5451 * Fires when a mouseout occur
5452 * @param {Roo.bootstrap.Table} this
5453 * @param {Roo.Element} el
5454 * @param {Number} rowIndex
5455 * @param {Number} columnIndex
5456 * @param {Roo.EventObject} e
5461 * Fires when a row is rendered, so you can change add a style to it.
5462 * @param {Roo.bootstrap.Table} this
5463 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5467 * @event rowsrendered
5468 * Fires when all the rows have been rendered
5469 * @param {Roo.bootstrap.Table} this
5471 'rowsrendered' : true
5476 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5500 RowSelection : false,
5501 CellSelection : false,
5504 // Roo.Element - the tbody
5507 getAutoCreate : function(){
5508 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5517 cfg.cls += ' table-striped';
5521 cfg.cls += ' table-hover';
5523 if (this.bordered) {
5524 cfg.cls += ' table-bordered';
5526 if (this.condensed) {
5527 cfg.cls += ' table-condensed';
5529 if (this.responsive) {
5530 cfg.cls += ' table-responsive';
5534 cfg.cls+= ' ' +this.cls;
5537 // this lot should be simplifed...
5540 cfg.align=this.align;
5543 cfg.bgcolor=this.bgcolor;
5546 cfg.border=this.border;
5548 if (this.cellpadding) {
5549 cfg.cellpadding=this.cellpadding;
5551 if (this.cellspacing) {
5552 cfg.cellspacing=this.cellspacing;
5555 cfg.frame=this.frame;
5558 cfg.rules=this.rules;
5560 if (this.sortable) {
5561 cfg.sortable=this.sortable;
5564 cfg.summary=this.summary;
5567 cfg.width=this.width;
5570 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5573 if(this.store || this.cm){
5575 cfg.cn.push(this.renderHeader());
5578 cfg.cn.push(this.renderBody());
5581 cfg.cn.push(this.renderFooter());
5584 cfg.cls+= ' TableGrid';
5587 return { cn : [ cfg ] };
5590 initEvents : function()
5592 if(!this.store || !this.cm){
5596 //Roo.log('initEvents with ds!!!!');
5598 this.mainBody = this.el.select('tbody', true).first();
5603 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5604 e.on('click', _this.sort, _this);
5607 this.el.on("click", this.onClick, this);
5608 this.el.on("dblclick", this.onDblClick, this);
5610 // why is this done????? = it breaks dialogs??
5611 //this.parent().el.setStyle('position', 'relative');
5615 this.footer.parentId = this.id;
5616 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5619 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5621 this.store.on('load', this.onLoad, this);
5622 this.store.on('beforeload', this.onBeforeLoad, this);
5623 this.store.on('update', this.onUpdate, this);
5624 this.store.on('add', this.onAdd, this);
5628 onMouseover : function(e, el)
5630 var cell = Roo.get(el);
5636 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5637 cell = cell.findParent('td', false, true);
5640 var row = cell.findParent('tr', false, true);
5641 var cellIndex = cell.dom.cellIndex;
5642 var rowIndex = row.dom.rowIndex - 1; // start from 0
5644 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5648 onMouseout : function(e, el)
5650 var cell = Roo.get(el);
5656 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5657 cell = cell.findParent('td', false, true);
5660 var row = cell.findParent('tr', false, true);
5661 var cellIndex = cell.dom.cellIndex;
5662 var rowIndex = row.dom.rowIndex - 1; // start from 0
5664 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5668 onClick : function(e, el)
5670 var cell = Roo.get(el);
5672 if(!cell || (!this.CellSelection && !this.RowSelection)){
5676 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5677 cell = cell.findParent('td', false, true);
5680 if(!cell || typeof(cell) == 'undefined'){
5684 var row = cell.findParent('tr', false, true);
5686 if(!row || typeof(row) == 'undefined'){
5690 var cellIndex = cell.dom.cellIndex;
5691 var rowIndex = this.getRowIndex(row);
5693 if(this.CellSelection){
5694 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5697 if(this.RowSelection){
5698 this.fireEvent('rowclick', this, row, rowIndex, e);
5704 onDblClick : function(e,el)
5706 var cell = Roo.get(el);
5708 if(!cell || (!this.CellSelection && !this.RowSelection)){
5712 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5713 cell = cell.findParent('td', false, true);
5716 if(!cell || typeof(cell) == 'undefined'){
5720 var row = cell.findParent('tr', false, true);
5722 if(!row || typeof(row) == 'undefined'){
5726 var cellIndex = cell.dom.cellIndex;
5727 var rowIndex = this.getRowIndex(row);
5729 if(this.CellSelection){
5730 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5733 if(this.RowSelection){
5734 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5738 sort : function(e,el)
5740 var col = Roo.get(el);
5742 if(!col.hasClass('sortable')){
5746 var sort = col.attr('sort');
5749 if(col.hasClass('glyphicon-arrow-up')){
5753 this.store.sortInfo = {field : sort, direction : dir};
5756 Roo.log("calling footer first");
5757 this.footer.onClick('first');
5760 this.store.load({ params : { start : 0 } });
5764 renderHeader : function()
5773 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5775 var config = cm.config[i];
5780 html: cm.getColumnHeader(i)
5783 if(typeof(config.tooltip) != 'undefined'){
5784 c.tooltip = config.tooltip;
5787 if(typeof(config.colspan) != 'undefined'){
5788 c.colspan = config.colspan;
5791 if(typeof(config.hidden) != 'undefined' && config.hidden){
5792 c.style += ' display:none;';
5795 if(typeof(config.dataIndex) != 'undefined'){
5796 c.sort = config.dataIndex;
5799 if(typeof(config.sortable) != 'undefined' && config.sortable){
5803 if(typeof(config.align) != 'undefined' && config.align.length){
5804 c.style += ' text-align:' + config.align + ';';
5807 if(typeof(config.width) != 'undefined'){
5808 c.style += ' width:' + config.width + 'px;';
5811 if(typeof(config.cls) != 'undefined'){
5812 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5821 renderBody : function()
5831 colspan : this.cm.getColumnCount()
5841 renderFooter : function()
5851 colspan : this.cm.getColumnCount()
5865 Roo.log('ds onload');
5870 var ds = this.store;
5872 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5873 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5875 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5876 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5879 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5880 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5884 var tbody = this.mainBody;
5886 if(ds.getCount() > 0){
5887 ds.data.each(function(d,rowIndex){
5888 var row = this.renderRow(cm, ds, rowIndex);
5890 tbody.createChild(row);
5894 if(row.cellObjects.length){
5895 Roo.each(row.cellObjects, function(r){
5896 _this.renderCellObject(r);
5903 Roo.each(this.el.select('tbody td', true).elements, function(e){
5904 e.on('mouseover', _this.onMouseover, _this);
5907 Roo.each(this.el.select('tbody td', true).elements, function(e){
5908 e.on('mouseout', _this.onMouseout, _this);
5910 this.fireEvent('rowsrendered', this);
5911 //if(this.loadMask){
5912 // this.maskEl.hide();
5917 onUpdate : function(ds,record)
5919 this.refreshRow(record);
5922 onRemove : function(ds, record, index, isUpdate){
5923 if(isUpdate !== true){
5924 this.fireEvent("beforerowremoved", this, index, record);
5926 var bt = this.mainBody.dom;
5928 var rows = this.el.select('tbody > tr', true).elements;
5930 if(typeof(rows[index]) != 'undefined'){
5931 bt.removeChild(rows[index].dom);
5934 // if(bt.rows[index]){
5935 // bt.removeChild(bt.rows[index]);
5938 if(isUpdate !== true){
5939 //this.stripeRows(index);
5940 //this.syncRowHeights(index, index);
5942 this.fireEvent("rowremoved", this, index, record);
5946 onAdd : function(ds, records, rowIndex)
5948 //Roo.log('on Add called');
5949 // - note this does not handle multiple adding very well..
5950 var bt = this.mainBody.dom;
5951 for (var i =0 ; i < records.length;i++) {
5952 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5953 //Roo.log(records[i]);
5954 //Roo.log(this.store.getAt(rowIndex+i));
5955 this.insertRow(this.store, rowIndex + i, false);
5962 refreshRow : function(record){
5963 var ds = this.store, index;
5964 if(typeof record == 'number'){
5966 record = ds.getAt(index);
5968 index = ds.indexOf(record);
5970 this.insertRow(ds, index, true);
5971 this.onRemove(ds, record, index+1, true);
5972 //this.syncRowHeights(index, index);
5974 this.fireEvent("rowupdated", this, index, record);
5977 insertRow : function(dm, rowIndex, isUpdate){
5980 this.fireEvent("beforerowsinserted", this, rowIndex);
5982 //var s = this.getScrollState();
5983 var row = this.renderRow(this.cm, this.store, rowIndex);
5984 // insert before rowIndex..
5985 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5989 if(row.cellObjects.length){
5990 Roo.each(row.cellObjects, function(r){
5991 _this.renderCellObject(r);
5996 this.fireEvent("rowsinserted", this, rowIndex);
5997 //this.syncRowHeights(firstRow, lastRow);
5998 //this.stripeRows(firstRow);
6005 getRowDom : function(rowIndex)
6007 var rows = this.el.select('tbody > tr', true).elements;
6009 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6012 // returns the object tree for a tr..
6015 renderRow : function(cm, ds, rowIndex)
6018 var d = ds.getAt(rowIndex);
6025 var cellObjects = [];
6027 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6028 var config = cm.config[i];
6030 var renderer = cm.getRenderer(i);
6034 if(typeof(renderer) !== 'undefined'){
6035 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6037 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6038 // and are rendered into the cells after the row is rendered - using the id for the element.
6040 if(typeof(value) === 'object'){
6050 rowIndex : rowIndex,
6055 this.fireEvent('rowclass', this, rowcfg);
6059 cls : rowcfg.rowClass,
6061 html: (typeof(value) === 'object') ? '' : value
6068 if(typeof(config.colspan) != 'undefined'){
6069 td.colspan = config.colspan;
6072 if(typeof(config.hidden) != 'undefined' && config.hidden){
6073 td.style += ' display:none;';
6076 if(typeof(config.align) != 'undefined' && config.align.length){
6077 td.style += ' text-align:' + config.align + ';';
6080 if(typeof(config.width) != 'undefined'){
6081 td.style += ' width:' + config.width + 'px;';
6084 if(typeof(config.cursor) != 'undefined'){
6085 td.style += ' cursor:' + config.cursor + ';';
6088 if(typeof(config.cls) != 'undefined'){
6089 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6096 row.cellObjects = cellObjects;
6104 onBeforeLoad : function()
6106 //Roo.log('ds onBeforeLoad');
6110 //if(this.loadMask){
6111 // this.maskEl.show();
6119 this.el.select('tbody', true).first().dom.innerHTML = '';
6122 * Show or hide a row.
6123 * @param {Number} rowIndex to show or hide
6124 * @param {Boolean} state hide
6126 setRowVisibility : function(rowIndex, state)
6128 var bt = this.mainBody.dom;
6130 var rows = this.el.select('tbody > tr', true).elements;
6132 if(typeof(rows[rowIndex]) == 'undefined'){
6135 rows[rowIndex].dom.style.display = state ? '' : 'none';
6139 getSelectionModel : function(){
6141 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6143 return this.selModel;
6146 * Render the Roo.bootstrap object from renderder
6148 renderCellObject : function(r)
6152 var t = r.cfg.render(r.container);
6155 Roo.each(r.cfg.cn, function(c){
6157 container: t.getChildContainer(),
6160 _this.renderCellObject(child);
6165 getRowIndex : function(row)
6169 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6192 * @class Roo.bootstrap.TableCell
6193 * @extends Roo.bootstrap.Component
6194 * Bootstrap TableCell class
6195 * @cfg {String} html cell contain text
6196 * @cfg {String} cls cell class
6197 * @cfg {String} tag cell tag (td|th) default td
6198 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6199 * @cfg {String} align Aligns the content in a cell
6200 * @cfg {String} axis Categorizes cells
6201 * @cfg {String} bgcolor Specifies the background color of a cell
6202 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6203 * @cfg {Number} colspan Specifies the number of columns a cell should span
6204 * @cfg {String} headers Specifies one or more header cells a cell is related to
6205 * @cfg {Number} height Sets the height of a cell
6206 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6207 * @cfg {Number} rowspan Sets the number of rows a cell should span
6208 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6209 * @cfg {String} valign Vertical aligns the content in a cell
6210 * @cfg {Number} width Specifies the width of a cell
6213 * Create a new TableCell
6214 * @param {Object} config The config object
6217 Roo.bootstrap.TableCell = function(config){
6218 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6221 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6241 getAutoCreate : function(){
6242 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6262 cfg.align=this.align
6268 cfg.bgcolor=this.bgcolor
6271 cfg.charoff=this.charoff
6274 cfg.colspan=this.colspan
6277 cfg.headers=this.headers
6280 cfg.height=this.height
6283 cfg.nowrap=this.nowrap
6286 cfg.rowspan=this.rowspan
6289 cfg.scope=this.scope
6292 cfg.valign=this.valign
6295 cfg.width=this.width
6314 * @class Roo.bootstrap.TableRow
6315 * @extends Roo.bootstrap.Component
6316 * Bootstrap TableRow class
6317 * @cfg {String} cls row class
6318 * @cfg {String} align Aligns the content in a table row
6319 * @cfg {String} bgcolor Specifies a background color for a table row
6320 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6321 * @cfg {String} valign Vertical aligns the content in a table row
6324 * Create a new TableRow
6325 * @param {Object} config The config object
6328 Roo.bootstrap.TableRow = function(config){
6329 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6332 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6340 getAutoCreate : function(){
6341 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6351 cfg.align = this.align;
6354 cfg.bgcolor = this.bgcolor;
6357 cfg.charoff = this.charoff;
6360 cfg.valign = this.valign;
6378 * @class Roo.bootstrap.TableBody
6379 * @extends Roo.bootstrap.Component
6380 * Bootstrap TableBody class
6381 * @cfg {String} cls element class
6382 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6383 * @cfg {String} align Aligns the content inside the element
6384 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6385 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6388 * Create a new TableBody
6389 * @param {Object} config The config object
6392 Roo.bootstrap.TableBody = function(config){
6393 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6396 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6404 getAutoCreate : function(){
6405 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6419 cfg.align = this.align;
6422 cfg.charoff = this.charoff;
6425 cfg.valign = this.valign;
6432 // initEvents : function()
6439 // this.store = Roo.factory(this.store, Roo.data);
6440 // this.store.on('load', this.onLoad, this);
6442 // this.store.load();
6446 // onLoad: function ()
6448 // this.fireEvent('load', this);
6458 * Ext JS Library 1.1.1
6459 * Copyright(c) 2006-2007, Ext JS, LLC.
6461 * Originally Released Under LGPL - original licence link has changed is not relivant.
6464 * <script type="text/javascript">
6467 // as we use this in bootstrap.
6468 Roo.namespace('Roo.form');
6470 * @class Roo.form.Action
6471 * Internal Class used to handle form actions
6473 * @param {Roo.form.BasicForm} el The form element or its id
6474 * @param {Object} config Configuration options
6479 // define the action interface
6480 Roo.form.Action = function(form, options){
6482 this.options = options || {};
6485 * Client Validation Failed
6488 Roo.form.Action.CLIENT_INVALID = 'client';
6490 * Server Validation Failed
6493 Roo.form.Action.SERVER_INVALID = 'server';
6495 * Connect to Server Failed
6498 Roo.form.Action.CONNECT_FAILURE = 'connect';
6500 * Reading Data from Server Failed
6503 Roo.form.Action.LOAD_FAILURE = 'load';
6505 Roo.form.Action.prototype = {
6507 failureType : undefined,
6508 response : undefined,
6512 run : function(options){
6517 success : function(response){
6522 handleResponse : function(response){
6526 // default connection failure
6527 failure : function(response){
6529 this.response = response;
6530 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6531 this.form.afterAction(this, false);
6534 processResponse : function(response){
6535 this.response = response;
6536 if(!response.responseText){
6539 this.result = this.handleResponse(response);
6543 // utility functions used internally
6544 getUrl : function(appendParams){
6545 var url = this.options.url || this.form.url || this.form.el.dom.action;
6547 var p = this.getParams();
6549 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6555 getMethod : function(){
6556 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6559 getParams : function(){
6560 var bp = this.form.baseParams;
6561 var p = this.options.params;
6563 if(typeof p == "object"){
6564 p = Roo.urlEncode(Roo.applyIf(p, bp));
6565 }else if(typeof p == 'string' && bp){
6566 p += '&' + Roo.urlEncode(bp);
6569 p = Roo.urlEncode(bp);
6574 createCallback : function(){
6576 success: this.success,
6577 failure: this.failure,
6579 timeout: (this.form.timeout*1000),
6580 upload: this.form.fileUpload ? this.success : undefined
6585 Roo.form.Action.Submit = function(form, options){
6586 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6589 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6592 haveProgress : false,
6593 uploadComplete : false,
6595 // uploadProgress indicator.
6596 uploadProgress : function()
6598 if (!this.form.progressUrl) {
6602 if (!this.haveProgress) {
6603 Roo.MessageBox.progress("Uploading", "Uploading");
6605 if (this.uploadComplete) {
6606 Roo.MessageBox.hide();
6610 this.haveProgress = true;
6612 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6614 var c = new Roo.data.Connection();
6616 url : this.form.progressUrl,
6621 success : function(req){
6622 //console.log(data);
6626 rdata = Roo.decode(req.responseText)
6628 Roo.log("Invalid data from server..");
6632 if (!rdata || !rdata.success) {
6634 Roo.MessageBox.alert(Roo.encode(rdata));
6637 var data = rdata.data;
6639 if (this.uploadComplete) {
6640 Roo.MessageBox.hide();
6645 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6646 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6649 this.uploadProgress.defer(2000,this);
6652 failure: function(data) {
6653 Roo.log('progress url failed ');
6664 // run get Values on the form, so it syncs any secondary forms.
6665 this.form.getValues();
6667 var o = this.options;
6668 var method = this.getMethod();
6669 var isPost = method == 'POST';
6670 if(o.clientValidation === false || this.form.isValid()){
6672 if (this.form.progressUrl) {
6673 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6674 (new Date() * 1) + '' + Math.random());
6679 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6680 form:this.form.el.dom,
6681 url:this.getUrl(!isPost),
6683 params:isPost ? this.getParams() : null,
6684 isUpload: this.form.fileUpload
6687 this.uploadProgress();
6689 }else if (o.clientValidation !== false){ // client validation failed
6690 this.failureType = Roo.form.Action.CLIENT_INVALID;
6691 this.form.afterAction(this, false);
6695 success : function(response)
6697 this.uploadComplete= true;
6698 if (this.haveProgress) {
6699 Roo.MessageBox.hide();
6703 var result = this.processResponse(response);
6704 if(result === true || result.success){
6705 this.form.afterAction(this, true);
6709 this.form.markInvalid(result.errors);
6710 this.failureType = Roo.form.Action.SERVER_INVALID;
6712 this.form.afterAction(this, false);
6714 failure : function(response)
6716 this.uploadComplete= true;
6717 if (this.haveProgress) {
6718 Roo.MessageBox.hide();
6721 this.response = response;
6722 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6723 this.form.afterAction(this, false);
6726 handleResponse : function(response){
6727 if(this.form.errorReader){
6728 var rs = this.form.errorReader.read(response);
6731 for(var i = 0, len = rs.records.length; i < len; i++) {
6732 var r = rs.records[i];
6736 if(errors.length < 1){
6740 success : rs.success,
6746 ret = Roo.decode(response.responseText);
6750 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6760 Roo.form.Action.Load = function(form, options){
6761 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6762 this.reader = this.form.reader;
6765 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6770 Roo.Ajax.request(Roo.apply(
6771 this.createCallback(), {
6772 method:this.getMethod(),
6773 url:this.getUrl(false),
6774 params:this.getParams()
6778 success : function(response){
6780 var result = this.processResponse(response);
6781 if(result === true || !result.success || !result.data){
6782 this.failureType = Roo.form.Action.LOAD_FAILURE;
6783 this.form.afterAction(this, false);
6786 this.form.clearInvalid();
6787 this.form.setValues(result.data);
6788 this.form.afterAction(this, true);
6791 handleResponse : function(response){
6792 if(this.form.reader){
6793 var rs = this.form.reader.read(response);
6794 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6796 success : rs.success,
6800 return Roo.decode(response.responseText);
6804 Roo.form.Action.ACTION_TYPES = {
6805 'load' : Roo.form.Action.Load,
6806 'submit' : Roo.form.Action.Submit
6815 * @class Roo.bootstrap.Form
6816 * @extends Roo.bootstrap.Component
6817 * Bootstrap Form class
6818 * @cfg {String} method GET | POST (default POST)
6819 * @cfg {String} labelAlign top | left (default top)
6820 * @cfg {String} align left | right - for navbars
6821 * @cfg {Boolean} loadMask load mask when submit (default true)
6826 * @param {Object} config The config object
6830 Roo.bootstrap.Form = function(config){
6831 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6834 * @event clientvalidation
6835 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6836 * @param {Form} this
6837 * @param {Boolean} valid true if the form has passed client-side validation
6839 clientvalidation: true,
6841 * @event beforeaction
6842 * Fires before any action is performed. Return false to cancel the action.
6843 * @param {Form} this
6844 * @param {Action} action The action to be performed
6848 * @event actionfailed
6849 * Fires when an action fails.
6850 * @param {Form} this
6851 * @param {Action} action The action that failed
6853 actionfailed : true,
6855 * @event actioncomplete
6856 * Fires when an action is completed.
6857 * @param {Form} this
6858 * @param {Action} action The action that completed
6860 actioncomplete : true
6865 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6868 * @cfg {String} method
6869 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6874 * The URL to use for form actions if one isn't supplied in the action options.
6877 * @cfg {Boolean} fileUpload
6878 * Set to true if this form is a file upload.
6882 * @cfg {Object} baseParams
6883 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6887 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6891 * @cfg {Sting} align (left|right) for navbar forms
6896 activeAction : null,
6899 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6900 * element by passing it or its id or mask the form itself by passing in true.
6903 waitMsgTarget : false,
6907 getAutoCreate : function(){
6911 method : this.method || 'POST',
6912 id : this.id || Roo.id(),
6915 if (this.parent().xtype.match(/^Nav/)) {
6916 cfg.cls = 'navbar-form navbar-' + this.align;
6920 if (this.labelAlign == 'left' ) {
6921 cfg.cls += ' form-horizontal';
6927 initEvents : function()
6929 this.el.on('submit', this.onSubmit, this);
6930 // this was added as random key presses on the form where triggering form submit.
6931 this.el.on('keypress', function(e) {
6932 if (e.getCharCode() != 13) {
6935 // we might need to allow it for textareas.. and some other items.
6936 // check e.getTarget().
6938 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6942 Roo.log("keypress blocked");
6950 onSubmit : function(e){
6955 * Returns true if client-side validation on the form is successful.
6958 isValid : function(){
6959 var items = this.getItems();
6961 items.each(function(f){
6970 * Returns true if any fields in this form have changed since their original load.
6973 isDirty : function(){
6975 var items = this.getItems();
6976 items.each(function(f){
6986 * Performs a predefined action (submit or load) or custom actions you define on this form.
6987 * @param {String} actionName The name of the action type
6988 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6989 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6990 * accept other config options):
6992 Property Type Description
6993 ---------------- --------------- ----------------------------------------------------------------------------------
6994 url String The url for the action (defaults to the form's url)
6995 method String The form method to use (defaults to the form's method, or POST if not defined)
6996 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6997 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6998 validate the form on the client (defaults to false)
7000 * @return {BasicForm} this
7002 doAction : function(action, options){
7003 if(typeof action == 'string'){
7004 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7006 if(this.fireEvent('beforeaction', this, action) !== false){
7007 this.beforeAction(action);
7008 action.run.defer(100, action);
7014 beforeAction : function(action){
7015 var o = action.options;
7018 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7020 // not really supported yet.. ??
7022 //if(this.waitMsgTarget === true){
7023 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7024 //}else if(this.waitMsgTarget){
7025 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7026 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7028 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7034 afterAction : function(action, success){
7035 this.activeAction = null;
7036 var o = action.options;
7038 //if(this.waitMsgTarget === true){
7040 //}else if(this.waitMsgTarget){
7041 // this.waitMsgTarget.unmask();
7043 // Roo.MessageBox.updateProgress(1);
7044 // Roo.MessageBox.hide();
7051 Roo.callback(o.success, o.scope, [this, action]);
7052 this.fireEvent('actioncomplete', this, action);
7056 // failure condition..
7057 // we have a scenario where updates need confirming.
7058 // eg. if a locking scenario exists..
7059 // we look for { errors : { needs_confirm : true }} in the response.
7061 (typeof(action.result) != 'undefined') &&
7062 (typeof(action.result.errors) != 'undefined') &&
7063 (typeof(action.result.errors.needs_confirm) != 'undefined')
7066 Roo.log("not supported yet");
7069 Roo.MessageBox.confirm(
7070 "Change requires confirmation",
7071 action.result.errorMsg,
7076 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7086 Roo.callback(o.failure, o.scope, [this, action]);
7087 // show an error message if no failed handler is set..
7088 if (!this.hasListener('actionfailed')) {
7089 Roo.log("need to add dialog support");
7091 Roo.MessageBox.alert("Error",
7092 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7093 action.result.errorMsg :
7094 "Saving Failed, please check your entries or try again"
7099 this.fireEvent('actionfailed', this, action);
7104 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7105 * @param {String} id The value to search for
7108 findField : function(id){
7109 var items = this.getItems();
7110 var field = items.get(id);
7112 items.each(function(f){
7113 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7120 return field || null;
7123 * Mark fields in this form invalid in bulk.
7124 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7125 * @return {BasicForm} this
7127 markInvalid : function(errors){
7128 if(errors instanceof Array){
7129 for(var i = 0, len = errors.length; i < len; i++){
7130 var fieldError = errors[i];
7131 var f = this.findField(fieldError.id);
7133 f.markInvalid(fieldError.msg);
7139 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7140 field.markInvalid(errors[id]);
7144 //Roo.each(this.childForms || [], function (f) {
7145 // f.markInvalid(errors);
7152 * Set values for fields in this form in bulk.
7153 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7154 * @return {BasicForm} this
7156 setValues : function(values){
7157 if(values instanceof Array){ // array of objects
7158 for(var i = 0, len = values.length; i < len; i++){
7160 var f = this.findField(v.id);
7162 f.setValue(v.value);
7163 if(this.trackResetOnLoad){
7164 f.originalValue = f.getValue();
7168 }else{ // object hash
7171 if(typeof values[id] != 'function' && (field = this.findField(id))){
7173 if (field.setFromData &&
7175 field.displayField &&
7176 // combos' with local stores can
7177 // be queried via setValue()
7178 // to set their value..
7179 (field.store && !field.store.isLocal)
7183 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7184 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7185 field.setFromData(sd);
7188 field.setValue(values[id]);
7192 if(this.trackResetOnLoad){
7193 field.originalValue = field.getValue();
7199 //Roo.each(this.childForms || [], function (f) {
7200 // f.setValues(values);
7207 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7208 * they are returned as an array.
7209 * @param {Boolean} asString
7212 getValues : function(asString){
7213 //if (this.childForms) {
7214 // copy values from the child forms
7215 // Roo.each(this.childForms, function (f) {
7216 // this.setValues(f.getValues());
7222 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7223 if(asString === true){
7226 return Roo.urlDecode(fs);
7230 * Returns the fields in this form as an object with key/value pairs.
7231 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7234 getFieldValues : function(with_hidden)
7236 var items = this.getItems();
7238 items.each(function(f){
7242 var v = f.getValue();
7243 if (f.inputType =='radio') {
7244 if (typeof(ret[f.getName()]) == 'undefined') {
7245 ret[f.getName()] = ''; // empty..
7248 if (!f.el.dom.checked) {
7256 // not sure if this supported any more..
7257 if ((typeof(v) == 'object') && f.getRawValue) {
7258 v = f.getRawValue() ; // dates..
7260 // combo boxes where name != hiddenName...
7261 if (f.name != f.getName()) {
7262 ret[f.name] = f.getRawValue();
7264 ret[f.getName()] = v;
7271 * Clears all invalid messages in this form.
7272 * @return {BasicForm} this
7274 clearInvalid : function(){
7275 var items = this.getItems();
7277 items.each(function(f){
7288 * @return {BasicForm} this
7291 var items = this.getItems();
7292 items.each(function(f){
7296 Roo.each(this.childForms || [], function (f) {
7303 getItems : function()
7305 var r=new Roo.util.MixedCollection(false, function(o){
7306 return o.id || (o.id = Roo.id());
7308 var iter = function(el) {
7315 Roo.each(el.items,function(e) {
7335 * Ext JS Library 1.1.1
7336 * Copyright(c) 2006-2007, Ext JS, LLC.
7338 * Originally Released Under LGPL - original licence link has changed is not relivant.
7341 * <script type="text/javascript">
7344 * @class Roo.form.VTypes
7345 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7348 Roo.form.VTypes = function(){
7349 // closure these in so they are only created once.
7350 var alpha = /^[a-zA-Z_]+$/;
7351 var alphanum = /^[a-zA-Z0-9_]+$/;
7352 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7353 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7355 // All these messages and functions are configurable
7358 * The function used to validate email addresses
7359 * @param {String} value The email address
7361 'email' : function(v){
7362 return email.test(v);
7365 * The error text to display when the email validation function returns false
7368 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7370 * The keystroke filter mask to be applied on email input
7373 'emailMask' : /[a-z0-9_\.\-@]/i,
7376 * The function used to validate URLs
7377 * @param {String} value The URL
7379 'url' : function(v){
7383 * The error text to display when the url validation function returns false
7386 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7389 * The function used to validate alpha values
7390 * @param {String} value The value
7392 'alpha' : function(v){
7393 return alpha.test(v);
7396 * The error text to display when the alpha validation function returns false
7399 'alphaText' : 'This field should only contain letters and _',
7401 * The keystroke filter mask to be applied on alpha input
7404 'alphaMask' : /[a-z_]/i,
7407 * The function used to validate alphanumeric values
7408 * @param {String} value The value
7410 'alphanum' : function(v){
7411 return alphanum.test(v);
7414 * The error text to display when the alphanumeric validation function returns false
7417 'alphanumText' : 'This field should only contain letters, numbers and _',
7419 * The keystroke filter mask to be applied on alphanumeric input
7422 'alphanumMask' : /[a-z0-9_]/i
7432 * @class Roo.bootstrap.Input
7433 * @extends Roo.bootstrap.Component
7434 * Bootstrap Input class
7435 * @cfg {Boolean} disabled is it disabled
7436 * @cfg {String} fieldLabel - the label associated
7437 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7438 * @cfg {String} name name of the input
7439 * @cfg {string} fieldLabel - the label associated
7440 * @cfg {string} inputType - input / file submit ...
7441 * @cfg {string} placeholder - placeholder to put in text.
7442 * @cfg {string} before - input group add on before
7443 * @cfg {string} after - input group add on after
7444 * @cfg {string} size - (lg|sm) or leave empty..
7445 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7446 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7447 * @cfg {Number} md colspan out of 12 for computer-sized screens
7448 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7449 * @cfg {string} value default value of the input
7450 * @cfg {Number} labelWidth set the width of label (0-12)
7451 * @cfg {String} labelAlign (top|left)
7452 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7453 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7455 * @cfg {String} align (left|center|right) Default left
7460 * Create a new Input
7461 * @param {Object} config The config object
7464 Roo.bootstrap.Input = function(config){
7465 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7470 * Fires when this field receives input focus.
7471 * @param {Roo.form.Field} this
7476 * Fires when this field loses input focus.
7477 * @param {Roo.form.Field} this
7482 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7483 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7484 * @param {Roo.form.Field} this
7485 * @param {Roo.EventObject} e The event object
7490 * Fires just before the field blurs if the field value has changed.
7491 * @param {Roo.form.Field} this
7492 * @param {Mixed} newValue The new value
7493 * @param {Mixed} oldValue The original value
7498 * Fires after the field has been marked as invalid.
7499 * @param {Roo.form.Field} this
7500 * @param {String} msg The validation message
7505 * Fires after the field has been validated with no errors.
7506 * @param {Roo.form.Field} this
7511 * Fires after the key up
7512 * @param {Roo.form.Field} this
7513 * @param {Roo.EventObject} e The event Object
7519 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7521 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7522 automatic validation (defaults to "keyup").
7524 validationEvent : "keyup",
7526 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7528 validateOnBlur : true,
7530 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7532 validationDelay : 250,
7534 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7536 focusClass : "x-form-focus", // not needed???
7540 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7542 invalidClass : "has-warning",
7545 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7547 validClass : "has-success",
7550 * @cfg {Boolean} hasFeedback (true|false) default true
7555 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7557 invalidFeedbackClass : "glyphicon-warning-sign",
7560 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7562 validFeedbackClass : "glyphicon-ok",
7565 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7567 selectOnFocus : false,
7570 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7574 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7579 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7581 disableKeyFilter : false,
7584 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7588 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7592 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7594 blankText : "This field is required",
7597 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7601 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7603 maxLength : Number.MAX_VALUE,
7605 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7607 minLengthText : "The minimum length for this field is {0}",
7609 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7611 maxLengthText : "The maximum length for this field is {0}",
7615 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7616 * If available, this function will be called only after the basic validators all return true, and will be passed the
7617 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7621 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7622 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7623 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7627 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7631 autocomplete: false,
7650 formatedValue : false,
7652 parentLabelAlign : function()
7655 while (parent.parent()) {
7656 parent = parent.parent();
7657 if (typeof(parent.labelAlign) !='undefined') {
7658 return parent.labelAlign;
7665 getAutoCreate : function(){
7667 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7673 if(this.inputType != 'hidden'){
7674 cfg.cls = 'form-group' //input-group
7680 type : this.inputType,
7682 cls : 'form-control',
7683 placeholder : this.placeholder || '',
7684 autocomplete : this.autocomplete || 'new-password'
7689 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7692 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7693 input.maxLength = this.maxLength;
7696 if (this.disabled) {
7697 input.disabled=true;
7700 if (this.readOnly) {
7701 input.readonly=true;
7705 input.name = this.name;
7708 input.cls += ' input-' + this.size;
7711 ['xs','sm','md','lg'].map(function(size){
7712 if (settings[size]) {
7713 cfg.cls += ' col-' + size + '-' + settings[size];
7717 var inputblock = input;
7721 cls: 'glyphicon form-control-feedback'
7724 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7727 cls : 'has-feedback',
7735 if (this.before || this.after) {
7738 cls : 'input-group',
7742 if (this.before && typeof(this.before) == 'string') {
7744 inputblock.cn.push({
7746 cls : 'roo-input-before input-group-addon',
7750 if (this.before && typeof(this.before) == 'object') {
7751 this.before = Roo.factory(this.before);
7752 Roo.log(this.before);
7753 inputblock.cn.push({
7755 cls : 'roo-input-before input-group-' +
7756 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7760 inputblock.cn.push(input);
7762 if (this.after && typeof(this.after) == 'string') {
7763 inputblock.cn.push({
7765 cls : 'roo-input-after input-group-addon',
7769 if (this.after && typeof(this.after) == 'object') {
7770 this.after = Roo.factory(this.after);
7771 Roo.log(this.after);
7772 inputblock.cn.push({
7774 cls : 'roo-input-after input-group-' +
7775 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7779 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7780 inputblock.cls += ' has-feedback';
7781 inputblock.cn.push(feedback);
7785 if (align ==='left' && this.fieldLabel.length) {
7786 Roo.log("left and has label");
7792 cls : 'control-label col-sm-' + this.labelWidth,
7793 html : this.fieldLabel
7797 cls : "col-sm-" + (12 - this.labelWidth),
7804 } else if ( this.fieldLabel.length) {
7810 //cls : 'input-group-addon',
7811 html : this.fieldLabel
7821 Roo.log(" no label && no align");
7830 Roo.log('input-parentType: ' + this.parentType);
7832 if (this.parentType === 'Navbar' && this.parent().bar) {
7833 cfg.cls += ' navbar-form';
7841 * return the real input element.
7843 inputEl: function ()
7845 return this.el.select('input.form-control',true).first();
7848 tooltipEl : function()
7850 return this.inputEl();
7853 setDisabled : function(v)
7855 var i = this.inputEl().dom;
7857 i.removeAttribute('disabled');
7861 i.setAttribute('disabled','true');
7863 initEvents : function()
7866 this.inputEl().on("keydown" , this.fireKey, this);
7867 this.inputEl().on("focus", this.onFocus, this);
7868 this.inputEl().on("blur", this.onBlur, this);
7870 this.inputEl().relayEvent('keyup', this);
7872 // reference to original value for reset
7873 this.originalValue = this.getValue();
7874 //Roo.form.TextField.superclass.initEvents.call(this);
7875 if(this.validationEvent == 'keyup'){
7876 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7877 this.inputEl().on('keyup', this.filterValidation, this);
7879 else if(this.validationEvent !== false){
7880 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7883 if(this.selectOnFocus){
7884 this.on("focus", this.preFocus, this);
7887 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7888 this.inputEl().on("keypress", this.filterKeys, this);
7891 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7892 this.el.on("click", this.autoSize, this);
7895 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7896 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7899 if (typeof(this.before) == 'object') {
7900 this.before.render(this.el.select('.roo-input-before',true).first());
7902 if (typeof(this.after) == 'object') {
7903 this.after.render(this.el.select('.roo-input-after',true).first());
7908 filterValidation : function(e){
7909 if(!e.isNavKeyPress()){
7910 this.validationTask.delay(this.validationDelay);
7914 * Validates the field value
7915 * @return {Boolean} True if the value is valid, else false
7917 validate : function(){
7918 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7919 if(this.disabled || this.validateValue(this.getRawValue())){
7930 * Validates a value according to the field's validation rules and marks the field as invalid
7931 * if the validation fails
7932 * @param {Mixed} value The value to validate
7933 * @return {Boolean} True if the value is valid, else false
7935 validateValue : function(value){
7936 if(value.length < 1) { // if it's blank
7937 if(this.allowBlank){
7943 if(value.length < this.minLength){
7946 if(value.length > this.maxLength){
7950 var vt = Roo.form.VTypes;
7951 if(!vt[this.vtype](value, this)){
7955 if(typeof this.validator == "function"){
7956 var msg = this.validator(value);
7962 if(this.regex && !this.regex.test(value)){
7972 fireKey : function(e){
7973 //Roo.log('field ' + e.getKey());
7974 if(e.isNavKeyPress()){
7975 this.fireEvent("specialkey", this, e);
7978 focus : function (selectText){
7980 this.inputEl().focus();
7981 if(selectText === true){
7982 this.inputEl().dom.select();
7988 onFocus : function(){
7989 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7990 // this.el.addClass(this.focusClass);
7993 this.hasFocus = true;
7994 this.startValue = this.getValue();
7995 this.fireEvent("focus", this);
7999 beforeBlur : Roo.emptyFn,
8003 onBlur : function(){
8005 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8006 //this.el.removeClass(this.focusClass);
8008 this.hasFocus = false;
8009 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8012 var v = this.getValue();
8013 if(String(v) !== String(this.startValue)){
8014 this.fireEvent('change', this, v, this.startValue);
8016 this.fireEvent("blur", this);
8020 * Resets the current field value to the originally loaded value and clears any validation messages
8023 this.setValue(this.originalValue);
8027 * Returns the name of the field
8028 * @return {Mixed} name The name field
8030 getName: function(){
8034 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8035 * @return {Mixed} value The field value
8037 getValue : function(){
8039 var v = this.inputEl().getValue();
8044 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8045 * @return {Mixed} value The field value
8047 getRawValue : function(){
8048 var v = this.inputEl().getValue();
8054 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8055 * @param {Mixed} value The value to set
8057 setRawValue : function(v){
8058 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8061 selectText : function(start, end){
8062 var v = this.getRawValue();
8064 start = start === undefined ? 0 : start;
8065 end = end === undefined ? v.length : end;
8066 var d = this.inputEl().dom;
8067 if(d.setSelectionRange){
8068 d.setSelectionRange(start, end);
8069 }else if(d.createTextRange){
8070 var range = d.createTextRange();
8071 range.moveStart("character", start);
8072 range.moveEnd("character", v.length-end);
8079 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8080 * @param {Mixed} value The value to set
8082 setValue : function(v){
8085 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8091 processValue : function(value){
8092 if(this.stripCharsRe){
8093 var newValue = value.replace(this.stripCharsRe, '');
8094 if(newValue !== value){
8095 this.setRawValue(newValue);
8102 preFocus : function(){
8104 if(this.selectOnFocus){
8105 this.inputEl().dom.select();
8108 filterKeys : function(e){
8110 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8113 var c = e.getCharCode(), cc = String.fromCharCode(c);
8114 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8117 if(!this.maskRe.test(cc)){
8122 * Clear any invalid styles/messages for this field
8124 clearInvalid : function(){
8126 if(!this.el || this.preventMark){ // not rendered
8129 this.el.removeClass(this.invalidClass);
8131 this.fireEvent('valid', this);
8135 * Mark this field as valid
8137 markValid : function(){
8138 if(!this.el || this.preventMark){ // not rendered
8142 this.el.removeClass([this.invalidClass, this.validClass]);
8144 if(this.disabled || this.allowBlank){
8148 this.el.addClass(this.validClass);
8150 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8152 var feedback = this.el.select('.form-control-feedback', true).first();
8155 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8156 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8161 this.fireEvent('valid', this);
8165 * Mark this field as invalid
8166 * @param {String} msg The validation message
8168 markInvalid : function(msg){
8169 if(!this.el || this.preventMark){ // not rendered
8173 this.el.removeClass([this.invalidClass, this.validClass]);
8175 if(this.disabled || this.allowBlank){
8179 this.el.addClass(this.invalidClass);
8181 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8183 var feedback = this.el.select('.form-control-feedback', true).first();
8186 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8188 if(this.getValue().length){
8189 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8196 this.fireEvent('invalid', this, msg);
8199 SafariOnKeyDown : function(event)
8201 // this is a workaround for a password hang bug on chrome/ webkit.
8203 var isSelectAll = false;
8205 if(this.inputEl().dom.selectionEnd > 0){
8206 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8208 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8209 event.preventDefault();
8214 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8216 event.preventDefault();
8217 // this is very hacky as keydown always get's upper case.
8219 var cc = String.fromCharCode(event.getCharCode());
8220 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8224 adjustWidth : function(tag, w){
8225 tag = tag.toLowerCase();
8226 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8227 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8231 if(tag == 'textarea'){
8234 }else if(Roo.isOpera){
8238 if(tag == 'textarea'){
8257 * @class Roo.bootstrap.TextArea
8258 * @extends Roo.bootstrap.Input
8259 * Bootstrap TextArea class
8260 * @cfg {Number} cols Specifies the visible width of a text area
8261 * @cfg {Number} rows Specifies the visible number of lines in a text area
8262 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8263 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8264 * @cfg {string} html text
8267 * Create a new TextArea
8268 * @param {Object} config The config object
8271 Roo.bootstrap.TextArea = function(config){
8272 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8276 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8286 getAutoCreate : function(){
8288 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8299 value : this.value || '',
8300 html: this.html || '',
8301 cls : 'form-control',
8302 placeholder : this.placeholder || ''
8306 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8307 input.maxLength = this.maxLength;
8311 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8315 input.cols = this.cols;
8318 if (this.readOnly) {
8319 input.readonly = true;
8323 input.name = this.name;
8327 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8331 ['xs','sm','md','lg'].map(function(size){
8332 if (settings[size]) {
8333 cfg.cls += ' col-' + size + '-' + settings[size];
8337 var inputblock = input;
8339 if(this.hasFeedback && !this.allowBlank){
8343 cls: 'glyphicon form-control-feedback'
8347 cls : 'has-feedback',
8356 if (this.before || this.after) {
8359 cls : 'input-group',
8363 inputblock.cn.push({
8365 cls : 'input-group-addon',
8370 inputblock.cn.push(input);
8372 if(this.hasFeedback && !this.allowBlank){
8373 inputblock.cls += ' has-feedback';
8374 inputblock.cn.push(feedback);
8378 inputblock.cn.push({
8380 cls : 'input-group-addon',
8387 if (align ==='left' && this.fieldLabel.length) {
8388 Roo.log("left and has label");
8394 cls : 'control-label col-sm-' + this.labelWidth,
8395 html : this.fieldLabel
8399 cls : "col-sm-" + (12 - this.labelWidth),
8406 } else if ( this.fieldLabel.length) {
8412 //cls : 'input-group-addon',
8413 html : this.fieldLabel
8423 Roo.log(" no label && no align");
8433 if (this.disabled) {
8434 input.disabled=true;
8441 * return the real textarea element.
8443 inputEl: function ()
8445 return this.el.select('textarea.form-control',true).first();
8453 * trigger field - base class for combo..
8458 * @class Roo.bootstrap.TriggerField
8459 * @extends Roo.bootstrap.Input
8460 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8461 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8462 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8463 * for which you can provide a custom implementation. For example:
8465 var trigger = new Roo.bootstrap.TriggerField();
8466 trigger.onTriggerClick = myTriggerFn;
8467 trigger.applyTo('my-field');
8470 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8471 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8472 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8473 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8474 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8477 * Create a new TriggerField.
8478 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8479 * to the base TextField)
8481 Roo.bootstrap.TriggerField = function(config){
8482 this.mimicing = false;
8483 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8486 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8488 * @cfg {String} triggerClass A CSS class to apply to the trigger
8491 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8496 * @cfg {Boolean} removable (true|false) special filter default false
8500 /** @cfg {Boolean} grow @hide */
8501 /** @cfg {Number} growMin @hide */
8502 /** @cfg {Number} growMax @hide */
8508 autoSize: Roo.emptyFn,
8515 actionMode : 'wrap',
8520 getAutoCreate : function(){
8522 var align = this.labelAlign || this.parentLabelAlign();
8527 cls: 'form-group' //input-group
8534 type : this.inputType,
8535 cls : 'form-control',
8536 autocomplete: 'new-password',
8537 placeholder : this.placeholder || ''
8541 input.name = this.name;
8544 input.cls += ' input-' + this.size;
8547 if (this.disabled) {
8548 input.disabled=true;
8551 var inputblock = input;
8553 if(this.hasFeedback && !this.allowBlank){
8557 cls: 'glyphicon form-control-feedback'
8560 if(this.removable && !this.editable && !this.tickable){
8562 cls : 'has-feedback',
8568 cls : 'roo-combo-removable-btn close'
8575 cls : 'has-feedback',
8584 if(this.removable && !this.editable && !this.tickable){
8586 cls : 'roo-removable',
8592 cls : 'roo-combo-removable-btn close'
8599 if (this.before || this.after) {
8602 cls : 'input-group',
8606 inputblock.cn.push({
8608 cls : 'input-group-addon',
8613 inputblock.cn.push(input);
8615 if(this.hasFeedback && !this.allowBlank){
8616 inputblock.cls += ' has-feedback';
8617 inputblock.cn.push(feedback);
8621 inputblock.cn.push({
8623 cls : 'input-group-addon',
8636 cls: 'form-hidden-field'
8644 Roo.log('multiple');
8652 cls: 'form-hidden-field'
8656 cls: 'select2-choices',
8660 cls: 'select2-search-field',
8673 cls: 'select2-container input-group',
8678 // cls: 'typeahead typeahead-long dropdown-menu',
8679 // style: 'display:none'
8684 if(!this.multiple && this.showToggleBtn){
8690 if (this.caret != false) {
8693 cls: 'fa fa-' + this.caret
8700 cls : 'input-group-addon btn dropdown-toggle',
8705 cls: 'combobox-clear',
8719 combobox.cls += ' select2-container-multi';
8722 if (align ==='left' && this.fieldLabel.length) {
8724 Roo.log("left and has label");
8730 cls : 'control-label col-sm-' + this.labelWidth,
8731 html : this.fieldLabel
8735 cls : "col-sm-" + (12 - this.labelWidth),
8742 } else if ( this.fieldLabel.length) {
8748 //cls : 'input-group-addon',
8749 html : this.fieldLabel
8759 Roo.log(" no label && no align");
8766 ['xs','sm','md','lg'].map(function(size){
8767 if (settings[size]) {
8768 cfg.cls += ' col-' + size + '-' + settings[size];
8779 onResize : function(w, h){
8780 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8781 // if(typeof w == 'number'){
8782 // var x = w - this.trigger.getWidth();
8783 // this.inputEl().setWidth(this.adjustWidth('input', x));
8784 // this.trigger.setStyle('left', x+'px');
8789 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8792 getResizeEl : function(){
8793 return this.inputEl();
8797 getPositionEl : function(){
8798 return this.inputEl();
8802 alignErrorIcon : function(){
8803 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8807 initEvents : function(){
8811 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8812 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8813 if(!this.multiple && this.showToggleBtn){
8814 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8815 if(this.hideTrigger){
8816 this.trigger.setDisplayed(false);
8818 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8822 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8825 if(this.removable && !this.editable && !this.tickable){
8826 var close = this.closeTriggerEl();
8829 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8830 close.on('click', this.removeBtnClick, this, close);
8834 //this.trigger.addClassOnOver('x-form-trigger-over');
8835 //this.trigger.addClassOnClick('x-form-trigger-click');
8838 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8842 closeTriggerEl : function()
8844 var close = this.el.select('.roo-combo-removable-btn', true).first();
8845 return close ? close : false;
8848 removeBtnClick : function(e, h, el)
8852 this.fireEvent("remove", this);
8855 createList : function()
8857 this.list = Roo.get(document.body).createChild({
8859 cls: 'typeahead typeahead-long dropdown-menu',
8860 style: 'display:none'
8863 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8868 initTrigger : function(){
8873 onDestroy : function(){
8875 this.trigger.removeAllListeners();
8876 // this.trigger.remove();
8879 // this.wrap.remove();
8881 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8885 onFocus : function(){
8886 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8889 this.wrap.addClass('x-trigger-wrap-focus');
8890 this.mimicing = true;
8891 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8892 if(this.monitorTab){
8893 this.el.on("keydown", this.checkTab, this);
8900 checkTab : function(e){
8901 if(e.getKey() == e.TAB){
8907 onBlur : function(){
8912 mimicBlur : function(e, t){
8914 if(!this.wrap.contains(t) && this.validateBlur()){
8921 triggerBlur : function(){
8922 this.mimicing = false;
8923 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8924 if(this.monitorTab){
8925 this.el.un("keydown", this.checkTab, this);
8927 //this.wrap.removeClass('x-trigger-wrap-focus');
8928 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8932 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8933 validateBlur : function(e, t){
8938 onDisable : function(){
8939 this.inputEl().dom.disabled = true;
8940 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8942 // this.wrap.addClass('x-item-disabled');
8947 onEnable : function(){
8948 this.inputEl().dom.disabled = false;
8949 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8951 // this.el.removeClass('x-item-disabled');
8956 onShow : function(){
8957 var ae = this.getActionEl();
8960 ae.dom.style.display = '';
8961 ae.dom.style.visibility = 'visible';
8967 onHide : function(){
8968 var ae = this.getActionEl();
8969 ae.dom.style.display = 'none';
8973 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8974 * by an implementing function.
8976 * @param {EventObject} e
8978 onTriggerClick : Roo.emptyFn
8982 * Ext JS Library 1.1.1
8983 * Copyright(c) 2006-2007, Ext JS, LLC.
8985 * Originally Released Under LGPL - original licence link has changed is not relivant.
8988 * <script type="text/javascript">
8993 * @class Roo.data.SortTypes
8995 * Defines the default sorting (casting?) comparison functions used when sorting data.
8997 Roo.data.SortTypes = {
8999 * Default sort that does nothing
9000 * @param {Mixed} s The value being converted
9001 * @return {Mixed} The comparison value
9008 * The regular expression used to strip tags
9012 stripTagsRE : /<\/?[^>]+>/gi,
9015 * Strips all HTML tags to sort on text only
9016 * @param {Mixed} s The value being converted
9017 * @return {String} The comparison value
9019 asText : function(s){
9020 return String(s).replace(this.stripTagsRE, "");
9024 * Strips all HTML tags to sort on text only - Case insensitive
9025 * @param {Mixed} s The value being converted
9026 * @return {String} The comparison value
9028 asUCText : function(s){
9029 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9033 * Case insensitive string
9034 * @param {Mixed} s The value being converted
9035 * @return {String} The comparison value
9037 asUCString : function(s) {
9038 return String(s).toUpperCase();
9043 * @param {Mixed} s The value being converted
9044 * @return {Number} The comparison value
9046 asDate : function(s) {
9050 if(s instanceof Date){
9053 return Date.parse(String(s));
9058 * @param {Mixed} s The value being converted
9059 * @return {Float} The comparison value
9061 asFloat : function(s) {
9062 var val = parseFloat(String(s).replace(/,/g, ""));
9063 if(isNaN(val)) val = 0;
9069 * @param {Mixed} s The value being converted
9070 * @return {Number} The comparison value
9072 asInt : function(s) {
9073 var val = parseInt(String(s).replace(/,/g, ""));
9074 if(isNaN(val)) val = 0;
9079 * Ext JS Library 1.1.1
9080 * Copyright(c) 2006-2007, Ext JS, LLC.
9082 * Originally Released Under LGPL - original licence link has changed is not relivant.
9085 * <script type="text/javascript">
9089 * @class Roo.data.Record
9090 * Instances of this class encapsulate both record <em>definition</em> information, and record
9091 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9092 * to access Records cached in an {@link Roo.data.Store} object.<br>
9094 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9095 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9098 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9100 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9101 * {@link #create}. The parameters are the same.
9102 * @param {Array} data An associative Array of data values keyed by the field name.
9103 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9104 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9105 * not specified an integer id is generated.
9107 Roo.data.Record = function(data, id){
9108 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9113 * Generate a constructor for a specific record layout.
9114 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9115 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9116 * Each field definition object may contain the following properties: <ul>
9117 * <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,
9118 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9119 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9120 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9121 * is being used, then this is a string containing the javascript expression to reference the data relative to
9122 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9123 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9124 * this may be omitted.</p></li>
9125 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9126 * <ul><li>auto (Default, implies no conversion)</li>
9131 * <li>date</li></ul></p></li>
9132 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9133 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9134 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9135 * by the Reader into an object that will be stored in the Record. It is passed the
9136 * following parameters:<ul>
9137 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9139 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9141 * <br>usage:<br><pre><code>
9142 var TopicRecord = Roo.data.Record.create(
9143 {name: 'title', mapping: 'topic_title'},
9144 {name: 'author', mapping: 'username'},
9145 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9146 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9147 {name: 'lastPoster', mapping: 'user2'},
9148 {name: 'excerpt', mapping: 'post_text'}
9151 var myNewRecord = new TopicRecord({
9152 title: 'Do my job please',
9155 lastPost: new Date(),
9156 lastPoster: 'Animal',
9157 excerpt: 'No way dude!'
9159 myStore.add(myNewRecord);
9164 Roo.data.Record.create = function(o){
9166 f.superclass.constructor.apply(this, arguments);
9168 Roo.extend(f, Roo.data.Record);
9169 var p = f.prototype;
9170 p.fields = new Roo.util.MixedCollection(false, function(field){
9173 for(var i = 0, len = o.length; i < len; i++){
9174 p.fields.add(new Roo.data.Field(o[i]));
9176 f.getField = function(name){
9177 return p.fields.get(name);
9182 Roo.data.Record.AUTO_ID = 1000;
9183 Roo.data.Record.EDIT = 'edit';
9184 Roo.data.Record.REJECT = 'reject';
9185 Roo.data.Record.COMMIT = 'commit';
9187 Roo.data.Record.prototype = {
9189 * Readonly flag - true if this record has been modified.
9198 join : function(store){
9203 * Set the named field to the specified value.
9204 * @param {String} name The name of the field to set.
9205 * @param {Object} value The value to set the field to.
9207 set : function(name, value){
9208 if(this.data[name] == value){
9215 if(typeof this.modified[name] == 'undefined'){
9216 this.modified[name] = this.data[name];
9218 this.data[name] = value;
9219 if(!this.editing && this.store){
9220 this.store.afterEdit(this);
9225 * Get the value of the named field.
9226 * @param {String} name The name of the field to get the value of.
9227 * @return {Object} The value of the field.
9229 get : function(name){
9230 return this.data[name];
9234 beginEdit : function(){
9235 this.editing = true;
9240 cancelEdit : function(){
9241 this.editing = false;
9242 delete this.modified;
9246 endEdit : function(){
9247 this.editing = false;
9248 if(this.dirty && this.store){
9249 this.store.afterEdit(this);
9254 * Usually called by the {@link Roo.data.Store} which owns the Record.
9255 * Rejects all changes made to the Record since either creation, or the last commit operation.
9256 * Modified fields are reverted to their original values.
9258 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9259 * of reject operations.
9261 reject : function(){
9262 var m = this.modified;
9264 if(typeof m[n] != "function"){
9265 this.data[n] = m[n];
9269 delete this.modified;
9270 this.editing = false;
9272 this.store.afterReject(this);
9277 * Usually called by the {@link Roo.data.Store} which owns the Record.
9278 * Commits all changes made to the Record since either creation, or the last commit operation.
9280 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9281 * of commit operations.
9283 commit : function(){
9285 delete this.modified;
9286 this.editing = false;
9288 this.store.afterCommit(this);
9293 hasError : function(){
9294 return this.error != null;
9298 clearError : function(){
9303 * Creates a copy of this record.
9304 * @param {String} id (optional) A new record id if you don't want to use this record's id
9307 copy : function(newId) {
9308 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9312 * Ext JS Library 1.1.1
9313 * Copyright(c) 2006-2007, Ext JS, LLC.
9315 * Originally Released Under LGPL - original licence link has changed is not relivant.
9318 * <script type="text/javascript">
9324 * @class Roo.data.Store
9325 * @extends Roo.util.Observable
9326 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9327 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9329 * 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
9330 * has no knowledge of the format of the data returned by the Proxy.<br>
9332 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9333 * instances from the data object. These records are cached and made available through accessor functions.
9335 * Creates a new Store.
9336 * @param {Object} config A config object containing the objects needed for the Store to access data,
9337 * and read the data into Records.
9339 Roo.data.Store = function(config){
9340 this.data = new Roo.util.MixedCollection(false);
9341 this.data.getKey = function(o){
9344 this.baseParams = {};
9351 "multisort" : "_multisort"
9354 if(config && config.data){
9355 this.inlineData = config.data;
9359 Roo.apply(this, config);
9361 if(this.reader){ // reader passed
9362 this.reader = Roo.factory(this.reader, Roo.data);
9363 this.reader.xmodule = this.xmodule || false;
9364 if(!this.recordType){
9365 this.recordType = this.reader.recordType;
9367 if(this.reader.onMetaChange){
9368 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9372 if(this.recordType){
9373 this.fields = this.recordType.prototype.fields;
9379 * @event datachanged
9380 * Fires when the data cache has changed, and a widget which is using this Store
9381 * as a Record cache should refresh its view.
9382 * @param {Store} this
9387 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9388 * @param {Store} this
9389 * @param {Object} meta The JSON metadata
9394 * Fires when Records have been added to the Store
9395 * @param {Store} this
9396 * @param {Roo.data.Record[]} records The array of Records added
9397 * @param {Number} index The index at which the record(s) were added
9402 * Fires when a Record has been removed from the Store
9403 * @param {Store} this
9404 * @param {Roo.data.Record} record The Record that was removed
9405 * @param {Number} index The index at which the record was removed
9410 * Fires when a Record has been updated
9411 * @param {Store} this
9412 * @param {Roo.data.Record} record The Record that was updated
9413 * @param {String} operation The update operation being performed. Value may be one of:
9415 Roo.data.Record.EDIT
9416 Roo.data.Record.REJECT
9417 Roo.data.Record.COMMIT
9423 * Fires when the data cache has been cleared.
9424 * @param {Store} this
9429 * Fires before a request is made for a new data object. If the beforeload handler returns false
9430 * the load action will be canceled.
9431 * @param {Store} this
9432 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9436 * @event beforeloadadd
9437 * Fires after a new set of Records has been loaded.
9438 * @param {Store} this
9439 * @param {Roo.data.Record[]} records The Records that were loaded
9440 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9442 beforeloadadd : true,
9445 * Fires after a new set of Records has been loaded, before they are added to the store.
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)
9449 * @params {Object} return from reader
9453 * @event loadexception
9454 * Fires if an exception occurs in the Proxy during loading.
9455 * Called with the signature of the Proxy's "loadexception" event.
9456 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9459 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9460 * @param {Object} load options
9461 * @param {Object} jsonData from your request (normally this contains the Exception)
9463 loadexception : true
9467 this.proxy = Roo.factory(this.proxy, Roo.data);
9468 this.proxy.xmodule = this.xmodule || false;
9469 this.relayEvents(this.proxy, ["loadexception"]);
9471 this.sortToggle = {};
9472 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9474 Roo.data.Store.superclass.constructor.call(this);
9476 if(this.inlineData){
9477 this.loadData(this.inlineData);
9478 delete this.inlineData;
9482 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9484 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9485 * without a remote query - used by combo/forms at present.
9489 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9492 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9495 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9496 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9499 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9500 * on any HTTP request
9503 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9506 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9510 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9511 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9516 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9517 * loaded or when a record is removed. (defaults to false).
9519 pruneModifiedRecords : false,
9525 * Add Records to the Store and fires the add event.
9526 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9528 add : function(records){
9529 records = [].concat(records);
9530 for(var i = 0, len = records.length; i < len; i++){
9531 records[i].join(this);
9533 var index = this.data.length;
9534 this.data.addAll(records);
9535 this.fireEvent("add", this, records, index);
9539 * Remove a Record from the Store and fires the remove event.
9540 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9542 remove : function(record){
9543 var index = this.data.indexOf(record);
9544 this.data.removeAt(index);
9545 if(this.pruneModifiedRecords){
9546 this.modified.remove(record);
9548 this.fireEvent("remove", this, record, index);
9552 * Remove all Records from the Store and fires the clear event.
9554 removeAll : function(){
9556 if(this.pruneModifiedRecords){
9559 this.fireEvent("clear", this);
9563 * Inserts Records to the Store at the given index and fires the add event.
9564 * @param {Number} index The start index at which to insert the passed Records.
9565 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9567 insert : function(index, records){
9568 records = [].concat(records);
9569 for(var i = 0, len = records.length; i < len; i++){
9570 this.data.insert(index, records[i]);
9571 records[i].join(this);
9573 this.fireEvent("add", this, records, index);
9577 * Get the index within the cache of the passed Record.
9578 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9579 * @return {Number} The index of the passed Record. Returns -1 if not found.
9581 indexOf : function(record){
9582 return this.data.indexOf(record);
9586 * Get the index within the cache of the Record with the passed id.
9587 * @param {String} id The id of the Record to find.
9588 * @return {Number} The index of the Record. Returns -1 if not found.
9590 indexOfId : function(id){
9591 return this.data.indexOfKey(id);
9595 * Get the Record with the specified id.
9596 * @param {String} id The id of the Record to find.
9597 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9599 getById : function(id){
9600 return this.data.key(id);
9604 * Get the Record at the specified index.
9605 * @param {Number} index The index of the Record to find.
9606 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9608 getAt : function(index){
9609 return this.data.itemAt(index);
9613 * Returns a range of Records between specified indices.
9614 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9615 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9616 * @return {Roo.data.Record[]} An array of Records
9618 getRange : function(start, end){
9619 return this.data.getRange(start, end);
9623 storeOptions : function(o){
9624 o = Roo.apply({}, o);
9627 this.lastOptions = o;
9631 * Loads the Record cache from the configured Proxy using the configured Reader.
9633 * If using remote paging, then the first load call must specify the <em>start</em>
9634 * and <em>limit</em> properties in the options.params property to establish the initial
9635 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9637 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9638 * and this call will return before the new data has been loaded. Perform any post-processing
9639 * in a callback function, or in a "load" event handler.</strong>
9641 * @param {Object} options An object containing properties which control loading options:<ul>
9642 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9643 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9644 * passed the following arguments:<ul>
9645 * <li>r : Roo.data.Record[]</li>
9646 * <li>options: Options object from the load call</li>
9647 * <li>success: Boolean success indicator</li></ul></li>
9648 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9649 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9652 load : function(options){
9653 options = options || {};
9654 if(this.fireEvent("beforeload", this, options) !== false){
9655 this.storeOptions(options);
9656 var p = Roo.apply(options.params || {}, this.baseParams);
9657 // if meta was not loaded from remote source.. try requesting it.
9658 if (!this.reader.metaFromRemote) {
9661 if(this.sortInfo && this.remoteSort){
9662 var pn = this.paramNames;
9663 p[pn["sort"]] = this.sortInfo.field;
9664 p[pn["dir"]] = this.sortInfo.direction;
9666 if (this.multiSort) {
9667 var pn = this.paramNames;
9668 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9671 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9676 * Reloads the Record cache from the configured Proxy using the configured Reader and
9677 * the options from the last load operation performed.
9678 * @param {Object} options (optional) An object containing properties which may override the options
9679 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9680 * the most recently used options are reused).
9682 reload : function(options){
9683 this.load(Roo.applyIf(options||{}, this.lastOptions));
9687 // Called as a callback by the Reader during a load operation.
9688 loadRecords : function(o, options, success){
9689 if(!o || success === false){
9690 if(success !== false){
9691 this.fireEvent("load", this, [], options, o);
9693 if(options.callback){
9694 options.callback.call(options.scope || this, [], options, false);
9698 // if data returned failure - throw an exception.
9699 if (o.success === false) {
9700 // show a message if no listener is registered.
9701 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9702 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9704 // loadmask wil be hooked into this..
9705 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9708 var r = o.records, t = o.totalRecords || r.length;
9710 this.fireEvent("beforeloadadd", this, r, options, o);
9712 if(!options || options.add !== true){
9713 if(this.pruneModifiedRecords){
9716 for(var i = 0, len = r.length; i < len; i++){
9720 this.data = this.snapshot;
9721 delete this.snapshot;
9724 this.data.addAll(r);
9725 this.totalLength = t;
9727 this.fireEvent("datachanged", this);
9729 this.totalLength = Math.max(t, this.data.length+r.length);
9732 this.fireEvent("load", this, r, options, o);
9733 if(options.callback){
9734 options.callback.call(options.scope || this, r, options, true);
9740 * Loads data from a passed data block. A Reader which understands the format of the data
9741 * must have been configured in the constructor.
9742 * @param {Object} data The data block from which to read the Records. The format of the data expected
9743 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9744 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9746 loadData : function(o, append){
9747 var r = this.reader.readRecords(o);
9748 this.loadRecords(r, {add: append}, true);
9752 * Gets the number of cached records.
9754 * <em>If using paging, this may not be the total size of the dataset. If the data object
9755 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9756 * the data set size</em>
9758 getCount : function(){
9759 return this.data.length || 0;
9763 * Gets the total number of records in the dataset as returned by the server.
9765 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9766 * the dataset size</em>
9768 getTotalCount : function(){
9769 return this.totalLength || 0;
9773 * Returns the sort state of the Store as an object with two properties:
9775 field {String} The name of the field by which the Records are sorted
9776 direction {String} The sort order, "ASC" or "DESC"
9779 getSortState : function(){
9780 return this.sortInfo;
9784 applySort : function(){
9785 if(this.sortInfo && !this.remoteSort){
9786 var s = this.sortInfo, f = s.field;
9787 var st = this.fields.get(f).sortType;
9788 var fn = function(r1, r2){
9789 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9790 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9792 this.data.sort(s.direction, fn);
9793 if(this.snapshot && this.snapshot != this.data){
9794 this.snapshot.sort(s.direction, fn);
9800 * Sets the default sort column and order to be used by the next load operation.
9801 * @param {String} fieldName The name of the field to sort by.
9802 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9804 setDefaultSort : function(field, dir){
9805 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9810 * If remote sorting is used, the sort is performed on the server, and the cache is
9811 * reloaded. If local sorting is used, the cache is sorted internally.
9812 * @param {String} fieldName The name of the field to sort by.
9813 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9815 sort : function(fieldName, dir){
9816 var f = this.fields.get(fieldName);
9818 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9820 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9821 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9826 this.sortToggle[f.name] = dir;
9827 this.sortInfo = {field: f.name, direction: dir};
9828 if(!this.remoteSort){
9830 this.fireEvent("datachanged", this);
9832 this.load(this.lastOptions);
9837 * Calls the specified function for each of the Records in the cache.
9838 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9839 * Returning <em>false</em> aborts and exits the iteration.
9840 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9842 each : function(fn, scope){
9843 this.data.each(fn, scope);
9847 * Gets all records modified since the last commit. Modified records are persisted across load operations
9848 * (e.g., during paging).
9849 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9851 getModifiedRecords : function(){
9852 return this.modified;
9856 createFilterFn : function(property, value, anyMatch){
9857 if(!value.exec){ // not a regex
9858 value = String(value);
9859 if(value.length == 0){
9862 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9865 return value.test(r.data[property]);
9870 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9871 * @param {String} property A field on your records
9872 * @param {Number} start The record index to start at (defaults to 0)
9873 * @param {Number} end The last record index to include (defaults to length - 1)
9874 * @return {Number} The sum
9876 sum : function(property, start, end){
9877 var rs = this.data.items, v = 0;
9879 end = (end || end === 0) ? end : rs.length-1;
9881 for(var i = start; i <= end; i++){
9882 v += (rs[i].data[property] || 0);
9888 * Filter the records by a specified property.
9889 * @param {String} field A field on your records
9890 * @param {String/RegExp} value Either a string that the field
9891 * should start with or a RegExp to test against the field
9892 * @param {Boolean} anyMatch True to match any part not just the beginning
9894 filter : function(property, value, anyMatch){
9895 var fn = this.createFilterFn(property, value, anyMatch);
9896 return fn ? this.filterBy(fn) : this.clearFilter();
9900 * Filter by a function. The specified function will be called with each
9901 * record in this data source. If the function returns true the record is included,
9902 * otherwise it is filtered.
9903 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9904 * @param {Object} scope (optional) The scope of the function (defaults to this)
9906 filterBy : function(fn, scope){
9907 this.snapshot = this.snapshot || this.data;
9908 this.data = this.queryBy(fn, scope||this);
9909 this.fireEvent("datachanged", this);
9913 * Query the records by a specified property.
9914 * @param {String} field A field on your records
9915 * @param {String/RegExp} value Either a string that the field
9916 * should start with or a RegExp to test against the field
9917 * @param {Boolean} anyMatch True to match any part not just the beginning
9918 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9920 query : function(property, value, anyMatch){
9921 var fn = this.createFilterFn(property, value, anyMatch);
9922 return fn ? this.queryBy(fn) : this.data.clone();
9926 * Query by a function. The specified function will be called with each
9927 * record in this data source. If the function returns true the record is included
9929 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9930 * @param {Object} scope (optional) The scope of the function (defaults to this)
9931 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9933 queryBy : function(fn, scope){
9934 var data = this.snapshot || this.data;
9935 return data.filterBy(fn, scope||this);
9939 * Collects unique values for a particular dataIndex from this store.
9940 * @param {String} dataIndex The property to collect
9941 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9942 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9943 * @return {Array} An array of the unique values
9945 collect : function(dataIndex, allowNull, bypassFilter){
9946 var d = (bypassFilter === true && this.snapshot) ?
9947 this.snapshot.items : this.data.items;
9948 var v, sv, r = [], l = {};
9949 for(var i = 0, len = d.length; i < len; i++){
9950 v = d[i].data[dataIndex];
9952 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9961 * Revert to a view of the Record cache with no filtering applied.
9962 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9964 clearFilter : function(suppressEvent){
9965 if(this.snapshot && this.snapshot != this.data){
9966 this.data = this.snapshot;
9967 delete this.snapshot;
9968 if(suppressEvent !== true){
9969 this.fireEvent("datachanged", this);
9975 afterEdit : function(record){
9976 if(this.modified.indexOf(record) == -1){
9977 this.modified.push(record);
9979 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9983 afterReject : function(record){
9984 this.modified.remove(record);
9985 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9989 afterCommit : function(record){
9990 this.modified.remove(record);
9991 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9995 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9996 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9998 commitChanges : function(){
9999 var m = this.modified.slice(0);
10000 this.modified = [];
10001 for(var i = 0, len = m.length; i < len; i++){
10007 * Cancel outstanding changes on all changed records.
10009 rejectChanges : function(){
10010 var m = this.modified.slice(0);
10011 this.modified = [];
10012 for(var i = 0, len = m.length; i < len; i++){
10017 onMetaChange : function(meta, rtype, o){
10018 this.recordType = rtype;
10019 this.fields = rtype.prototype.fields;
10020 delete this.snapshot;
10021 this.sortInfo = meta.sortInfo || this.sortInfo;
10022 this.modified = [];
10023 this.fireEvent('metachange', this, this.reader.meta);
10026 moveIndex : function(data, type)
10028 var index = this.indexOf(data);
10030 var newIndex = index + type;
10034 this.insert(newIndex, data);
10039 * Ext JS Library 1.1.1
10040 * Copyright(c) 2006-2007, Ext JS, LLC.
10042 * Originally Released Under LGPL - original licence link has changed is not relivant.
10045 * <script type="text/javascript">
10049 * @class Roo.data.SimpleStore
10050 * @extends Roo.data.Store
10051 * Small helper class to make creating Stores from Array data easier.
10052 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10053 * @cfg {Array} fields An array of field definition objects, or field name strings.
10054 * @cfg {Array} data The multi-dimensional array of data
10056 * @param {Object} config
10058 Roo.data.SimpleStore = function(config){
10059 Roo.data.SimpleStore.superclass.constructor.call(this, {
10061 reader: new Roo.data.ArrayReader({
10064 Roo.data.Record.create(config.fields)
10066 proxy : new Roo.data.MemoryProxy(config.data)
10070 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10072 * Ext JS Library 1.1.1
10073 * Copyright(c) 2006-2007, Ext JS, LLC.
10075 * Originally Released Under LGPL - original licence link has changed is not relivant.
10078 * <script type="text/javascript">
10083 * @extends Roo.data.Store
10084 * @class Roo.data.JsonStore
10085 * Small helper class to make creating Stores for JSON data easier. <br/>
10087 var store = new Roo.data.JsonStore({
10088 url: 'get-images.php',
10090 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10093 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10094 * JsonReader and HttpProxy (unless inline data is provided).</b>
10095 * @cfg {Array} fields An array of field definition objects, or field name strings.
10097 * @param {Object} config
10099 Roo.data.JsonStore = function(c){
10100 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10101 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10102 reader: new Roo.data.JsonReader(c, c.fields)
10105 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10107 * Ext JS Library 1.1.1
10108 * Copyright(c) 2006-2007, Ext JS, LLC.
10110 * Originally Released Under LGPL - original licence link has changed is not relivant.
10113 * <script type="text/javascript">
10117 Roo.data.Field = function(config){
10118 if(typeof config == "string"){
10119 config = {name: config};
10121 Roo.apply(this, config);
10124 this.type = "auto";
10127 var st = Roo.data.SortTypes;
10128 // named sortTypes are supported, here we look them up
10129 if(typeof this.sortType == "string"){
10130 this.sortType = st[this.sortType];
10133 // set default sortType for strings and dates
10134 if(!this.sortType){
10137 this.sortType = st.asUCString;
10140 this.sortType = st.asDate;
10143 this.sortType = st.none;
10148 var stripRe = /[\$,%]/g;
10150 // prebuilt conversion function for this field, instead of
10151 // switching every time we're reading a value
10153 var cv, dateFormat = this.dateFormat;
10158 cv = function(v){ return v; };
10161 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10165 return v !== undefined && v !== null && v !== '' ?
10166 parseInt(String(v).replace(stripRe, ""), 10) : '';
10171 return v !== undefined && v !== null && v !== '' ?
10172 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10177 cv = function(v){ return v === true || v === "true" || v == 1; };
10184 if(v instanceof Date){
10188 if(dateFormat == "timestamp"){
10189 return new Date(v*1000);
10191 return Date.parseDate(v, dateFormat);
10193 var parsed = Date.parse(v);
10194 return parsed ? new Date(parsed) : null;
10203 Roo.data.Field.prototype = {
10211 * Ext JS Library 1.1.1
10212 * Copyright(c) 2006-2007, Ext JS, LLC.
10214 * Originally Released Under LGPL - original licence link has changed is not relivant.
10217 * <script type="text/javascript">
10220 // Base class for reading structured data from a data source. This class is intended to be
10221 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10224 * @class Roo.data.DataReader
10225 * Base class for reading structured data from a data source. This class is intended to be
10226 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10229 Roo.data.DataReader = function(meta, recordType){
10233 this.recordType = recordType instanceof Array ?
10234 Roo.data.Record.create(recordType) : recordType;
10237 Roo.data.DataReader.prototype = {
10239 * Create an empty record
10240 * @param {Object} data (optional) - overlay some values
10241 * @return {Roo.data.Record} record created.
10243 newRow : function(d) {
10245 this.recordType.prototype.fields.each(function(c) {
10247 case 'int' : da[c.name] = 0; break;
10248 case 'date' : da[c.name] = new Date(); break;
10249 case 'float' : da[c.name] = 0.0; break;
10250 case 'boolean' : da[c.name] = false; break;
10251 default : da[c.name] = ""; break;
10255 return new this.recordType(Roo.apply(da, d));
10260 * Ext JS Library 1.1.1
10261 * Copyright(c) 2006-2007, Ext JS, LLC.
10263 * Originally Released Under LGPL - original licence link has changed is not relivant.
10266 * <script type="text/javascript">
10270 * @class Roo.data.DataProxy
10271 * @extends Roo.data.Observable
10272 * This class is an abstract base class for implementations which provide retrieval of
10273 * unformatted data objects.<br>
10275 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10276 * (of the appropriate type which knows how to parse the data object) to provide a block of
10277 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10279 * Custom implementations must implement the load method as described in
10280 * {@link Roo.data.HttpProxy#load}.
10282 Roo.data.DataProxy = function(){
10285 * @event beforeload
10286 * Fires before a network request is made to retrieve a data object.
10287 * @param {Object} This DataProxy object.
10288 * @param {Object} params The params parameter to the load function.
10293 * Fires before the load method's callback is called.
10294 * @param {Object} This DataProxy object.
10295 * @param {Object} o The data object.
10296 * @param {Object} arg The callback argument object passed to the load function.
10300 * @event loadexception
10301 * Fires if an Exception occurs during data retrieval.
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.
10305 * @param {Object} e The Exception.
10307 loadexception : true
10309 Roo.data.DataProxy.superclass.constructor.call(this);
10312 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10315 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10319 * Ext JS Library 1.1.1
10320 * Copyright(c) 2006-2007, Ext JS, LLC.
10322 * Originally Released Under LGPL - original licence link has changed is not relivant.
10325 * <script type="text/javascript">
10328 * @class Roo.data.MemoryProxy
10329 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10330 * to the Reader when its load method is called.
10332 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10334 Roo.data.MemoryProxy = function(data){
10338 Roo.data.MemoryProxy.superclass.constructor.call(this);
10342 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10344 * Load data from the requested source (in this case an in-memory
10345 * data object passed to the constructor), read the data object into
10346 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10347 * process that block using the passed callback.
10348 * @param {Object} params This parameter is not used by the MemoryProxy class.
10349 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10350 * object into a block of Roo.data.Records.
10351 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10352 * The function must be passed <ul>
10353 * <li>The Record block object</li>
10354 * <li>The "arg" argument from the load function</li>
10355 * <li>A boolean success indicator</li>
10357 * @param {Object} scope The scope in which to call the callback
10358 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10360 load : function(params, reader, callback, scope, arg){
10361 params = params || {};
10364 result = reader.readRecords(this.data);
10366 this.fireEvent("loadexception", this, arg, null, e);
10367 callback.call(scope, null, arg, false);
10370 callback.call(scope, result, arg, true);
10374 update : function(params, records){
10379 * Ext JS Library 1.1.1
10380 * Copyright(c) 2006-2007, Ext JS, LLC.
10382 * Originally Released Under LGPL - original licence link has changed is not relivant.
10385 * <script type="text/javascript">
10388 * @class Roo.data.HttpProxy
10389 * @extends Roo.data.DataProxy
10390 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10391 * configured to reference a certain URL.<br><br>
10393 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10394 * from which the running page was served.<br><br>
10396 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10398 * Be aware that to enable the browser to parse an XML document, the server must set
10399 * the Content-Type header in the HTTP response to "text/xml".
10401 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10402 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10403 * will be used to make the request.
10405 Roo.data.HttpProxy = function(conn){
10406 Roo.data.HttpProxy.superclass.constructor.call(this);
10407 // is conn a conn config or a real conn?
10409 this.useAjax = !conn || !conn.events;
10413 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10414 // thse are take from connection...
10417 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10420 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10421 * extra parameters to each request made by this object. (defaults to undefined)
10424 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10425 * to each request made by this object. (defaults to undefined)
10428 * @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)
10431 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10434 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10440 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10444 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10445 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10446 * a finer-grained basis than the DataProxy events.
10448 getConnection : function(){
10449 return this.useAjax ? Roo.Ajax : this.conn;
10453 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10454 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10455 * process that block using the passed callback.
10456 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10457 * for the request to the remote server.
10458 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10459 * object into a block of Roo.data.Records.
10460 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10461 * The function must be passed <ul>
10462 * <li>The Record block object</li>
10463 * <li>The "arg" argument from the load function</li>
10464 * <li>A boolean success indicator</li>
10466 * @param {Object} scope The scope in which to call the callback
10467 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10469 load : function(params, reader, callback, scope, arg){
10470 if(this.fireEvent("beforeload", this, params) !== false){
10472 params : params || {},
10474 callback : callback,
10479 callback : this.loadResponse,
10483 Roo.applyIf(o, this.conn);
10484 if(this.activeRequest){
10485 Roo.Ajax.abort(this.activeRequest);
10487 this.activeRequest = Roo.Ajax.request(o);
10489 this.conn.request(o);
10492 callback.call(scope||this, null, arg, false);
10497 loadResponse : function(o, success, response){
10498 delete this.activeRequest;
10500 this.fireEvent("loadexception", this, o, response);
10501 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10506 result = o.reader.read(response);
10508 this.fireEvent("loadexception", this, o, response, e);
10509 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10513 this.fireEvent("load", this, o, o.request.arg);
10514 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10518 update : function(dataSet){
10523 updateResponse : function(dataSet){
10528 * Ext JS Library 1.1.1
10529 * Copyright(c) 2006-2007, Ext JS, LLC.
10531 * Originally Released Under LGPL - original licence link has changed is not relivant.
10534 * <script type="text/javascript">
10538 * @class Roo.data.ScriptTagProxy
10539 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10540 * other than the originating domain of the running page.<br><br>
10542 * <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
10543 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10545 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10546 * source code that is used as the source inside a <script> tag.<br><br>
10548 * In order for the browser to process the returned data, the server must wrap the data object
10549 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10550 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10551 * depending on whether the callback name was passed:
10554 boolean scriptTag = false;
10555 String cb = request.getParameter("callback");
10558 response.setContentType("text/javascript");
10560 response.setContentType("application/x-json");
10562 Writer out = response.getWriter();
10564 out.write(cb + "(");
10566 out.print(dataBlock.toJsonString());
10573 * @param {Object} config A configuration object.
10575 Roo.data.ScriptTagProxy = function(config){
10576 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10577 Roo.apply(this, config);
10578 this.head = document.getElementsByTagName("head")[0];
10581 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10583 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10585 * @cfg {String} url The URL from which to request the data object.
10588 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10592 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10593 * the server the name of the callback function set up by the load call to process the returned data object.
10594 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10595 * javascript output which calls this named function passing the data object as its only parameter.
10597 callbackParam : "callback",
10599 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10600 * name to the request.
10605 * Load data from the configured URL, read the data object into
10606 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10607 * process that block using the passed callback.
10608 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10609 * for the request to the remote server.
10610 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10611 * object into a block of Roo.data.Records.
10612 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10613 * The function must be passed <ul>
10614 * <li>The Record block object</li>
10615 * <li>The "arg" argument from the load function</li>
10616 * <li>A boolean success indicator</li>
10618 * @param {Object} scope The scope in which to call the callback
10619 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10621 load : function(params, reader, callback, scope, arg){
10622 if(this.fireEvent("beforeload", this, params) !== false){
10624 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10626 var url = this.url;
10627 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10629 url += "&_dc=" + (new Date().getTime());
10631 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10634 cb : "stcCallback"+transId,
10635 scriptId : "stcScript"+transId,
10639 callback : callback,
10645 window[trans.cb] = function(o){
10646 conn.handleResponse(o, trans);
10649 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10651 if(this.autoAbort !== false){
10655 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10657 var script = document.createElement("script");
10658 script.setAttribute("src", url);
10659 script.setAttribute("type", "text/javascript");
10660 script.setAttribute("id", trans.scriptId);
10661 this.head.appendChild(script);
10663 this.trans = trans;
10665 callback.call(scope||this, null, arg, false);
10670 isLoading : function(){
10671 return this.trans ? true : false;
10675 * Abort the current server request.
10677 abort : function(){
10678 if(this.isLoading()){
10679 this.destroyTrans(this.trans);
10684 destroyTrans : function(trans, isLoaded){
10685 this.head.removeChild(document.getElementById(trans.scriptId));
10686 clearTimeout(trans.timeoutId);
10688 window[trans.cb] = undefined;
10690 delete window[trans.cb];
10693 // if hasn't been loaded, wait for load to remove it to prevent script error
10694 window[trans.cb] = function(){
10695 window[trans.cb] = undefined;
10697 delete window[trans.cb];
10704 handleResponse : function(o, trans){
10705 this.trans = false;
10706 this.destroyTrans(trans, true);
10709 result = trans.reader.readRecords(o);
10711 this.fireEvent("loadexception", this, o, trans.arg, e);
10712 trans.callback.call(trans.scope||window, null, trans.arg, false);
10715 this.fireEvent("load", this, o, trans.arg);
10716 trans.callback.call(trans.scope||window, result, trans.arg, true);
10720 handleFailure : function(trans){
10721 this.trans = false;
10722 this.destroyTrans(trans, false);
10723 this.fireEvent("loadexception", this, null, trans.arg);
10724 trans.callback.call(trans.scope||window, null, trans.arg, false);
10728 * Ext JS Library 1.1.1
10729 * Copyright(c) 2006-2007, Ext JS, LLC.
10731 * Originally Released Under LGPL - original licence link has changed is not relivant.
10734 * <script type="text/javascript">
10738 * @class Roo.data.JsonReader
10739 * @extends Roo.data.DataReader
10740 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10741 * based on mappings in a provided Roo.data.Record constructor.
10743 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10744 * in the reply previously.
10749 var RecordDef = Roo.data.Record.create([
10750 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10751 {name: 'occupation'} // This field will use "occupation" as the mapping.
10753 var myReader = new Roo.data.JsonReader({
10754 totalProperty: "results", // The property which contains the total dataset size (optional)
10755 root: "rows", // The property which contains an Array of row objects
10756 id: "id" // The property within each row object that provides an ID for the record (optional)
10760 * This would consume a JSON file like this:
10762 { 'results': 2, 'rows': [
10763 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10764 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10767 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10768 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10769 * paged from the remote server.
10770 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10771 * @cfg {String} root name of the property which contains the Array of row objects.
10772 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10773 * @cfg {Array} fields Array of field definition objects
10775 * Create a new JsonReader
10776 * @param {Object} meta Metadata configuration options
10777 * @param {Object} recordType Either an Array of field definition objects,
10778 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10780 Roo.data.JsonReader = function(meta, recordType){
10783 // set some defaults:
10784 Roo.applyIf(meta, {
10785 totalProperty: 'total',
10786 successProperty : 'success',
10791 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10793 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10796 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10797 * Used by Store query builder to append _requestMeta to params.
10800 metaFromRemote : false,
10802 * This method is only used by a DataProxy which has retrieved data from a remote server.
10803 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10804 * @return {Object} data A data block which is used by an Roo.data.Store object as
10805 * a cache of Roo.data.Records.
10807 read : function(response){
10808 var json = response.responseText;
10810 var o = /* eval:var:o */ eval("("+json+")");
10812 throw {message: "JsonReader.read: Json object not found"};
10818 this.metaFromRemote = true;
10819 this.meta = o.metaData;
10820 this.recordType = Roo.data.Record.create(o.metaData.fields);
10821 this.onMetaChange(this.meta, this.recordType, o);
10823 return this.readRecords(o);
10826 // private function a store will implement
10827 onMetaChange : function(meta, recordType, o){
10834 simpleAccess: function(obj, subsc) {
10841 getJsonAccessor: function(){
10843 return function(expr) {
10845 return(re.test(expr))
10846 ? new Function("obj", "return obj." + expr)
10851 return Roo.emptyFn;
10856 * Create a data block containing Roo.data.Records from an XML document.
10857 * @param {Object} o An object which contains an Array of row objects in the property specified
10858 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10859 * which contains the total size of the dataset.
10860 * @return {Object} data A data block which is used by an Roo.data.Store object as
10861 * a cache of Roo.data.Records.
10863 readRecords : function(o){
10865 * After any data loads, the raw JSON data is available for further custom processing.
10869 var s = this.meta, Record = this.recordType,
10870 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10872 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10874 if(s.totalProperty) {
10875 this.getTotal = this.getJsonAccessor(s.totalProperty);
10877 if(s.successProperty) {
10878 this.getSuccess = this.getJsonAccessor(s.successProperty);
10880 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10882 var g = this.getJsonAccessor(s.id);
10883 this.getId = function(rec) {
10885 return (r === undefined || r === "") ? null : r;
10888 this.getId = function(){return null;};
10891 for(var jj = 0; jj < fl; jj++){
10893 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10894 this.ef[jj] = this.getJsonAccessor(map);
10898 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10899 if(s.totalProperty){
10900 var vt = parseInt(this.getTotal(o), 10);
10905 if(s.successProperty){
10906 var vs = this.getSuccess(o);
10907 if(vs === false || vs === 'false'){
10912 for(var i = 0; i < c; i++){
10915 var id = this.getId(n);
10916 for(var j = 0; j < fl; j++){
10918 var v = this.ef[j](n);
10920 Roo.log('missing convert for ' + f.name);
10924 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10926 var record = new Record(values, id);
10928 records[i] = record;
10934 totalRecords : totalRecords
10939 * Ext JS Library 1.1.1
10940 * Copyright(c) 2006-2007, Ext JS, LLC.
10942 * Originally Released Under LGPL - original licence link has changed is not relivant.
10945 * <script type="text/javascript">
10949 * @class Roo.data.ArrayReader
10950 * @extends Roo.data.DataReader
10951 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10952 * Each element of that Array represents a row of data fields. The
10953 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10954 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10958 var RecordDef = Roo.data.Record.create([
10959 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10960 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10962 var myReader = new Roo.data.ArrayReader({
10963 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10967 * This would consume an Array like this:
10969 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10971 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10973 * Create a new JsonReader
10974 * @param {Object} meta Metadata configuration options.
10975 * @param {Object} recordType Either an Array of field definition objects
10976 * as specified to {@link Roo.data.Record#create},
10977 * or an {@link Roo.data.Record} object
10978 * created using {@link Roo.data.Record#create}.
10980 Roo.data.ArrayReader = function(meta, recordType){
10981 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10984 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10986 * Create a data block containing Roo.data.Records from an XML document.
10987 * @param {Object} o An Array of row objects which represents the dataset.
10988 * @return {Object} data A data block which is used by an Roo.data.Store object as
10989 * a cache of Roo.data.Records.
10991 readRecords : function(o){
10992 var sid = this.meta ? this.meta.id : null;
10993 var recordType = this.recordType, fields = recordType.prototype.fields;
10996 for(var i = 0; i < root.length; i++){
10999 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11000 for(var j = 0, jlen = fields.length; j < jlen; j++){
11001 var f = fields.items[j];
11002 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11003 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11005 values[f.name] = v;
11007 var record = new recordType(values, id);
11009 records[records.length] = record;
11013 totalRecords : records.length
11022 * @class Roo.bootstrap.ComboBox
11023 * @extends Roo.bootstrap.TriggerField
11024 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11025 * @cfg {Boolean} append (true|false) default false
11026 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11027 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11028 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11029 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11030 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11032 * Create a new ComboBox.
11033 * @param {Object} config Configuration options
11035 Roo.bootstrap.ComboBox = function(config){
11036 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11040 * Fires when the dropdown list is expanded
11041 * @param {Roo.bootstrap.ComboBox} combo This combo box
11046 * Fires when the dropdown list is collapsed
11047 * @param {Roo.bootstrap.ComboBox} combo This combo box
11051 * @event beforeselect
11052 * Fires before a list item is selected. Return false to cancel the selection.
11053 * @param {Roo.bootstrap.ComboBox} combo This combo box
11054 * @param {Roo.data.Record} record The data record returned from the underlying store
11055 * @param {Number} index The index of the selected item in the dropdown list
11057 'beforeselect' : true,
11060 * Fires when a list item is selected
11061 * @param {Roo.bootstrap.ComboBox} combo This combo box
11062 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11063 * @param {Number} index The index of the selected item in the dropdown list
11067 * @event beforequery
11068 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11069 * The event object passed has these properties:
11070 * @param {Roo.bootstrap.ComboBox} combo This combo box
11071 * @param {String} query The query
11072 * @param {Boolean} forceAll true to force "all" query
11073 * @param {Boolean} cancel true to cancel the query
11074 * @param {Object} e The query event object
11076 'beforequery': true,
11079 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11080 * @param {Roo.bootstrap.ComboBox} combo This combo box
11085 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11086 * @param {Roo.bootstrap.ComboBox} combo This combo box
11087 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11092 * Fires when the remove value from the combobox array
11093 * @param {Roo.bootstrap.ComboBox} combo This combo box
11097 * @event specialfilter
11098 * Fires when specialfilter
11099 * @param {Roo.bootstrap.ComboBox} combo This combo box
11101 'specialfilter' : true
11106 this.tickItems = [];
11108 this.selectedIndex = -1;
11109 if(this.mode == 'local'){
11110 if(config.queryDelay === undefined){
11111 this.queryDelay = 10;
11113 if(config.minChars === undefined){
11119 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11122 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11123 * rendering into an Roo.Editor, defaults to false)
11126 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11127 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11130 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11133 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11134 * the dropdown list (defaults to undefined, with no header element)
11138 * @cfg {String/Roo.Template} tpl The template to use to render the output
11142 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11144 listWidth: undefined,
11146 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11147 * mode = 'remote' or 'text' if mode = 'local')
11149 displayField: undefined,
11152 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11153 * mode = 'remote' or 'value' if mode = 'local').
11154 * Note: use of a valueField requires the user make a selection
11155 * in order for a value to be mapped.
11157 valueField: undefined,
11161 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11162 * field's data value (defaults to the underlying DOM element's name)
11164 hiddenName: undefined,
11166 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11170 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11172 selectedClass: 'active',
11175 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11179 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11180 * anchor positions (defaults to 'tl-bl')
11182 listAlign: 'tl-bl?',
11184 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11188 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11189 * query specified by the allQuery config option (defaults to 'query')
11191 triggerAction: 'query',
11193 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11194 * (defaults to 4, does not apply if editable = false)
11198 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11199 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11203 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11204 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11208 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11209 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11213 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11214 * when editable = true (defaults to false)
11216 selectOnFocus:false,
11218 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11220 queryParam: 'query',
11222 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11223 * when mode = 'remote' (defaults to 'Loading...')
11225 loadingText: 'Loading...',
11227 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11231 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11235 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11236 * traditional select (defaults to true)
11240 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11244 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11248 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11249 * listWidth has a higher value)
11253 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11254 * allow the user to set arbitrary text into the field (defaults to false)
11256 forceSelection:false,
11258 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11259 * if typeAhead = true (defaults to 250)
11261 typeAheadDelay : 250,
11263 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11264 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11266 valueNotFoundText : undefined,
11268 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11270 blockFocus : false,
11273 * @cfg {Boolean} disableClear Disable showing of clear button.
11275 disableClear : false,
11277 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11279 alwaysQuery : false,
11282 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11287 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11289 invalidClass : "has-warning",
11292 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11294 validClass : "has-success",
11297 * @cfg {Boolean} specialFilter (true|false) special filter default false
11299 specialFilter : false,
11311 btnPosition : 'right',
11312 triggerList : true,
11313 showToggleBtn : true,
11314 // element that contains real text value.. (when hidden is used..)
11316 getAutoCreate : function()
11323 if(!this.tickable){
11324 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11329 * ComboBox with tickable selections
11332 var align = this.labelAlign || this.parentLabelAlign();
11335 cls : 'form-group roo-combobox-tickable' //input-group
11340 cls : 'tickable-buttons',
11345 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11352 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11359 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11366 buttons.cn.unshift({
11368 cls: 'select2-search-field-input'
11374 Roo.each(buttons.cn, function(c){
11376 c.cls += ' btn-' + _this.size;
11379 if (_this.disabled) {
11390 cls: 'form-hidden-field'
11394 cls: 'select2-choices',
11398 cls: 'select2-search-field',
11410 cls: 'select2-container input-group select2-container-multi',
11415 // cls: 'typeahead typeahead-long dropdown-menu',
11416 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11421 if(this.hasFeedback && !this.allowBlank){
11425 cls: 'glyphicon form-control-feedback'
11428 combobox.cn.push(feedback);
11431 if (align ==='left' && this.fieldLabel.length) {
11433 Roo.log("left and has label");
11439 cls : 'control-label col-sm-' + this.labelWidth,
11440 html : this.fieldLabel
11444 cls : "col-sm-" + (12 - this.labelWidth),
11451 } else if ( this.fieldLabel.length) {
11457 //cls : 'input-group-addon',
11458 html : this.fieldLabel
11468 Roo.log(" no label && no align");
11475 ['xs','sm','md','lg'].map(function(size){
11476 if (settings[size]) {
11477 cfg.cls += ' col-' + size + '-' + settings[size];
11486 initEvents: function()
11490 throw "can not find store for combo";
11492 this.store = Roo.factory(this.store, Roo.data);
11495 this.initTickableEvents();
11499 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11501 if(this.hiddenName){
11503 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11505 this.hiddenField.dom.value =
11506 this.hiddenValue !== undefined ? this.hiddenValue :
11507 this.value !== undefined ? this.value : '';
11509 // prevent input submission
11510 this.el.dom.removeAttribute('name');
11511 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11516 // this.el.dom.setAttribute('autocomplete', 'off');
11519 var cls = 'x-combo-list';
11521 //this.list = new Roo.Layer({
11522 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11528 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11529 _this.list.setWidth(lw);
11532 this.list.on('mouseover', this.onViewOver, this);
11533 this.list.on('mousemove', this.onViewMove, this);
11535 this.list.on('scroll', this.onViewScroll, this);
11538 this.list.swallowEvent('mousewheel');
11539 this.assetHeight = 0;
11542 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11543 this.assetHeight += this.header.getHeight();
11546 this.innerList = this.list.createChild({cls:cls+'-inner'});
11547 this.innerList.on('mouseover', this.onViewOver, this);
11548 this.innerList.on('mousemove', this.onViewMove, this);
11549 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11551 if(this.allowBlank && !this.pageSize && !this.disableClear){
11552 this.footer = this.list.createChild({cls:cls+'-ft'});
11553 this.pageTb = new Roo.Toolbar(this.footer);
11557 this.footer = this.list.createChild({cls:cls+'-ft'});
11558 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11559 {pageSize: this.pageSize});
11563 if (this.pageTb && this.allowBlank && !this.disableClear) {
11565 this.pageTb.add(new Roo.Toolbar.Fill(), {
11566 cls: 'x-btn-icon x-btn-clear',
11568 handler: function()
11571 _this.clearValue();
11572 _this.onSelect(false, -1);
11577 this.assetHeight += this.footer.getHeight();
11582 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11585 this.view = new Roo.View(this.list, this.tpl, {
11586 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11588 //this.view.wrapEl.setDisplayed(false);
11589 this.view.on('click', this.onViewClick, this);
11593 this.store.on('beforeload', this.onBeforeLoad, this);
11594 this.store.on('load', this.onLoad, this);
11595 this.store.on('loadexception', this.onLoadException, this);
11597 if(this.resizable){
11598 this.resizer = new Roo.Resizable(this.list, {
11599 pinned:true, handles:'se'
11601 this.resizer.on('resize', function(r, w, h){
11602 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11603 this.listWidth = w;
11604 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11605 this.restrictHeight();
11607 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11610 if(!this.editable){
11611 this.editable = true;
11612 this.setEditable(false);
11617 if (typeof(this.events.add.listeners) != 'undefined') {
11619 this.addicon = this.wrap.createChild(
11620 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11622 this.addicon.on('click', function(e) {
11623 this.fireEvent('add', this);
11626 if (typeof(this.events.edit.listeners) != 'undefined') {
11628 this.editicon = this.wrap.createChild(
11629 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11630 if (this.addicon) {
11631 this.editicon.setStyle('margin-left', '40px');
11633 this.editicon.on('click', function(e) {
11635 // we fire even if inothing is selected..
11636 this.fireEvent('edit', this, this.lastData );
11642 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11643 "up" : function(e){
11644 this.inKeyMode = true;
11648 "down" : function(e){
11649 if(!this.isExpanded()){
11650 this.onTriggerClick();
11652 this.inKeyMode = true;
11657 "enter" : function(e){
11658 // this.onViewClick();
11662 if(this.fireEvent("specialkey", this, e)){
11663 this.onViewClick(false);
11669 "esc" : function(e){
11673 "tab" : function(e){
11676 if(this.fireEvent("specialkey", this, e)){
11677 this.onViewClick(false);
11685 doRelay : function(foo, bar, hname){
11686 if(hname == 'down' || this.scope.isExpanded()){
11687 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11696 this.queryDelay = Math.max(this.queryDelay || 10,
11697 this.mode == 'local' ? 10 : 250);
11700 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11702 if(this.typeAhead){
11703 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11705 if(this.editable !== false){
11706 this.inputEl().on("keyup", this.onKeyUp, this);
11708 if(this.forceSelection){
11709 this.inputEl().on('blur', this.doForce, this);
11713 this.choices = this.el.select('ul.select2-choices', true).first();
11714 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11718 initTickableEvents: function()
11722 if(this.hiddenName){
11724 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11726 this.hiddenField.dom.value =
11727 this.hiddenValue !== undefined ? this.hiddenValue :
11728 this.value !== undefined ? this.value : '';
11730 // prevent input submission
11731 this.el.dom.removeAttribute('name');
11732 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11737 // this.list = this.el.select('ul.dropdown-menu',true).first();
11739 this.choices = this.el.select('ul.select2-choices', true).first();
11740 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11741 if(this.triggerList){
11742 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11745 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11746 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11748 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11749 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11751 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11752 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11754 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11755 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11756 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11759 this.cancelBtn.hide();
11764 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11765 _this.list.setWidth(lw);
11768 this.list.on('mouseover', this.onViewOver, this);
11769 this.list.on('mousemove', this.onViewMove, this);
11771 this.list.on('scroll', this.onViewScroll, this);
11774 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>';
11777 this.view = new Roo.View(this.list, this.tpl, {
11778 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11781 //this.view.wrapEl.setDisplayed(false);
11782 this.view.on('click', this.onViewClick, this);
11786 this.store.on('beforeload', this.onBeforeLoad, this);
11787 this.store.on('load', this.onLoad, this);
11788 this.store.on('loadexception', this.onLoadException, this);
11791 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11792 "up" : function(e){
11793 this.inKeyMode = true;
11797 "down" : function(e){
11798 this.inKeyMode = true;
11802 "enter" : function(e){
11803 if(this.fireEvent("specialkey", this, e)){
11804 this.onViewClick(false);
11810 "esc" : function(e){
11811 this.onTickableFooterButtonClick(e, false, false);
11814 "tab" : function(e){
11815 this.fireEvent("specialkey", this, e);
11817 this.onTickableFooterButtonClick(e, false, false);
11824 doRelay : function(e, fn, key){
11825 if(this.scope.isExpanded()){
11826 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11835 this.queryDelay = Math.max(this.queryDelay || 10,
11836 this.mode == 'local' ? 10 : 250);
11839 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11841 if(this.typeAhead){
11842 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11845 if(this.editable !== false){
11846 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11851 onDestroy : function(){
11853 this.view.setStore(null);
11854 this.view.el.removeAllListeners();
11855 this.view.el.remove();
11856 this.view.purgeListeners();
11859 this.list.dom.innerHTML = '';
11863 this.store.un('beforeload', this.onBeforeLoad, this);
11864 this.store.un('load', this.onLoad, this);
11865 this.store.un('loadexception', this.onLoadException, this);
11867 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11871 fireKey : function(e){
11872 if(e.isNavKeyPress() && !this.list.isVisible()){
11873 this.fireEvent("specialkey", this, e);
11878 onResize: function(w, h){
11879 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11881 // if(typeof w != 'number'){
11882 // // we do not handle it!?!?
11885 // var tw = this.trigger.getWidth();
11886 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11887 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11889 // this.inputEl().setWidth( this.adjustWidth('input', x));
11891 // //this.trigger.setStyle('left', x+'px');
11893 // if(this.list && this.listWidth === undefined){
11894 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11895 // this.list.setWidth(lw);
11896 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11904 * Allow or prevent the user from directly editing the field text. If false is passed,
11905 * the user will only be able to select from the items defined in the dropdown list. This method
11906 * is the runtime equivalent of setting the 'editable' config option at config time.
11907 * @param {Boolean} value True to allow the user to directly edit the field text
11909 setEditable : function(value){
11910 if(value == this.editable){
11913 this.editable = value;
11915 this.inputEl().dom.setAttribute('readOnly', true);
11916 this.inputEl().on('mousedown', this.onTriggerClick, this);
11917 this.inputEl().addClass('x-combo-noedit');
11919 this.inputEl().dom.setAttribute('readOnly', false);
11920 this.inputEl().un('mousedown', this.onTriggerClick, this);
11921 this.inputEl().removeClass('x-combo-noedit');
11927 onBeforeLoad : function(combo,opts){
11928 if(!this.hasFocus){
11932 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11934 this.restrictHeight();
11935 this.selectedIndex = -1;
11939 onLoad : function(){
11941 this.hasQuery = false;
11943 if(!this.hasFocus){
11947 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11948 this.loading.hide();
11951 if(this.store.getCount() > 0){
11953 this.restrictHeight();
11954 if(this.lastQuery == this.allQuery){
11955 if(this.editable && !this.tickable){
11956 this.inputEl().dom.select();
11960 !this.selectByValue(this.value, true) &&
11963 !this.store.lastOptions ||
11964 typeof(this.store.lastOptions.add) == 'undefined' ||
11965 this.store.lastOptions.add != true
11968 this.select(0, true);
11971 if(this.autoFocus){
11974 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11975 this.taTask.delay(this.typeAheadDelay);
11979 this.onEmptyResults();
11985 onLoadException : function()
11987 this.hasQuery = false;
11989 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11990 this.loading.hide();
11993 if(this.tickable && this.editable){
11999 Roo.log(this.store.reader.jsonData);
12000 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12002 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12008 onTypeAhead : function(){
12009 if(this.store.getCount() > 0){
12010 var r = this.store.getAt(0);
12011 var newValue = r.data[this.displayField];
12012 var len = newValue.length;
12013 var selStart = this.getRawValue().length;
12015 if(selStart != len){
12016 this.setRawValue(newValue);
12017 this.selectText(selStart, newValue.length);
12023 onSelect : function(record, index){
12025 if(this.fireEvent('beforeselect', this, record, index) !== false){
12027 this.setFromData(index > -1 ? record.data : false);
12030 this.fireEvent('select', this, record, index);
12035 * Returns the currently selected field value or empty string if no value is set.
12036 * @return {String} value The selected value
12038 getValue : function(){
12041 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12044 if(this.valueField){
12045 return typeof this.value != 'undefined' ? this.value : '';
12047 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12052 * Clears any text/value currently set in the field
12054 clearValue : function(){
12055 if(this.hiddenField){
12056 this.hiddenField.dom.value = '';
12059 this.setRawValue('');
12060 this.lastSelectionText = '';
12061 this.lastData = false;
12063 var close = this.closeTriggerEl();
12072 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12073 * will be displayed in the field. If the value does not match the data value of an existing item,
12074 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12075 * Otherwise the field will be blank (although the value will still be set).
12076 * @param {String} value The value to match
12078 setValue : function(v){
12085 if(this.valueField){
12086 var r = this.findRecord(this.valueField, v);
12088 text = r.data[this.displayField];
12089 }else if(this.valueNotFoundText !== undefined){
12090 text = this.valueNotFoundText;
12093 this.lastSelectionText = text;
12094 if(this.hiddenField){
12095 this.hiddenField.dom.value = v;
12097 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12100 var close = this.closeTriggerEl();
12103 (v.length || v * 1 > 0) ? close.show() : close.hide();
12107 * @property {Object} the last set data for the element
12112 * Sets the value of the field based on a object which is related to the record format for the store.
12113 * @param {Object} value the value to set as. or false on reset?
12115 setFromData : function(o){
12122 var dv = ''; // display value
12123 var vv = ''; // value value..
12125 if (this.displayField) {
12126 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12128 // this is an error condition!!!
12129 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12132 if(this.valueField){
12133 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12136 var close = this.closeTriggerEl();
12139 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12142 if(this.hiddenField){
12143 this.hiddenField.dom.value = vv;
12145 this.lastSelectionText = dv;
12146 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12150 // no hidden field.. - we store the value in 'value', but still display
12151 // display field!!!!
12152 this.lastSelectionText = dv;
12153 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12160 reset : function(){
12161 // overridden so that last data is reset..
12168 this.setValue(this.originalValue);
12169 this.clearInvalid();
12170 this.lastData = false;
12172 this.view.clearSelections();
12176 findRecord : function(prop, value){
12178 if(this.store.getCount() > 0){
12179 this.store.each(function(r){
12180 if(r.data[prop] == value){
12190 getName: function()
12192 // returns hidden if it's set..
12193 if (!this.rendered) {return ''};
12194 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12198 onViewMove : function(e, t){
12199 this.inKeyMode = false;
12203 onViewOver : function(e, t){
12204 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12207 var item = this.view.findItemFromChild(t);
12210 var index = this.view.indexOf(item);
12211 this.select(index, false);
12216 onViewClick : function(view, doFocus, el, e)
12218 var index = this.view.getSelectedIndexes()[0];
12220 var r = this.store.getAt(index);
12224 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12231 Roo.each(this.tickItems, function(v,k){
12233 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12234 _this.tickItems.splice(k, 1);
12236 if(typeof(e) == 'undefined' && view == false){
12237 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12249 this.tickItems.push(r.data);
12251 if(typeof(e) == 'undefined' && view == false){
12252 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12259 this.onSelect(r, index);
12261 if(doFocus !== false && !this.blockFocus){
12262 this.inputEl().focus();
12267 restrictHeight : function(){
12268 //this.innerList.dom.style.height = '';
12269 //var inner = this.innerList.dom;
12270 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12271 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12272 //this.list.beginUpdate();
12273 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12274 this.list.alignTo(this.inputEl(), this.listAlign);
12275 this.list.alignTo(this.inputEl(), this.listAlign);
12276 //this.list.endUpdate();
12280 onEmptyResults : function(){
12282 if(this.tickable && this.editable){
12283 this.restrictHeight();
12291 * Returns true if the dropdown list is expanded, else false.
12293 isExpanded : function(){
12294 return this.list.isVisible();
12298 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12299 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12300 * @param {String} value The data value of the item to select
12301 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12302 * selected item if it is not currently in view (defaults to true)
12303 * @return {Boolean} True if the value matched an item in the list, else false
12305 selectByValue : function(v, scrollIntoView){
12306 if(v !== undefined && v !== null){
12307 var r = this.findRecord(this.valueField || this.displayField, v);
12309 this.select(this.store.indexOf(r), scrollIntoView);
12317 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12318 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12319 * @param {Number} index The zero-based index of the list item to select
12320 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12321 * selected item if it is not currently in view (defaults to true)
12323 select : function(index, scrollIntoView){
12324 this.selectedIndex = index;
12325 this.view.select(index);
12326 if(scrollIntoView !== false){
12327 var el = this.view.getNode(index);
12329 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12332 this.list.scrollChildIntoView(el, false);
12338 selectNext : function(){
12339 var ct = this.store.getCount();
12341 if(this.selectedIndex == -1){
12343 }else if(this.selectedIndex < ct-1){
12344 this.select(this.selectedIndex+1);
12350 selectPrev : function(){
12351 var ct = this.store.getCount();
12353 if(this.selectedIndex == -1){
12355 }else if(this.selectedIndex != 0){
12356 this.select(this.selectedIndex-1);
12362 onKeyUp : function(e){
12363 if(this.editable !== false && !e.isSpecialKey()){
12364 this.lastKey = e.getKey();
12365 this.dqTask.delay(this.queryDelay);
12370 validateBlur : function(){
12371 return !this.list || !this.list.isVisible();
12375 initQuery : function(){
12377 var v = this.getRawValue();
12379 if(this.tickable && this.editable){
12380 v = this.tickableInputEl().getValue();
12387 doForce : function(){
12388 if(this.inputEl().dom.value.length > 0){
12389 this.inputEl().dom.value =
12390 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12396 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12397 * query allowing the query action to be canceled if needed.
12398 * @param {String} query The SQL query to execute
12399 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12400 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12401 * saved in the current store (defaults to false)
12403 doQuery : function(q, forceAll){
12405 if(q === undefined || q === null){
12410 forceAll: forceAll,
12414 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12419 forceAll = qe.forceAll;
12420 if(forceAll === true || (q.length >= this.minChars)){
12422 this.hasQuery = true;
12424 if(this.lastQuery != q || this.alwaysQuery){
12425 this.lastQuery = q;
12426 if(this.mode == 'local'){
12427 this.selectedIndex = -1;
12429 this.store.clearFilter();
12432 if(this.specialFilter){
12433 this.fireEvent('specialfilter', this);
12438 this.store.filter(this.displayField, q);
12441 this.store.fireEvent("datachanged", this.store);
12448 this.store.baseParams[this.queryParam] = q;
12450 var options = {params : this.getParams(q)};
12453 options.add = true;
12454 options.params.start = this.page * this.pageSize;
12457 this.store.load(options);
12460 * this code will make the page width larger, at the beginning, the list not align correctly,
12461 * we should expand the list on onLoad
12462 * so command out it
12467 this.selectedIndex = -1;
12472 this.loadNext = false;
12476 getParams : function(q){
12478 //p[this.queryParam] = q;
12482 p.limit = this.pageSize;
12488 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12490 collapse : function(){
12491 if(!this.isExpanded()){
12498 this.hasFocus = false;
12500 this.cancelBtn.hide();
12501 this.trigger.show();
12504 this.tickableInputEl().dom.value = '';
12505 this.tickableInputEl().blur();
12510 Roo.get(document).un('mousedown', this.collapseIf, this);
12511 Roo.get(document).un('mousewheel', this.collapseIf, this);
12512 if (!this.editable) {
12513 Roo.get(document).un('keydown', this.listKeyPress, this);
12515 this.fireEvent('collapse', this);
12519 collapseIf : function(e){
12520 var in_combo = e.within(this.el);
12521 var in_list = e.within(this.list);
12522 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12524 if (in_combo || in_list || is_list) {
12525 //e.stopPropagation();
12530 this.onTickableFooterButtonClick(e, false, false);
12538 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12540 expand : function(){
12542 if(this.isExpanded() || !this.hasFocus){
12546 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12547 this.list.setWidth(lw);
12554 this.restrictHeight();
12558 this.tickItems = Roo.apply([], this.item);
12561 this.cancelBtn.show();
12562 this.trigger.hide();
12565 this.tickableInputEl().focus();
12570 Roo.get(document).on('mousedown', this.collapseIf, this);
12571 Roo.get(document).on('mousewheel', this.collapseIf, this);
12572 if (!this.editable) {
12573 Roo.get(document).on('keydown', this.listKeyPress, this);
12576 this.fireEvent('expand', this);
12580 // Implements the default empty TriggerField.onTriggerClick function
12581 onTriggerClick : function(e)
12583 Roo.log('trigger click');
12585 if(this.disabled || !this.triggerList){
12590 this.loadNext = false;
12592 if(this.isExpanded()){
12594 if (!this.blockFocus) {
12595 this.inputEl().focus();
12599 this.hasFocus = true;
12600 if(this.triggerAction == 'all') {
12601 this.doQuery(this.allQuery, true);
12603 this.doQuery(this.getRawValue());
12605 if (!this.blockFocus) {
12606 this.inputEl().focus();
12611 onTickableTriggerClick : function(e)
12618 this.loadNext = false;
12619 this.hasFocus = true;
12621 if(this.triggerAction == 'all') {
12622 this.doQuery(this.allQuery, true);
12624 this.doQuery(this.getRawValue());
12628 onSearchFieldClick : function(e)
12630 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12631 this.onTickableFooterButtonClick(e, false, false);
12635 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12640 this.loadNext = false;
12641 this.hasFocus = true;
12643 if(this.triggerAction == 'all') {
12644 this.doQuery(this.allQuery, true);
12646 this.doQuery(this.getRawValue());
12650 listKeyPress : function(e)
12652 //Roo.log('listkeypress');
12653 // scroll to first matching element based on key pres..
12654 if (e.isSpecialKey()) {
12657 var k = String.fromCharCode(e.getKey()).toUpperCase();
12660 var csel = this.view.getSelectedNodes();
12661 var cselitem = false;
12663 var ix = this.view.indexOf(csel[0]);
12664 cselitem = this.store.getAt(ix);
12665 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12671 this.store.each(function(v) {
12673 // start at existing selection.
12674 if (cselitem.id == v.id) {
12680 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12681 match = this.store.indexOf(v);
12687 if (match === false) {
12688 return true; // no more action?
12691 this.view.select(match);
12692 var sn = Roo.get(this.view.getSelectedNodes()[0])
12693 sn.scrollIntoView(sn.dom.parentNode, false);
12696 onViewScroll : function(e, t){
12698 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){
12702 this.hasQuery = true;
12704 this.loading = this.list.select('.loading', true).first();
12706 if(this.loading === null){
12707 this.list.createChild({
12709 cls: 'loading select2-more-results select2-active',
12710 html: 'Loading more results...'
12713 this.loading = this.list.select('.loading', true).first();
12715 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12717 this.loading.hide();
12720 this.loading.show();
12725 this.loadNext = true;
12727 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12732 addItem : function(o)
12734 var dv = ''; // display value
12736 if (this.displayField) {
12737 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12739 // this is an error condition!!!
12740 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12747 var choice = this.choices.createChild({
12749 cls: 'select2-search-choice',
12758 cls: 'select2-search-choice-close',
12763 }, this.searchField);
12765 var close = choice.select('a.select2-search-choice-close', true).first()
12767 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12775 this.inputEl().dom.value = '';
12780 onRemoveItem : function(e, _self, o)
12782 e.preventDefault();
12784 this.lastItem = Roo.apply([], this.item);
12786 var index = this.item.indexOf(o.data) * 1;
12789 Roo.log('not this item?!');
12793 this.item.splice(index, 1);
12798 this.fireEvent('remove', this, e);
12804 syncValue : function()
12806 if(!this.item.length){
12813 Roo.each(this.item, function(i){
12814 if(_this.valueField){
12815 value.push(i[_this.valueField]);
12822 this.value = value.join(',');
12824 if(this.hiddenField){
12825 this.hiddenField.dom.value = this.value;
12828 this.store.fireEvent("datachanged", this.store);
12831 clearItem : function()
12833 if(!this.multiple){
12839 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12848 inputEl: function ()
12851 return this.searchField;
12853 return this.el.select('input.form-control',true).first();
12857 onTickableFooterButtonClick : function(e, btn, el)
12859 e.preventDefault();
12861 this.lastItem = Roo.apply([], this.item);
12863 if(btn && btn.name == 'cancel'){
12864 this.tickItems = Roo.apply([], this.item);
12873 Roo.each(this.tickItems, function(o){
12881 validate : function()
12883 var v = this.getRawValue();
12886 v = this.getValue();
12889 if(this.disabled || this.allowBlank || v.length){
12894 this.markInvalid();
12898 tickableInputEl : function()
12900 if(!this.tickable || !this.editable){
12901 return this.inputEl();
12904 return this.inputEl().select('.select2-search-field-input', true).first();
12910 * @cfg {Boolean} grow
12914 * @cfg {Number} growMin
12918 * @cfg {Number} growMax
12928 * Ext JS Library 1.1.1
12929 * Copyright(c) 2006-2007, Ext JS, LLC.
12931 * Originally Released Under LGPL - original licence link has changed is not relivant.
12934 * <script type="text/javascript">
12939 * @extends Roo.util.Observable
12940 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12941 * This class also supports single and multi selection modes. <br>
12942 * Create a data model bound view:
12944 var store = new Roo.data.Store(...);
12946 var view = new Roo.View({
12948 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12950 singleSelect: true,
12951 selectedClass: "ydataview-selected",
12955 // listen for node click?
12956 view.on("click", function(vw, index, node, e){
12957 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12961 dataModel.load("foobar.xml");
12963 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12965 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12966 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12968 * Note: old style constructor is still suported (container, template, config)
12971 * Create a new View
12972 * @param {Object} config The config object
12975 Roo.View = function(config, depreciated_tpl, depreciated_config){
12977 this.parent = false;
12979 if (typeof(depreciated_tpl) == 'undefined') {
12980 // new way.. - universal constructor.
12981 Roo.apply(this, config);
12982 this.el = Roo.get(this.el);
12985 this.el = Roo.get(config);
12986 this.tpl = depreciated_tpl;
12987 Roo.apply(this, depreciated_config);
12989 this.wrapEl = this.el.wrap().wrap();
12990 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12993 if(typeof(this.tpl) == "string"){
12994 this.tpl = new Roo.Template(this.tpl);
12996 // support xtype ctors..
12997 this.tpl = new Roo.factory(this.tpl, Roo);
13001 this.tpl.compile();
13006 * @event beforeclick
13007 * Fires before a click is processed. Returns false to cancel the default action.
13008 * @param {Roo.View} this
13009 * @param {Number} index The index of the target node
13010 * @param {HTMLElement} node The target node
13011 * @param {Roo.EventObject} e The raw event object
13013 "beforeclick" : true,
13016 * Fires when a template node is clicked.
13017 * @param {Roo.View} this
13018 * @param {Number} index The index of the target node
13019 * @param {HTMLElement} node The target node
13020 * @param {Roo.EventObject} e The raw event object
13025 * Fires when a template node is double clicked.
13026 * @param {Roo.View} this
13027 * @param {Number} index The index of the target node
13028 * @param {HTMLElement} node The target node
13029 * @param {Roo.EventObject} e The raw event object
13033 * @event contextmenu
13034 * Fires when a template node is right clicked.
13035 * @param {Roo.View} this
13036 * @param {Number} index The index of the target node
13037 * @param {HTMLElement} node The target node
13038 * @param {Roo.EventObject} e The raw event object
13040 "contextmenu" : true,
13042 * @event selectionchange
13043 * Fires when the selected nodes change.
13044 * @param {Roo.View} this
13045 * @param {Array} selections Array of the selected nodes
13047 "selectionchange" : true,
13050 * @event beforeselect
13051 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13052 * @param {Roo.View} this
13053 * @param {HTMLElement} node The node to be selected
13054 * @param {Array} selections Array of currently selected nodes
13056 "beforeselect" : true,
13058 * @event preparedata
13059 * Fires on every row to render, to allow you to change the data.
13060 * @param {Roo.View} this
13061 * @param {Object} data to be rendered (change this)
13063 "preparedata" : true
13071 "click": this.onClick,
13072 "dblclick": this.onDblClick,
13073 "contextmenu": this.onContextMenu,
13077 this.selections = [];
13079 this.cmp = new Roo.CompositeElementLite([]);
13081 this.store = Roo.factory(this.store, Roo.data);
13082 this.setStore(this.store, true);
13085 if ( this.footer && this.footer.xtype) {
13087 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13089 this.footer.dataSource = this.store
13090 this.footer.container = fctr;
13091 this.footer = Roo.factory(this.footer, Roo);
13092 fctr.insertFirst(this.el);
13094 // this is a bit insane - as the paging toolbar seems to detach the el..
13095 // dom.parentNode.parentNode.parentNode
13096 // they get detached?
13100 Roo.View.superclass.constructor.call(this);
13105 Roo.extend(Roo.View, Roo.util.Observable, {
13108 * @cfg {Roo.data.Store} store Data store to load data from.
13113 * @cfg {String|Roo.Element} el The container element.
13118 * @cfg {String|Roo.Template} tpl The template used by this View
13122 * @cfg {String} dataName the named area of the template to use as the data area
13123 * Works with domtemplates roo-name="name"
13127 * @cfg {String} selectedClass The css class to add to selected nodes
13129 selectedClass : "x-view-selected",
13131 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13136 * @cfg {String} text to display on mask (default Loading)
13140 * @cfg {Boolean} multiSelect Allow multiple selection
13142 multiSelect : false,
13144 * @cfg {Boolean} singleSelect Allow single selection
13146 singleSelect: false,
13149 * @cfg {Boolean} toggleSelect - selecting
13151 toggleSelect : false,
13154 * @cfg {Boolean} tickable - selecting
13159 * Returns the element this view is bound to.
13160 * @return {Roo.Element}
13162 getEl : function(){
13163 return this.wrapEl;
13169 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13171 refresh : function(){
13172 //Roo.log('refresh');
13175 // if we are using something like 'domtemplate', then
13176 // the what gets used is:
13177 // t.applySubtemplate(NAME, data, wrapping data..)
13178 // the outer template then get' applied with
13179 // the store 'extra data'
13180 // and the body get's added to the
13181 // roo-name="data" node?
13182 // <span class='roo-tpl-{name}'></span> ?????
13186 this.clearSelections();
13187 this.el.update("");
13189 var records = this.store.getRange();
13190 if(records.length < 1) {
13192 // is this valid?? = should it render a template??
13194 this.el.update(this.emptyText);
13198 if (this.dataName) {
13199 this.el.update(t.apply(this.store.meta)); //????
13200 el = this.el.child('.roo-tpl-' + this.dataName);
13203 for(var i = 0, len = records.length; i < len; i++){
13204 var data = this.prepareData(records[i].data, i, records[i]);
13205 this.fireEvent("preparedata", this, data, i, records[i]);
13207 var d = Roo.apply({}, data);
13210 Roo.apply(d, {'roo-id' : Roo.id()});
13214 Roo.each(this.parent.item, function(item){
13215 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13218 Roo.apply(d, {'roo-data-checked' : 'checked'});
13222 html[html.length] = Roo.util.Format.trim(
13224 t.applySubtemplate(this.dataName, d, this.store.meta) :
13231 el.update(html.join(""));
13232 this.nodes = el.dom.childNodes;
13233 this.updateIndexes(0);
13238 * Function to override to reformat the data that is sent to
13239 * the template for each node.
13240 * DEPRICATED - use the preparedata event handler.
13241 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13242 * a JSON object for an UpdateManager bound view).
13244 prepareData : function(data, index, record)
13246 this.fireEvent("preparedata", this, data, index, record);
13250 onUpdate : function(ds, record){
13251 // Roo.log('on update');
13252 this.clearSelections();
13253 var index = this.store.indexOf(record);
13254 var n = this.nodes[index];
13255 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13256 n.parentNode.removeChild(n);
13257 this.updateIndexes(index, index);
13263 onAdd : function(ds, records, index)
13265 //Roo.log(['on Add', ds, records, index] );
13266 this.clearSelections();
13267 if(this.nodes.length == 0){
13271 var n = this.nodes[index];
13272 for(var i = 0, len = records.length; i < len; i++){
13273 var d = this.prepareData(records[i].data, i, records[i]);
13275 this.tpl.insertBefore(n, d);
13278 this.tpl.append(this.el, d);
13281 this.updateIndexes(index);
13284 onRemove : function(ds, record, index){
13285 // Roo.log('onRemove');
13286 this.clearSelections();
13287 var el = this.dataName ?
13288 this.el.child('.roo-tpl-' + this.dataName) :
13291 el.dom.removeChild(this.nodes[index]);
13292 this.updateIndexes(index);
13296 * Refresh an individual node.
13297 * @param {Number} index
13299 refreshNode : function(index){
13300 this.onUpdate(this.store, this.store.getAt(index));
13303 updateIndexes : function(startIndex, endIndex){
13304 var ns = this.nodes;
13305 startIndex = startIndex || 0;
13306 endIndex = endIndex || ns.length - 1;
13307 for(var i = startIndex; i <= endIndex; i++){
13308 ns[i].nodeIndex = i;
13313 * Changes the data store this view uses and refresh the view.
13314 * @param {Store} store
13316 setStore : function(store, initial){
13317 if(!initial && this.store){
13318 this.store.un("datachanged", this.refresh);
13319 this.store.un("add", this.onAdd);
13320 this.store.un("remove", this.onRemove);
13321 this.store.un("update", this.onUpdate);
13322 this.store.un("clear", this.refresh);
13323 this.store.un("beforeload", this.onBeforeLoad);
13324 this.store.un("load", this.onLoad);
13325 this.store.un("loadexception", this.onLoad);
13329 store.on("datachanged", this.refresh, this);
13330 store.on("add", this.onAdd, this);
13331 store.on("remove", this.onRemove, this);
13332 store.on("update", this.onUpdate, this);
13333 store.on("clear", this.refresh, this);
13334 store.on("beforeload", this.onBeforeLoad, this);
13335 store.on("load", this.onLoad, this);
13336 store.on("loadexception", this.onLoad, this);
13344 * onbeforeLoad - masks the loading area.
13347 onBeforeLoad : function(store,opts)
13349 //Roo.log('onBeforeLoad');
13351 this.el.update("");
13353 this.el.mask(this.mask ? this.mask : "Loading" );
13355 onLoad : function ()
13362 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13363 * @param {HTMLElement} node
13364 * @return {HTMLElement} The template node
13366 findItemFromChild : function(node){
13367 var el = this.dataName ?
13368 this.el.child('.roo-tpl-' + this.dataName,true) :
13371 if(!node || node.parentNode == el){
13374 var p = node.parentNode;
13375 while(p && p != el){
13376 if(p.parentNode == el){
13385 onClick : function(e){
13386 var item = this.findItemFromChild(e.getTarget());
13388 var index = this.indexOf(item);
13389 if(this.onItemClick(item, index, e) !== false){
13390 this.fireEvent("click", this, index, item, e);
13393 this.clearSelections();
13398 onContextMenu : function(e){
13399 var item = this.findItemFromChild(e.getTarget());
13401 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13406 onDblClick : function(e){
13407 var item = this.findItemFromChild(e.getTarget());
13409 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13413 onItemClick : function(item, index, e)
13415 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13418 if (this.toggleSelect) {
13419 var m = this.isSelected(item) ? 'unselect' : 'select';
13422 _t[m](item, true, false);
13425 if(this.multiSelect || this.singleSelect){
13426 if(this.multiSelect && e.shiftKey && this.lastSelection){
13427 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13429 this.select(item, this.multiSelect && e.ctrlKey);
13430 this.lastSelection = item;
13433 if(!this.tickable){
13434 e.preventDefault();
13442 * Get the number of selected nodes.
13445 getSelectionCount : function(){
13446 return this.selections.length;
13450 * Get the currently selected nodes.
13451 * @return {Array} An array of HTMLElements
13453 getSelectedNodes : function(){
13454 return this.selections;
13458 * Get the indexes of the selected nodes.
13461 getSelectedIndexes : function(){
13462 var indexes = [], s = this.selections;
13463 for(var i = 0, len = s.length; i < len; i++){
13464 indexes.push(s[i].nodeIndex);
13470 * Clear all selections
13471 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13473 clearSelections : function(suppressEvent){
13474 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13475 this.cmp.elements = this.selections;
13476 this.cmp.removeClass(this.selectedClass);
13477 this.selections = [];
13478 if(!suppressEvent){
13479 this.fireEvent("selectionchange", this, this.selections);
13485 * Returns true if the passed node is selected
13486 * @param {HTMLElement/Number} node The node or node index
13487 * @return {Boolean}
13489 isSelected : function(node){
13490 var s = this.selections;
13494 node = this.getNode(node);
13495 return s.indexOf(node) !== -1;
13500 * @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
13501 * @param {Boolean} keepExisting (optional) true to keep existing selections
13502 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13504 select : function(nodeInfo, keepExisting, suppressEvent){
13505 if(nodeInfo instanceof Array){
13507 this.clearSelections(true);
13509 for(var i = 0, len = nodeInfo.length; i < len; i++){
13510 this.select(nodeInfo[i], true, true);
13514 var node = this.getNode(nodeInfo);
13515 if(!node || this.isSelected(node)){
13516 return; // already selected.
13519 this.clearSelections(true);
13522 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13523 Roo.fly(node).addClass(this.selectedClass);
13524 this.selections.push(node);
13525 if(!suppressEvent){
13526 this.fireEvent("selectionchange", this, this.selections);
13534 * @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
13535 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13536 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13538 unselect : function(nodeInfo, keepExisting, suppressEvent)
13540 if(nodeInfo instanceof Array){
13541 Roo.each(this.selections, function(s) {
13542 this.unselect(s, nodeInfo);
13546 var node = this.getNode(nodeInfo);
13547 if(!node || !this.isSelected(node)){
13548 //Roo.log("not selected");
13549 return; // not selected.
13553 Roo.each(this.selections, function(s) {
13555 Roo.fly(node).removeClass(this.selectedClass);
13562 this.selections= ns;
13563 this.fireEvent("selectionchange", this, this.selections);
13567 * Gets a template node.
13568 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13569 * @return {HTMLElement} The node or null if it wasn't found
13571 getNode : function(nodeInfo){
13572 if(typeof nodeInfo == "string"){
13573 return document.getElementById(nodeInfo);
13574 }else if(typeof nodeInfo == "number"){
13575 return this.nodes[nodeInfo];
13581 * Gets a range template nodes.
13582 * @param {Number} startIndex
13583 * @param {Number} endIndex
13584 * @return {Array} An array of nodes
13586 getNodes : function(start, end){
13587 var ns = this.nodes;
13588 start = start || 0;
13589 end = typeof end == "undefined" ? ns.length - 1 : end;
13592 for(var i = start; i <= end; i++){
13596 for(var i = start; i >= end; i--){
13604 * Finds the index of the passed node
13605 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13606 * @return {Number} The index of the node or -1
13608 indexOf : function(node){
13609 node = this.getNode(node);
13610 if(typeof node.nodeIndex == "number"){
13611 return node.nodeIndex;
13613 var ns = this.nodes;
13614 for(var i = 0, len = ns.length; i < len; i++){
13625 * based on jquery fullcalendar
13629 Roo.bootstrap = Roo.bootstrap || {};
13631 * @class Roo.bootstrap.Calendar
13632 * @extends Roo.bootstrap.Component
13633 * Bootstrap Calendar class
13634 * @cfg {Boolean} loadMask (true|false) default false
13635 * @cfg {Object} header generate the user specific header of the calendar, default false
13638 * Create a new Container
13639 * @param {Object} config The config object
13644 Roo.bootstrap.Calendar = function(config){
13645 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13649 * Fires when a date is selected
13650 * @param {DatePicker} this
13651 * @param {Date} date The selected date
13655 * @event monthchange
13656 * Fires when the displayed month changes
13657 * @param {DatePicker} this
13658 * @param {Date} date The selected month
13660 'monthchange': true,
13662 * @event evententer
13663 * Fires when mouse over an event
13664 * @param {Calendar} this
13665 * @param {event} Event
13667 'evententer': true,
13669 * @event eventleave
13670 * Fires when the mouse leaves an
13671 * @param {Calendar} this
13674 'eventleave': true,
13676 * @event eventclick
13677 * Fires when the mouse click an
13678 * @param {Calendar} this
13687 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13690 * @cfg {Number} startDay
13691 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13699 getAutoCreate : function(){
13702 var fc_button = function(name, corner, style, content ) {
13703 return Roo.apply({},{
13705 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13707 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13710 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13721 style : 'width:100%',
13728 cls : 'fc-header-left',
13730 fc_button('prev', 'left', 'arrow', '‹' ),
13731 fc_button('next', 'right', 'arrow', '›' ),
13732 { tag: 'span', cls: 'fc-header-space' },
13733 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13741 cls : 'fc-header-center',
13745 cls: 'fc-header-title',
13748 html : 'month / year'
13756 cls : 'fc-header-right',
13758 /* fc_button('month', 'left', '', 'month' ),
13759 fc_button('week', '', '', 'week' ),
13760 fc_button('day', 'right', '', 'day' )
13772 header = this.header;
13775 var cal_heads = function() {
13777 // fixme - handle this.
13779 for (var i =0; i < Date.dayNames.length; i++) {
13780 var d = Date.dayNames[i];
13783 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13784 html : d.substring(0,3)
13788 ret[0].cls += ' fc-first';
13789 ret[6].cls += ' fc-last';
13792 var cal_cell = function(n) {
13795 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13800 cls: 'fc-day-number',
13804 cls: 'fc-day-content',
13808 style: 'position: relative;' // height: 17px;
13820 var cal_rows = function() {
13823 for (var r = 0; r < 6; r++) {
13830 for (var i =0; i < Date.dayNames.length; i++) {
13831 var d = Date.dayNames[i];
13832 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13835 row.cn[0].cls+=' fc-first';
13836 row.cn[0].cn[0].style = 'min-height:90px';
13837 row.cn[6].cls+=' fc-last';
13841 ret[0].cls += ' fc-first';
13842 ret[4].cls += ' fc-prev-last';
13843 ret[5].cls += ' fc-last';
13850 cls: 'fc-border-separate',
13851 style : 'width:100%',
13859 cls : 'fc-first fc-last',
13877 cls : 'fc-content',
13878 style : "position: relative;",
13881 cls : 'fc-view fc-view-month fc-grid',
13882 style : 'position: relative',
13883 unselectable : 'on',
13886 cls : 'fc-event-container',
13887 style : 'position:absolute;z-index:8;top:0;left:0;'
13905 initEvents : function()
13908 throw "can not find store for calendar";
13914 style: "text-align:center",
13918 style: "background-color:white;width:50%;margin:250 auto",
13922 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13933 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13935 var size = this.el.select('.fc-content', true).first().getSize();
13936 this.maskEl.setSize(size.width, size.height);
13937 this.maskEl.enableDisplayMode("block");
13938 if(!this.loadMask){
13939 this.maskEl.hide();
13942 this.store = Roo.factory(this.store, Roo.data);
13943 this.store.on('load', this.onLoad, this);
13944 this.store.on('beforeload', this.onBeforeLoad, this);
13948 this.cells = this.el.select('.fc-day',true);
13949 //Roo.log(this.cells);
13950 this.textNodes = this.el.query('.fc-day-number');
13951 this.cells.addClassOnOver('fc-state-hover');
13953 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13954 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13955 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13956 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13958 this.on('monthchange', this.onMonthChange, this);
13960 this.update(new Date().clearTime());
13963 resize : function() {
13964 var sz = this.el.getSize();
13966 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13967 this.el.select('.fc-day-content div',true).setHeight(34);
13972 showPrevMonth : function(e){
13973 this.update(this.activeDate.add("mo", -1));
13975 showToday : function(e){
13976 this.update(new Date().clearTime());
13979 showNextMonth : function(e){
13980 this.update(this.activeDate.add("mo", 1));
13984 showPrevYear : function(){
13985 this.update(this.activeDate.add("y", -1));
13989 showNextYear : function(){
13990 this.update(this.activeDate.add("y", 1));
13995 update : function(date)
13997 var vd = this.activeDate;
13998 this.activeDate = date;
13999 // if(vd && this.el){
14000 // var t = date.getTime();
14001 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14002 // Roo.log('using add remove');
14004 // this.fireEvent('monthchange', this, date);
14006 // this.cells.removeClass("fc-state-highlight");
14007 // this.cells.each(function(c){
14008 // if(c.dateValue == t){
14009 // c.addClass("fc-state-highlight");
14010 // setTimeout(function(){
14011 // try{c.dom.firstChild.focus();}catch(e){}
14021 var days = date.getDaysInMonth();
14023 var firstOfMonth = date.getFirstDateOfMonth();
14024 var startingPos = firstOfMonth.getDay()-this.startDay;
14026 if(startingPos < this.startDay){
14030 var pm = date.add(Date.MONTH, -1);
14031 var prevStart = pm.getDaysInMonth()-startingPos;
14033 this.cells = this.el.select('.fc-day',true);
14034 this.textNodes = this.el.query('.fc-day-number');
14035 this.cells.addClassOnOver('fc-state-hover');
14037 var cells = this.cells.elements;
14038 var textEls = this.textNodes;
14040 Roo.each(cells, function(cell){
14041 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14044 days += startingPos;
14046 // convert everything to numbers so it's fast
14047 var day = 86400000;
14048 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14051 //Roo.log(prevStart);
14053 var today = new Date().clearTime().getTime();
14054 var sel = date.clearTime().getTime();
14055 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14056 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14057 var ddMatch = this.disabledDatesRE;
14058 var ddText = this.disabledDatesText;
14059 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14060 var ddaysText = this.disabledDaysText;
14061 var format = this.format;
14063 var setCellClass = function(cal, cell){
14067 //Roo.log('set Cell Class');
14069 var t = d.getTime();
14073 cell.dateValue = t;
14075 cell.className += " fc-today";
14076 cell.className += " fc-state-highlight";
14077 cell.title = cal.todayText;
14080 // disable highlight in other month..
14081 //cell.className += " fc-state-highlight";
14086 cell.className = " fc-state-disabled";
14087 cell.title = cal.minText;
14091 cell.className = " fc-state-disabled";
14092 cell.title = cal.maxText;
14096 if(ddays.indexOf(d.getDay()) != -1){
14097 cell.title = ddaysText;
14098 cell.className = " fc-state-disabled";
14101 if(ddMatch && format){
14102 var fvalue = d.dateFormat(format);
14103 if(ddMatch.test(fvalue)){
14104 cell.title = ddText.replace("%0", fvalue);
14105 cell.className = " fc-state-disabled";
14109 if (!cell.initialClassName) {
14110 cell.initialClassName = cell.dom.className;
14113 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14118 for(; i < startingPos; i++) {
14119 textEls[i].innerHTML = (++prevStart);
14120 d.setDate(d.getDate()+1);
14122 cells[i].className = "fc-past fc-other-month";
14123 setCellClass(this, cells[i]);
14128 for(; i < days; i++){
14129 intDay = i - startingPos + 1;
14130 textEls[i].innerHTML = (intDay);
14131 d.setDate(d.getDate()+1);
14133 cells[i].className = ''; // "x-date-active";
14134 setCellClass(this, cells[i]);
14138 for(; i < 42; i++) {
14139 textEls[i].innerHTML = (++extraDays);
14140 d.setDate(d.getDate()+1);
14142 cells[i].className = "fc-future fc-other-month";
14143 setCellClass(this, cells[i]);
14146 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14148 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14150 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14151 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14153 if(totalRows != 6){
14154 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14155 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14158 this.fireEvent('monthchange', this, date);
14162 if(!this.internalRender){
14163 var main = this.el.dom.firstChild;
14164 var w = main.offsetWidth;
14165 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14166 Roo.fly(main).setWidth(w);
14167 this.internalRender = true;
14168 // opera does not respect the auto grow header center column
14169 // then, after it gets a width opera refuses to recalculate
14170 // without a second pass
14171 if(Roo.isOpera && !this.secondPass){
14172 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14173 this.secondPass = true;
14174 this.update.defer(10, this, [date]);
14181 findCell : function(dt) {
14182 dt = dt.clearTime().getTime();
14184 this.cells.each(function(c){
14185 //Roo.log("check " +c.dateValue + '?=' + dt);
14186 if(c.dateValue == dt){
14196 findCells : function(ev) {
14197 var s = ev.start.clone().clearTime().getTime();
14199 var e= ev.end.clone().clearTime().getTime();
14202 this.cells.each(function(c){
14203 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14205 if(c.dateValue > e){
14208 if(c.dateValue < s){
14217 // findBestRow: function(cells)
14221 // for (var i =0 ; i < cells.length;i++) {
14222 // ret = Math.max(cells[i].rows || 0,ret);
14229 addItem : function(ev)
14231 // look for vertical location slot in
14232 var cells = this.findCells(ev);
14234 // ev.row = this.findBestRow(cells);
14236 // work out the location.
14240 for(var i =0; i < cells.length; i++) {
14242 cells[i].row = cells[0].row;
14245 cells[i].row = cells[i].row + 1;
14255 if (crow.start.getY() == cells[i].getY()) {
14257 crow.end = cells[i];
14274 cells[0].events.push(ev);
14276 this.calevents.push(ev);
14279 clearEvents: function() {
14281 if(!this.calevents){
14285 Roo.each(this.cells.elements, function(c){
14291 Roo.each(this.calevents, function(e) {
14292 Roo.each(e.els, function(el) {
14293 el.un('mouseenter' ,this.onEventEnter, this);
14294 el.un('mouseleave' ,this.onEventLeave, this);
14299 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14305 renderEvents: function()
14309 this.cells.each(function(c) {
14318 if(c.row != c.events.length){
14319 r = 4 - (4 - (c.row - c.events.length));
14322 c.events = ev.slice(0, r);
14323 c.more = ev.slice(r);
14325 if(c.more.length && c.more.length == 1){
14326 c.events.push(c.more.pop());
14329 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14333 this.cells.each(function(c) {
14335 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14338 for (var e = 0; e < c.events.length; e++){
14339 var ev = c.events[e];
14340 var rows = ev.rows;
14342 for(var i = 0; i < rows.length; i++) {
14344 // how many rows should it span..
14347 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14348 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14350 unselectable : "on",
14353 cls: 'fc-event-inner',
14357 // cls: 'fc-event-time',
14358 // html : cells.length > 1 ? '' : ev.time
14362 cls: 'fc-event-title',
14363 html : String.format('{0}', ev.title)
14370 cls: 'ui-resizable-handle ui-resizable-e',
14371 html : '  '
14378 cfg.cls += ' fc-event-start';
14380 if ((i+1) == rows.length) {
14381 cfg.cls += ' fc-event-end';
14384 var ctr = _this.el.select('.fc-event-container',true).first();
14385 var cg = ctr.createChild(cfg);
14387 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14388 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14390 var r = (c.more.length) ? 1 : 0;
14391 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14392 cg.setWidth(ebox.right - sbox.x -2);
14394 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14395 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14396 cg.on('click', _this.onEventClick, _this, ev);
14407 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14408 style : 'position: absolute',
14409 unselectable : "on",
14412 cls: 'fc-event-inner',
14416 cls: 'fc-event-title',
14424 cls: 'ui-resizable-handle ui-resizable-e',
14425 html : '  '
14431 var ctr = _this.el.select('.fc-event-container',true).first();
14432 var cg = ctr.createChild(cfg);
14434 var sbox = c.select('.fc-day-content',true).first().getBox();
14435 var ebox = c.select('.fc-day-content',true).first().getBox();
14437 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14438 cg.setWidth(ebox.right - sbox.x -2);
14440 cg.on('click', _this.onMoreEventClick, _this, c.more);
14450 onEventEnter: function (e, el,event,d) {
14451 this.fireEvent('evententer', this, el, event);
14454 onEventLeave: function (e, el,event,d) {
14455 this.fireEvent('eventleave', this, el, event);
14458 onEventClick: function (e, el,event,d) {
14459 this.fireEvent('eventclick', this, el, event);
14462 onMonthChange: function () {
14466 onMoreEventClick: function(e, el, more)
14470 this.calpopover.placement = 'right';
14471 this.calpopover.setTitle('More');
14473 this.calpopover.setContent('');
14475 var ctr = this.calpopover.el.select('.popover-content', true).first();
14477 Roo.each(more, function(m){
14479 cls : 'fc-event-hori fc-event-draggable',
14482 var cg = ctr.createChild(cfg);
14484 cg.on('click', _this.onEventClick, _this, m);
14487 this.calpopover.show(el);
14492 onLoad: function ()
14494 this.calevents = [];
14497 if(this.store.getCount() > 0){
14498 this.store.data.each(function(d){
14501 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14502 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14503 time : d.data.start_time,
14504 title : d.data.title,
14505 description : d.data.description,
14506 venue : d.data.venue
14511 this.renderEvents();
14513 if(this.calevents.length && this.loadMask){
14514 this.maskEl.hide();
14518 onBeforeLoad: function()
14520 this.clearEvents();
14522 this.maskEl.show();
14536 * @class Roo.bootstrap.Popover
14537 * @extends Roo.bootstrap.Component
14538 * Bootstrap Popover class
14539 * @cfg {String} html contents of the popover (or false to use children..)
14540 * @cfg {String} title of popover (or false to hide)
14541 * @cfg {String} placement how it is placed
14542 * @cfg {String} trigger click || hover (or false to trigger manually)
14543 * @cfg {String} over what (parent or false to trigger manually.)
14544 * @cfg {Number} delay - delay before showing
14547 * Create a new Popover
14548 * @param {Object} config The config object
14551 Roo.bootstrap.Popover = function(config){
14552 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14555 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14557 title: 'Fill in a title',
14560 placement : 'right',
14561 trigger : 'hover', // hover
14567 can_build_overlaid : false,
14569 getChildContainer : function()
14571 return this.el.select('.popover-content',true).first();
14574 getAutoCreate : function(){
14575 Roo.log('make popover?');
14577 cls : 'popover roo-dynamic',
14578 style: 'display:block',
14584 cls : 'popover-inner',
14588 cls: 'popover-title',
14592 cls : 'popover-content',
14603 setTitle: function(str)
14605 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14607 setContent: function(str)
14609 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14611 // as it get's added to the bottom of the page.
14612 onRender : function(ct, position)
14614 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14616 var cfg = Roo.apply({}, this.getAutoCreate());
14620 cfg.cls += ' ' + this.cls;
14623 cfg.style = this.style;
14625 Roo.log("adding to ")
14626 this.el = Roo.get(document.body).createChild(cfg, position);
14632 initEvents : function()
14634 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14635 this.el.enableDisplayMode('block');
14637 if (this.over === false) {
14640 if (this.triggers === false) {
14643 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14644 var triggers = this.trigger ? this.trigger.split(' ') : [];
14645 Roo.each(triggers, function(trigger) {
14647 if (trigger == 'click') {
14648 on_el.on('click', this.toggle, this);
14649 } else if (trigger != 'manual') {
14650 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14651 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14653 on_el.on(eventIn ,this.enter, this);
14654 on_el.on(eventOut, this.leave, this);
14665 toggle : function () {
14666 this.hoverState == 'in' ? this.leave() : this.enter();
14669 enter : function () {
14672 clearTimeout(this.timeout);
14674 this.hoverState = 'in';
14676 if (!this.delay || !this.delay.show) {
14681 this.timeout = setTimeout(function () {
14682 if (_t.hoverState == 'in') {
14685 }, this.delay.show)
14687 leave : function() {
14688 clearTimeout(this.timeout);
14690 this.hoverState = 'out';
14692 if (!this.delay || !this.delay.hide) {
14697 this.timeout = setTimeout(function () {
14698 if (_t.hoverState == 'out') {
14701 }, this.delay.hide)
14704 show : function (on_el)
14707 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14710 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14711 if (this.html !== false) {
14712 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14714 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14715 if (!this.title.length) {
14716 this.el.select('.popover-title',true).hide();
14719 var placement = typeof this.placement == 'function' ?
14720 this.placement.call(this, this.el, on_el) :
14723 var autoToken = /\s?auto?\s?/i;
14724 var autoPlace = autoToken.test(placement);
14726 placement = placement.replace(autoToken, '') || 'top';
14730 //this.el.setXY([0,0]);
14732 this.el.dom.style.display='block';
14733 this.el.addClass(placement);
14735 //this.el.appendTo(on_el);
14737 var p = this.getPosition();
14738 var box = this.el.getBox();
14743 var align = Roo.bootstrap.Popover.alignment[placement];
14744 this.el.alignTo(on_el, align[0],align[1]);
14745 //var arrow = this.el.select('.arrow',true).first();
14746 //arrow.set(align[2],
14748 this.el.addClass('in');
14749 this.hoverState = null;
14751 if (this.el.hasClass('fade')) {
14758 this.el.setXY([0,0]);
14759 this.el.removeClass('in');
14766 Roo.bootstrap.Popover.alignment = {
14767 'left' : ['r-l', [-10,0], 'right'],
14768 'right' : ['l-r', [10,0], 'left'],
14769 'bottom' : ['t-b', [0,10], 'top'],
14770 'top' : [ 'b-t', [0,-10], 'bottom']
14781 * @class Roo.bootstrap.Progress
14782 * @extends Roo.bootstrap.Component
14783 * Bootstrap Progress class
14784 * @cfg {Boolean} striped striped of the progress bar
14785 * @cfg {Boolean} active animated of the progress bar
14789 * Create a new Progress
14790 * @param {Object} config The config object
14793 Roo.bootstrap.Progress = function(config){
14794 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14797 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14802 getAutoCreate : function(){
14810 cfg.cls += ' progress-striped';
14814 cfg.cls += ' active';
14833 * @class Roo.bootstrap.ProgressBar
14834 * @extends Roo.bootstrap.Component
14835 * Bootstrap ProgressBar class
14836 * @cfg {Number} aria_valuenow aria-value now
14837 * @cfg {Number} aria_valuemin aria-value min
14838 * @cfg {Number} aria_valuemax aria-value max
14839 * @cfg {String} label label for the progress bar
14840 * @cfg {String} panel (success | info | warning | danger )
14841 * @cfg {String} role role of the progress bar
14842 * @cfg {String} sr_only text
14846 * Create a new ProgressBar
14847 * @param {Object} config The config object
14850 Roo.bootstrap.ProgressBar = function(config){
14851 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14854 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14858 aria_valuemax : 100,
14864 getAutoCreate : function()
14869 cls: 'progress-bar',
14870 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14882 cfg.role = this.role;
14885 if(this.aria_valuenow){
14886 cfg['aria-valuenow'] = this.aria_valuenow;
14889 if(this.aria_valuemin){
14890 cfg['aria-valuemin'] = this.aria_valuemin;
14893 if(this.aria_valuemax){
14894 cfg['aria-valuemax'] = this.aria_valuemax;
14897 if(this.label && !this.sr_only){
14898 cfg.html = this.label;
14902 cfg.cls += ' progress-bar-' + this.panel;
14908 update : function(aria_valuenow)
14910 this.aria_valuenow = aria_valuenow;
14912 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14927 * @class Roo.bootstrap.TabGroup
14928 * @extends Roo.bootstrap.Column
14929 * Bootstrap Column class
14930 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14931 * @cfg {Boolean} carousel true to make the group behave like a carousel
14932 * @cfg {Number} bullets show the panel pointer.. default 0
14933 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14934 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14935 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14938 * Create a new TabGroup
14939 * @param {Object} config The config object
14942 Roo.bootstrap.TabGroup = function(config){
14943 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14945 this.navId = Roo.id();
14948 Roo.bootstrap.TabGroup.register(this);
14952 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14955 transition : false,
14960 slideOnTouch : false,
14962 getAutoCreate : function()
14964 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14966 cfg.cls += ' tab-content';
14968 Roo.log('get auto create...............');
14970 if (this.carousel) {
14971 cfg.cls += ' carousel slide';
14974 cls : 'carousel-inner'
14977 if(this.bullets > 0 && !Roo.isTouch){
14980 cls : 'carousel-bullets',
14984 if(this.bullets_cls){
14985 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14988 for (var i = 0; i < this.bullets; i++){
14990 cls : 'bullet bullet-' + i
14998 cfg.cn[0].cn = bullets;
15005 initEvents: function()
15007 Roo.log('-------- init events on tab group ---------');
15009 if(this.bullets > 0 && !Roo.isTouch){
15015 if(Roo.isTouch && this.slideOnTouch){
15016 this.el.on("touchstart", this.onTouchStart, this);
15019 if(this.autoslide){
15022 this.slideFn = window.setInterval(function() {
15023 _this.showPanelNext();
15029 onTouchStart : function(e, el, o)
15031 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15035 this.showPanelNext();
15038 getChildContainer : function()
15040 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15044 * register a Navigation item
15045 * @param {Roo.bootstrap.NavItem} the navitem to add
15047 register : function(item)
15049 this.tabs.push( item);
15050 item.navId = this.navId; // not really needed..
15054 getActivePanel : function()
15057 Roo.each(this.tabs, function(t) {
15067 getPanelByName : function(n)
15070 Roo.each(this.tabs, function(t) {
15071 if (t.tabId == n) {
15079 indexOfPanel : function(p)
15082 Roo.each(this.tabs, function(t,i) {
15083 if (t.tabId == p.tabId) {
15092 * show a specific panel
15093 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15094 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15096 showPanel : function (pan)
15098 if(this.transition){
15099 Roo.log("waiting for the transitionend");
15103 if (typeof(pan) == 'number') {
15104 pan = this.tabs[pan];
15106 if (typeof(pan) == 'string') {
15107 pan = this.getPanelByName(pan);
15109 if (pan.tabId == this.getActivePanel().tabId) {
15112 var cur = this.getActivePanel();
15114 if (false === cur.fireEvent('beforedeactivate')) {
15118 if(this.bullets > 0 && !Roo.isTouch){
15119 this.setActiveBullet(this.indexOfPanel(pan));
15122 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15124 this.transition = true;
15125 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15126 var lr = dir == 'next' ? 'left' : 'right';
15127 pan.el.addClass(dir); // or prev
15128 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15129 cur.el.addClass(lr); // or right
15130 pan.el.addClass(lr);
15133 cur.el.on('transitionend', function() {
15134 Roo.log("trans end?");
15136 pan.el.removeClass([lr,dir]);
15137 pan.setActive(true);
15139 cur.el.removeClass([lr]);
15140 cur.setActive(false);
15142 _this.transition = false;
15144 }, this, { single: true } );
15149 cur.setActive(false);
15150 pan.setActive(true);
15155 showPanelNext : function()
15157 var i = this.indexOfPanel(this.getActivePanel());
15159 if (i >= this.tabs.length - 1 && !this.autoslide) {
15163 if (i >= this.tabs.length - 1 && this.autoslide) {
15167 this.showPanel(this.tabs[i+1]);
15170 showPanelPrev : function()
15172 var i = this.indexOfPanel(this.getActivePanel());
15174 if (i < 1 && !this.autoslide) {
15178 if (i < 1 && this.autoslide) {
15179 i = this.tabs.length;
15182 this.showPanel(this.tabs[i-1]);
15185 initBullet : function()
15193 for (var i = 0; i < this.bullets; i++){
15194 var bullet = this.el.select('.bullet-' + i, true).first();
15200 bullet.on('click', (function(e, el, o, ii, t){
15202 e.preventDefault();
15204 _this.showPanel(ii);
15206 if(_this.autoslide && _this.slideFn){
15207 clearInterval(_this.slideFn);
15208 _this.slideFn = window.setInterval(function() {
15209 _this.showPanelNext();
15213 }).createDelegate(this, [i, bullet], true));
15217 setActiveBullet : function(i)
15223 Roo.each(this.el.select('.bullet', true).elements, function(el){
15224 el.removeClass('selected');
15227 var bullet = this.el.select('.bullet-' + i, true).first();
15233 bullet.addClass('selected');
15244 Roo.apply(Roo.bootstrap.TabGroup, {
15248 * register a Navigation Group
15249 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15251 register : function(navgrp)
15253 this.groups[navgrp.navId] = navgrp;
15257 * fetch a Navigation Group based on the navigation ID
15258 * if one does not exist , it will get created.
15259 * @param {string} the navgroup to add
15260 * @returns {Roo.bootstrap.NavGroup} the navgroup
15262 get: function(navId) {
15263 if (typeof(this.groups[navId]) == 'undefined') {
15264 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15266 return this.groups[navId] ;
15281 * @class Roo.bootstrap.TabPanel
15282 * @extends Roo.bootstrap.Component
15283 * Bootstrap TabPanel class
15284 * @cfg {Boolean} active panel active
15285 * @cfg {String} html panel content
15286 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15287 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15291 * Create a new TabPanel
15292 * @param {Object} config The config object
15295 Roo.bootstrap.TabPanel = function(config){
15296 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15300 * Fires when the active status changes
15301 * @param {Roo.bootstrap.TabPanel} this
15302 * @param {Boolean} state the new state
15307 * @event beforedeactivate
15308 * Fires before a tab is de-activated - can be used to do validation on a form.
15309 * @param {Roo.bootstrap.TabPanel} this
15310 * @return {Boolean} false if there is an error
15313 'beforedeactivate': true
15316 this.tabId = this.tabId || Roo.id();
15320 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15327 getAutoCreate : function(){
15330 // item is needed for carousel - not sure if it has any effect otherwise
15331 cls: 'tab-pane item',
15332 html: this.html || ''
15336 cfg.cls += ' active';
15340 cfg.tabId = this.tabId;
15347 initEvents: function()
15349 Roo.log('-------- init events on tab panel ---------');
15351 var p = this.parent();
15352 this.navId = this.navId || p.navId;
15354 if (typeof(this.navId) != 'undefined') {
15355 // not really needed.. but just in case.. parent should be a NavGroup.
15356 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15357 Roo.log(['register', tg, this]);
15360 var i = tg.tabs.length - 1;
15362 if(this.active && tg.bullets > 0 && i < tg.bullets){
15363 tg.setActiveBullet(i);
15370 onRender : function(ct, position)
15372 // Roo.log("Call onRender: " + this.xtype);
15374 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15382 setActive: function(state)
15384 Roo.log("panel - set active " + this.tabId + "=" + state);
15386 this.active = state;
15388 this.el.removeClass('active');
15390 } else if (!this.el.hasClass('active')) {
15391 this.el.addClass('active');
15394 this.fireEvent('changed', this, state);
15411 * @class Roo.bootstrap.DateField
15412 * @extends Roo.bootstrap.Input
15413 * Bootstrap DateField class
15414 * @cfg {Number} weekStart default 0
15415 * @cfg {String} viewMode default empty, (months|years)
15416 * @cfg {String} minViewMode default empty, (months|years)
15417 * @cfg {Number} startDate default -Infinity
15418 * @cfg {Number} endDate default Infinity
15419 * @cfg {Boolean} todayHighlight default false
15420 * @cfg {Boolean} todayBtn default false
15421 * @cfg {Boolean} calendarWeeks default false
15422 * @cfg {Object} daysOfWeekDisabled default empty
15423 * @cfg {Boolean} singleMode default false (true | false)
15425 * @cfg {Boolean} keyboardNavigation default true
15426 * @cfg {String} language default en
15429 * Create a new DateField
15430 * @param {Object} config The config object
15433 Roo.bootstrap.DateField = function(config){
15434 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15438 * Fires when this field show.
15439 * @param {Roo.bootstrap.DateField} this
15440 * @param {Mixed} date The date value
15445 * Fires when this field hide.
15446 * @param {Roo.bootstrap.DateField} this
15447 * @param {Mixed} date The date value
15452 * Fires when select a date.
15453 * @param {Roo.bootstrap.DateField} this
15454 * @param {Mixed} date The date value
15460 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15463 * @cfg {String} format
15464 * The default date format string which can be overriden for localization support. The format must be
15465 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15469 * @cfg {String} altFormats
15470 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15471 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15473 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15481 todayHighlight : false,
15487 keyboardNavigation: true,
15489 calendarWeeks: false,
15491 startDate: -Infinity,
15495 daysOfWeekDisabled: [],
15499 singleMode : false,
15501 UTCDate: function()
15503 return new Date(Date.UTC.apply(Date, arguments));
15506 UTCToday: function()
15508 var today = new Date();
15509 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15512 getDate: function() {
15513 var d = this.getUTCDate();
15514 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15517 getUTCDate: function() {
15521 setDate: function(d) {
15522 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15525 setUTCDate: function(d) {
15527 this.setValue(this.formatDate(this.date));
15530 onRender: function(ct, position)
15533 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15535 this.language = this.language || 'en';
15536 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15537 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15539 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15540 this.format = this.format || 'm/d/y';
15541 this.isInline = false;
15542 this.isInput = true;
15543 this.component = this.el.select('.add-on', true).first() || false;
15544 this.component = (this.component && this.component.length === 0) ? false : this.component;
15545 this.hasInput = this.component && this.inputEL().length;
15547 if (typeof(this.minViewMode === 'string')) {
15548 switch (this.minViewMode) {
15550 this.minViewMode = 1;
15553 this.minViewMode = 2;
15556 this.minViewMode = 0;
15561 if (typeof(this.viewMode === 'string')) {
15562 switch (this.viewMode) {
15575 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15577 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15579 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15581 this.picker().on('mousedown', this.onMousedown, this);
15582 this.picker().on('click', this.onClick, this);
15584 this.picker().addClass('datepicker-dropdown');
15586 this.startViewMode = this.viewMode;
15588 if(this.singleMode){
15589 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15590 v.setVisibilityMode(Roo.Element.DISPLAY)
15594 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15595 v.setStyle('width', '189px');
15599 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15600 if(!this.calendarWeeks){
15605 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15606 v.attr('colspan', function(i, val){
15607 return parseInt(val) + 1;
15612 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15614 this.setStartDate(this.startDate);
15615 this.setEndDate(this.endDate);
15617 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15624 if(this.isInline) {
15629 picker : function()
15631 return this.pickerEl;
15632 // return this.el.select('.datepicker', true).first();
15635 fillDow: function()
15637 var dowCnt = this.weekStart;
15646 if(this.calendarWeeks){
15654 while (dowCnt < this.weekStart + 7) {
15658 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15662 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15665 fillMonths: function()
15668 var months = this.picker().select('>.datepicker-months td', true).first();
15670 months.dom.innerHTML = '';
15676 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15679 months.createChild(month);
15686 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;
15688 if (this.date < this.startDate) {
15689 this.viewDate = new Date(this.startDate);
15690 } else if (this.date > this.endDate) {
15691 this.viewDate = new Date(this.endDate);
15693 this.viewDate = new Date(this.date);
15701 var d = new Date(this.viewDate),
15702 year = d.getUTCFullYear(),
15703 month = d.getUTCMonth(),
15704 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15705 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15706 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15707 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15708 currentDate = this.date && this.date.valueOf(),
15709 today = this.UTCToday();
15711 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15713 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15715 // this.picker.select('>tfoot th.today').
15716 // .text(dates[this.language].today)
15717 // .toggle(this.todayBtn !== false);
15719 this.updateNavArrows();
15722 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15724 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15726 prevMonth.setUTCDate(day);
15728 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15730 var nextMonth = new Date(prevMonth);
15732 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15734 nextMonth = nextMonth.valueOf();
15736 var fillMonths = false;
15738 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15740 while(prevMonth.valueOf() < nextMonth) {
15743 if (prevMonth.getUTCDay() === this.weekStart) {
15745 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15753 if(this.calendarWeeks){
15754 // ISO 8601: First week contains first thursday.
15755 // ISO also states week starts on Monday, but we can be more abstract here.
15757 // Start of current week: based on weekstart/current date
15758 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15759 // Thursday of this week
15760 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15761 // First Thursday of year, year from thursday
15762 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15763 // Calendar week: ms between thursdays, div ms per day, div 7 days
15764 calWeek = (th - yth) / 864e5 / 7 + 1;
15766 fillMonths.cn.push({
15774 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15776 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15779 if (this.todayHighlight &&
15780 prevMonth.getUTCFullYear() == today.getFullYear() &&
15781 prevMonth.getUTCMonth() == today.getMonth() &&
15782 prevMonth.getUTCDate() == today.getDate()) {
15783 clsName += ' today';
15786 if (currentDate && prevMonth.valueOf() === currentDate) {
15787 clsName += ' active';
15790 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15791 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15792 clsName += ' disabled';
15795 fillMonths.cn.push({
15797 cls: 'day ' + clsName,
15798 html: prevMonth.getDate()
15801 prevMonth.setDate(prevMonth.getDate()+1);
15804 var currentYear = this.date && this.date.getUTCFullYear();
15805 var currentMonth = this.date && this.date.getUTCMonth();
15807 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15809 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15810 v.removeClass('active');
15812 if(currentYear === year && k === currentMonth){
15813 v.addClass('active');
15816 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15817 v.addClass('disabled');
15823 year = parseInt(year/10, 10) * 10;
15825 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15827 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15830 for (var i = -1; i < 11; i++) {
15831 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15833 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15841 showMode: function(dir)
15844 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15847 Roo.each(this.picker().select('>div',true).elements, function(v){
15848 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15851 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15856 if(this.isInline) return;
15858 this.picker().removeClass(['bottom', 'top']);
15860 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15862 * place to the top of element!
15866 this.picker().addClass('top');
15867 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15872 this.picker().addClass('bottom');
15874 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15877 parseDate : function(value)
15879 if(!value || value instanceof Date){
15882 var v = Date.parseDate(value, this.format);
15883 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15884 v = Date.parseDate(value, 'Y-m-d');
15886 if(!v && this.altFormats){
15887 if(!this.altFormatsArray){
15888 this.altFormatsArray = this.altFormats.split("|");
15890 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15891 v = Date.parseDate(value, this.altFormatsArray[i]);
15897 formatDate : function(date, fmt)
15899 return (!date || !(date instanceof Date)) ?
15900 date : date.dateFormat(fmt || this.format);
15903 onFocus : function()
15905 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15909 onBlur : function()
15911 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15913 var d = this.inputEl().getValue();
15922 this.picker().show();
15926 this.fireEvent('show', this, this.date);
15931 if(this.isInline) return;
15932 this.picker().hide();
15933 this.viewMode = this.startViewMode;
15936 this.fireEvent('hide', this, this.date);
15940 onMousedown: function(e)
15942 e.stopPropagation();
15943 e.preventDefault();
15948 Roo.bootstrap.DateField.superclass.keyup.call(this);
15952 setValue: function(v)
15955 // v can be a string or a date..
15958 var d = new Date(this.parseDate(v) ).clearTime();
15960 if(isNaN(d.getTime())){
15961 this.date = this.viewDate = '';
15962 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15966 v = this.formatDate(d);
15968 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15970 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15974 this.fireEvent('select', this, this.date);
15978 getValue: function()
15980 return this.formatDate(this.date);
15983 fireKey: function(e)
15985 if (!this.picker().isVisible()){
15986 if (e.keyCode == 27) // allow escape to hide and re-show picker
15991 var dateChanged = false,
15993 newDate, newViewDate;
15998 e.preventDefault();
16002 if (!this.keyboardNavigation) break;
16003 dir = e.keyCode == 37 ? -1 : 1;
16006 newDate = this.moveYear(this.date, dir);
16007 newViewDate = this.moveYear(this.viewDate, dir);
16008 } else if (e.shiftKey){
16009 newDate = this.moveMonth(this.date, dir);
16010 newViewDate = this.moveMonth(this.viewDate, dir);
16012 newDate = new Date(this.date);
16013 newDate.setUTCDate(this.date.getUTCDate() + dir);
16014 newViewDate = new Date(this.viewDate);
16015 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16017 if (this.dateWithinRange(newDate)){
16018 this.date = newDate;
16019 this.viewDate = newViewDate;
16020 this.setValue(this.formatDate(this.date));
16022 e.preventDefault();
16023 dateChanged = true;
16028 if (!this.keyboardNavigation) break;
16029 dir = e.keyCode == 38 ? -1 : 1;
16031 newDate = this.moveYear(this.date, dir);
16032 newViewDate = this.moveYear(this.viewDate, dir);
16033 } else if (e.shiftKey){
16034 newDate = this.moveMonth(this.date, dir);
16035 newViewDate = this.moveMonth(this.viewDate, dir);
16037 newDate = new Date(this.date);
16038 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16039 newViewDate = new Date(this.viewDate);
16040 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16042 if (this.dateWithinRange(newDate)){
16043 this.date = newDate;
16044 this.viewDate = newViewDate;
16045 this.setValue(this.formatDate(this.date));
16047 e.preventDefault();
16048 dateChanged = true;
16052 this.setValue(this.formatDate(this.date));
16054 e.preventDefault();
16057 this.setValue(this.formatDate(this.date));
16071 onClick: function(e)
16073 e.stopPropagation();
16074 e.preventDefault();
16076 var target = e.getTarget();
16078 if(target.nodeName.toLowerCase() === 'i'){
16079 target = Roo.get(target).dom.parentNode;
16082 var nodeName = target.nodeName;
16083 var className = target.className;
16084 var html = target.innerHTML;
16085 //Roo.log(nodeName);
16087 switch(nodeName.toLowerCase()) {
16089 switch(className) {
16095 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16096 switch(this.viewMode){
16098 this.viewDate = this.moveMonth(this.viewDate, dir);
16102 this.viewDate = this.moveYear(this.viewDate, dir);
16108 var date = new Date();
16109 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16111 this.setValue(this.formatDate(this.date));
16118 if (className.indexOf('disabled') < 0) {
16119 this.viewDate.setUTCDate(1);
16120 if (className.indexOf('month') > -1) {
16121 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16123 var year = parseInt(html, 10) || 0;
16124 this.viewDate.setUTCFullYear(year);
16128 if(this.singleMode){
16129 this.setValue(this.formatDate(this.viewDate));
16140 //Roo.log(className);
16141 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16142 var day = parseInt(html, 10) || 1;
16143 var year = this.viewDate.getUTCFullYear(),
16144 month = this.viewDate.getUTCMonth();
16146 if (className.indexOf('old') > -1) {
16153 } else if (className.indexOf('new') > -1) {
16161 //Roo.log([year,month,day]);
16162 this.date = this.UTCDate(year, month, day,0,0,0,0);
16163 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16165 //Roo.log(this.formatDate(this.date));
16166 this.setValue(this.formatDate(this.date));
16173 setStartDate: function(startDate)
16175 this.startDate = startDate || -Infinity;
16176 if (this.startDate !== -Infinity) {
16177 this.startDate = this.parseDate(this.startDate);
16180 this.updateNavArrows();
16183 setEndDate: function(endDate)
16185 this.endDate = endDate || Infinity;
16186 if (this.endDate !== Infinity) {
16187 this.endDate = this.parseDate(this.endDate);
16190 this.updateNavArrows();
16193 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16195 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16196 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16197 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16199 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16200 return parseInt(d, 10);
16203 this.updateNavArrows();
16206 updateNavArrows: function()
16208 if(this.singleMode){
16212 var d = new Date(this.viewDate),
16213 year = d.getUTCFullYear(),
16214 month = d.getUTCMonth();
16216 Roo.each(this.picker().select('.prev', true).elements, function(v){
16218 switch (this.viewMode) {
16221 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16227 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16234 Roo.each(this.picker().select('.next', true).elements, function(v){
16236 switch (this.viewMode) {
16239 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16245 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16253 moveMonth: function(date, dir)
16255 if (!dir) return date;
16256 var new_date = new Date(date.valueOf()),
16257 day = new_date.getUTCDate(),
16258 month = new_date.getUTCMonth(),
16259 mag = Math.abs(dir),
16261 dir = dir > 0 ? 1 : -1;
16264 // If going back one month, make sure month is not current month
16265 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16267 return new_date.getUTCMonth() == month;
16269 // If going forward one month, make sure month is as expected
16270 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16272 return new_date.getUTCMonth() != new_month;
16274 new_month = month + dir;
16275 new_date.setUTCMonth(new_month);
16276 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16277 if (new_month < 0 || new_month > 11)
16278 new_month = (new_month + 12) % 12;
16280 // For magnitudes >1, move one month at a time...
16281 for (var i=0; i<mag; i++)
16282 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16283 new_date = this.moveMonth(new_date, dir);
16284 // ...then reset the day, keeping it in the new month
16285 new_month = new_date.getUTCMonth();
16286 new_date.setUTCDate(day);
16288 return new_month != new_date.getUTCMonth();
16291 // Common date-resetting loop -- if date is beyond end of month, make it
16294 new_date.setUTCDate(--day);
16295 new_date.setUTCMonth(new_month);
16300 moveYear: function(date, dir)
16302 return this.moveMonth(date, dir*12);
16305 dateWithinRange: function(date)
16307 return date >= this.startDate && date <= this.endDate;
16313 this.picker().remove();
16318 Roo.apply(Roo.bootstrap.DateField, {
16329 html: '<i class="fa fa-arrow-left"/>'
16339 html: '<i class="fa fa-arrow-right"/>'
16381 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16382 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16383 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16384 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16385 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16398 navFnc: 'FullYear',
16403 navFnc: 'FullYear',
16408 Roo.apply(Roo.bootstrap.DateField, {
16412 cls: 'datepicker dropdown-menu roo-dynamic',
16416 cls: 'datepicker-days',
16420 cls: 'table-condensed',
16422 Roo.bootstrap.DateField.head,
16426 Roo.bootstrap.DateField.footer
16433 cls: 'datepicker-months',
16437 cls: 'table-condensed',
16439 Roo.bootstrap.DateField.head,
16440 Roo.bootstrap.DateField.content,
16441 Roo.bootstrap.DateField.footer
16448 cls: 'datepicker-years',
16452 cls: 'table-condensed',
16454 Roo.bootstrap.DateField.head,
16455 Roo.bootstrap.DateField.content,
16456 Roo.bootstrap.DateField.footer
16475 * @class Roo.bootstrap.TimeField
16476 * @extends Roo.bootstrap.Input
16477 * Bootstrap DateField class
16481 * Create a new TimeField
16482 * @param {Object} config The config object
16485 Roo.bootstrap.TimeField = function(config){
16486 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16490 * Fires when this field show.
16491 * @param {Roo.bootstrap.DateField} thisthis
16492 * @param {Mixed} date The date value
16497 * Fires when this field hide.
16498 * @param {Roo.bootstrap.DateField} this
16499 * @param {Mixed} date The date value
16504 * Fires when select a date.
16505 * @param {Roo.bootstrap.DateField} this
16506 * @param {Mixed} date The date value
16512 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16515 * @cfg {String} format
16516 * The default time format string which can be overriden for localization support. The format must be
16517 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16521 onRender: function(ct, position)
16524 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16526 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16528 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16530 this.pop = this.picker().select('>.datepicker-time',true).first();
16531 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16533 this.picker().on('mousedown', this.onMousedown, this);
16534 this.picker().on('click', this.onClick, this);
16536 this.picker().addClass('datepicker-dropdown');
16541 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16542 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16543 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16544 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16545 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16546 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16550 fireKey: function(e){
16551 if (!this.picker().isVisible()){
16552 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16558 e.preventDefault();
16566 this.onTogglePeriod();
16569 this.onIncrementMinutes();
16572 this.onDecrementMinutes();
16581 onClick: function(e) {
16582 e.stopPropagation();
16583 e.preventDefault();
16586 picker : function()
16588 return this.el.select('.datepicker', true).first();
16591 fillTime: function()
16593 var time = this.pop.select('tbody', true).first();
16595 time.dom.innerHTML = '';
16610 cls: 'hours-up glyphicon glyphicon-chevron-up'
16630 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16651 cls: 'timepicker-hour',
16666 cls: 'timepicker-minute',
16681 cls: 'btn btn-primary period',
16703 cls: 'hours-down glyphicon glyphicon-chevron-down'
16723 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16741 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16748 var hours = this.time.getHours();
16749 var minutes = this.time.getMinutes();
16762 hours = hours - 12;
16766 hours = '0' + hours;
16770 minutes = '0' + minutes;
16773 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16774 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16775 this.pop.select('button', true).first().dom.innerHTML = period;
16781 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16783 var cls = ['bottom'];
16785 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16792 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16797 this.picker().addClass(cls.join('-'));
16801 Roo.each(cls, function(c){
16803 _this.picker().setTop(_this.inputEl().getHeight());
16807 _this.picker().setTop(0 - _this.picker().getHeight());
16812 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16816 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16823 onFocus : function()
16825 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16829 onBlur : function()
16831 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16837 this.picker().show();
16842 this.fireEvent('show', this, this.date);
16847 this.picker().hide();
16850 this.fireEvent('hide', this, this.date);
16853 setTime : function()
16856 this.setValue(this.time.format(this.format));
16858 this.fireEvent('select', this, this.date);
16863 onMousedown: function(e){
16864 e.stopPropagation();
16865 e.preventDefault();
16868 onIncrementHours: function()
16870 Roo.log('onIncrementHours');
16871 this.time = this.time.add(Date.HOUR, 1);
16876 onDecrementHours: function()
16878 Roo.log('onDecrementHours');
16879 this.time = this.time.add(Date.HOUR, -1);
16883 onIncrementMinutes: function()
16885 Roo.log('onIncrementMinutes');
16886 this.time = this.time.add(Date.MINUTE, 1);
16890 onDecrementMinutes: function()
16892 Roo.log('onDecrementMinutes');
16893 this.time = this.time.add(Date.MINUTE, -1);
16897 onTogglePeriod: function()
16899 Roo.log('onTogglePeriod');
16900 this.time = this.time.add(Date.HOUR, 12);
16907 Roo.apply(Roo.bootstrap.TimeField, {
16937 cls: 'btn btn-info ok',
16949 Roo.apply(Roo.bootstrap.TimeField, {
16953 cls: 'datepicker dropdown-menu',
16957 cls: 'datepicker-time',
16961 cls: 'table-condensed',
16963 Roo.bootstrap.TimeField.content,
16964 Roo.bootstrap.TimeField.footer
16983 * @class Roo.bootstrap.MonthField
16984 * @extends Roo.bootstrap.Input
16985 * Bootstrap MonthField class
16987 * @cfg {String} language default en
16990 * Create a new MonthField
16991 * @param {Object} config The config object
16994 Roo.bootstrap.MonthField = function(config){
16995 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
17000 * Fires when this field show.
17001 * @param {Roo.bootstrap.MonthField} this
17002 * @param {Mixed} date The date value
17007 * Fires when this field hide.
17008 * @param {Roo.bootstrap.MonthField} this
17009 * @param {Mixed} date The date value
17014 * Fires when select a date.
17015 * @param {Roo.bootstrap.MonthField} this
17016 * @param {String} oldvalue The old value
17017 * @param {String} newvalue The new value
17023 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17025 onRender: function(ct, position)
17028 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17030 this.language = this.language || 'en';
17031 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17032 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17034 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17035 this.isInline = false;
17036 this.isInput = true;
17037 this.component = this.el.select('.add-on', true).first() || false;
17038 this.component = (this.component && this.component.length === 0) ? false : this.component;
17039 this.hasInput = this.component && this.inputEL().length;
17041 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17043 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17045 this.picker().on('mousedown', this.onMousedown, this);
17046 this.picker().on('click', this.onClick, this);
17048 this.picker().addClass('datepicker-dropdown');
17050 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17051 v.setStyle('width', '189px');
17058 if(this.isInline) {
17064 setValue: function(v, suppressEvent)
17066 var o = this.getValue();
17068 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17072 if(suppressEvent !== true){
17073 this.fireEvent('select', this, o, v);
17078 getValue: function()
17083 onClick: function(e)
17085 e.stopPropagation();
17086 e.preventDefault();
17088 var target = e.getTarget();
17090 if(target.nodeName.toLowerCase() === 'i'){
17091 target = Roo.get(target).dom.parentNode;
17094 var nodeName = target.nodeName;
17095 var className = target.className;
17096 var html = target.innerHTML;
17098 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17102 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17104 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17110 picker : function()
17112 return this.pickerEl;
17115 fillMonths: function()
17118 var months = this.picker().select('>.datepicker-months td', true).first();
17120 months.dom.innerHTML = '';
17126 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17129 months.createChild(month);
17138 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17139 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17142 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17143 e.removeClass('active');
17145 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17146 e.addClass('active');
17153 if(this.isInline) return;
17155 this.picker().removeClass(['bottom', 'top']);
17157 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17159 * place to the top of element!
17163 this.picker().addClass('top');
17164 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17169 this.picker().addClass('bottom');
17171 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17174 onFocus : function()
17176 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17180 onBlur : function()
17182 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17184 var d = this.inputEl().getValue();
17193 this.picker().show();
17194 this.picker().select('>.datepicker-months', true).first().show();
17198 this.fireEvent('show', this, this.date);
17203 if(this.isInline) return;
17204 this.picker().hide();
17205 this.fireEvent('hide', this, this.date);
17209 onMousedown: function(e)
17211 e.stopPropagation();
17212 e.preventDefault();
17217 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17221 fireKey: function(e)
17223 if (!this.picker().isVisible()){
17224 if (e.keyCode == 27) // allow escape to hide and re-show picker
17234 e.preventDefault();
17238 dir = e.keyCode == 37 ? -1 : 1;
17240 this.vIndex = this.vIndex + dir;
17242 if(this.vIndex < 0){
17246 if(this.vIndex > 11){
17250 if(isNaN(this.vIndex)){
17254 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17260 dir = e.keyCode == 38 ? -1 : 1;
17262 this.vIndex = this.vIndex + dir * 4;
17264 if(this.vIndex < 0){
17268 if(this.vIndex > 11){
17272 if(isNaN(this.vIndex)){
17276 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17281 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17282 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17286 e.preventDefault();
17289 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17290 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17306 this.picker().remove();
17311 Roo.apply(Roo.bootstrap.MonthField, {
17330 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17331 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17336 Roo.apply(Roo.bootstrap.MonthField, {
17340 cls: 'datepicker dropdown-menu roo-dynamic',
17344 cls: 'datepicker-months',
17348 cls: 'table-condensed',
17350 Roo.bootstrap.DateField.content
17370 * @class Roo.bootstrap.CheckBox
17371 * @extends Roo.bootstrap.Input
17372 * Bootstrap CheckBox class
17374 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17375 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17376 * @cfg {String} boxLabel The text that appears beside the checkbox
17377 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17378 * @cfg {Boolean} checked initnal the element
17379 * @cfg {Boolean} inline inline the element (default false)
17380 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17383 * Create a new CheckBox
17384 * @param {Object} config The config object
17387 Roo.bootstrap.CheckBox = function(config){
17388 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17393 * Fires when the element is checked or unchecked.
17394 * @param {Roo.bootstrap.CheckBox} this This input
17395 * @param {Boolean} checked The new checked value
17402 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17404 inputType: 'checkbox',
17412 getAutoCreate : function()
17414 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17420 cfg.cls = 'form-group ' + this.inputType; //input-group
17423 cfg.cls += ' ' + this.inputType + '-inline';
17429 type : this.inputType,
17430 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17431 cls : 'roo-' + this.inputType, //'form-box',
17432 placeholder : this.placeholder || ''
17436 if (this.weight) { // Validity check?
17437 cfg.cls += " " + this.inputType + "-" + this.weight;
17440 if (this.disabled) {
17441 input.disabled=true;
17445 input.checked = this.checked;
17449 input.name = this.name;
17453 input.cls += ' input-' + this.size;
17458 ['xs','sm','md','lg'].map(function(size){
17459 if (settings[size]) {
17460 cfg.cls += ' col-' + size + '-' + settings[size];
17464 var inputblock = input;
17466 if (this.before || this.after) {
17469 cls : 'input-group',
17474 inputblock.cn.push({
17476 cls : 'input-group-addon',
17481 inputblock.cn.push(input);
17484 inputblock.cn.push({
17486 cls : 'input-group-addon',
17493 if (align ==='left' && this.fieldLabel.length) {
17494 Roo.log("left and has label");
17500 cls : 'control-label col-md-' + this.labelWidth,
17501 html : this.fieldLabel
17505 cls : "col-md-" + (12 - this.labelWidth),
17512 } else if ( this.fieldLabel.length) {
17517 tag: this.boxLabel ? 'span' : 'label',
17519 cls: 'control-label box-input-label',
17520 //cls : 'input-group-addon',
17521 html : this.fieldLabel
17531 Roo.log(" no label && no align");
17532 cfg.cn = [ inputblock ] ;
17537 var boxLabelCfg = {
17539 //'for': id, // box label is handled by onclick - so no for...
17541 html: this.boxLabel
17545 boxLabelCfg.tooltip = this.tooltip;
17548 cfg.cn.push(boxLabelCfg);
17558 * return the real input element.
17560 inputEl: function ()
17562 return this.el.select('input.roo-' + this.inputType,true).first();
17565 labelEl: function()
17567 return this.el.select('label.control-label',true).first();
17569 /* depricated... */
17573 return this.labelEl();
17576 initEvents : function()
17578 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17580 this.inputEl().on('click', this.onClick, this);
17582 if (this.boxLabel) {
17583 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17586 this.startValue = this.getValue();
17589 Roo.bootstrap.CheckBox.register(this);
17593 onClick : function()
17595 this.setChecked(!this.checked);
17598 setChecked : function(state,suppressEvent)
17600 this.startValue = this.getValue();
17602 if(this.inputType == 'radio'){
17604 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17605 e.dom.checked = false;
17608 this.inputEl().dom.checked = true;
17610 this.inputEl().dom.value = this.inputValue;
17612 if(suppressEvent !== true){
17613 this.fireEvent('check', this, true);
17621 this.checked = state;
17623 this.inputEl().dom.checked = state;
17625 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17627 if(suppressEvent !== true){
17628 this.fireEvent('check', this, state);
17634 getValue : function()
17636 if(this.inputType == 'radio'){
17637 return this.getGroupValue();
17640 return this.inputEl().getValue();
17644 getGroupValue : function()
17646 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17650 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17653 setValue : function(v,suppressEvent)
17655 if(this.inputType == 'radio'){
17656 this.setGroupValue(v, suppressEvent);
17660 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17665 setGroupValue : function(v, suppressEvent)
17667 this.startValue = this.getValue();
17669 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17670 e.dom.checked = false;
17672 if(e.dom.value == v){
17673 e.dom.checked = true;
17677 if(suppressEvent !== true){
17678 this.fireEvent('check', this, true);
17686 validate : function()
17690 (this.inputType == 'radio' && this.validateRadio()) ||
17691 (this.inputType == 'checkbox' && this.validateCheckbox())
17697 this.markInvalid();
17701 validateRadio : function()
17705 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17706 if(!e.dom.checked){
17718 validateCheckbox : function()
17721 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17724 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17732 for(var i in group){
17737 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17744 * Mark this field as valid
17746 markValid : function()
17748 if(this.allowBlank){
17754 this.fireEvent('valid', this);
17756 if(this.inputType == 'radio'){
17757 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17758 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17759 e.findParent('.form-group', false, true).addClass(_this.validClass);
17766 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17767 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17771 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17777 for(var i in group){
17778 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17779 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17784 * Mark this field as invalid
17785 * @param {String} msg The validation message
17787 markInvalid : function(msg)
17789 if(this.allowBlank){
17795 this.fireEvent('invalid', this, msg);
17797 if(this.inputType == 'radio'){
17798 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17799 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17800 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17807 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17808 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17812 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17818 for(var i in group){
17819 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17820 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17827 Roo.apply(Roo.bootstrap.CheckBox, {
17832 * register a CheckBox Group
17833 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17835 register : function(checkbox)
17837 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17838 this.groups[checkbox.groupId] = {};
17841 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17845 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17849 * fetch a CheckBox Group based on the group ID
17850 * @param {string} the group ID
17851 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17853 get: function(groupId) {
17854 if (typeof(this.groups[groupId]) == 'undefined') {
17858 return this.groups[groupId] ;
17870 *<div class="radio">
17872 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17873 Option one is this and that—be sure to include why it's great
17880 *<label class="radio-inline">fieldLabel</label>
17881 *<label class="radio-inline">
17882 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17890 * @class Roo.bootstrap.Radio
17891 * @extends Roo.bootstrap.CheckBox
17892 * Bootstrap Radio class
17895 * Create a new Radio
17896 * @param {Object} config The config object
17899 Roo.bootstrap.Radio = function(config){
17900 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17904 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17906 inputType: 'radio',
17910 getAutoCreate : function()
17912 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17913 align = align || 'left'; // default...
17920 tag : this.inline ? 'span' : 'div',
17925 var inline = this.inline ? ' radio-inline' : '';
17929 // does not need for, as we wrap the input with it..
17931 cls : 'control-label box-label' + inline,
17934 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17938 //cls : 'control-label' + inline,
17939 html : this.fieldLabel,
17940 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17949 type : this.inputType,
17950 //value : (!this.checked) ? this.valueOff : this.inputValue,
17951 value : this.inputValue,
17953 placeholder : this.placeholder || '' // ?? needed????
17956 if (this.weight) { // Validity check?
17957 input.cls += " radio-" + this.weight;
17959 if (this.disabled) {
17960 input.disabled=true;
17964 input.checked = this.checked;
17968 input.name = this.name;
17972 input.cls += ' input-' + this.size;
17975 //?? can span's inline have a width??
17978 ['xs','sm','md','lg'].map(function(size){
17979 if (settings[size]) {
17980 cfg.cls += ' col-' + size + '-' + settings[size];
17984 var inputblock = input;
17986 if (this.before || this.after) {
17989 cls : 'input-group',
17994 inputblock.cn.push({
17996 cls : 'input-group-addon',
18000 inputblock.cn.push(input);
18002 inputblock.cn.push({
18004 cls : 'input-group-addon',
18012 if (this.fieldLabel && this.fieldLabel.length) {
18013 cfg.cn.push(fieldLabel);
18016 // normal bootstrap puts the input inside the label.
18017 // however with our styled version - it has to go after the input.
18019 //lbl.cn.push(inputblock);
18023 cls: 'radio' + inline,
18030 cfg.cn.push( lblwrap);
18035 html: this.boxLabel
18044 initEvents : function()
18046 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18048 this.inputEl().on('click', this.onClick, this);
18049 if (this.boxLabel) {
18050 Roo.log('find label')
18051 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18056 inputEl: function ()
18058 return this.el.select('input.roo-radio',true).first();
18060 onClick : function()
18063 this.setChecked(true);
18066 setChecked : function(state,suppressEvent)
18069 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18070 v.dom.checked = false;
18073 Roo.log(this.inputEl().dom);
18074 this.checked = state;
18075 this.inputEl().dom.checked = state;
18077 if(suppressEvent !== true){
18078 this.fireEvent('check', this, state);
18081 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18085 getGroupValue : function()
18088 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18089 if(v.dom.checked == true){
18090 value = v.dom.value;
18098 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18099 * @return {Mixed} value The field value
18101 getValue : function(){
18102 return this.getGroupValue();
18108 //<script type="text/javascript">
18111 * Based Ext JS Library 1.1.1
18112 * Copyright(c) 2006-2007, Ext JS, LLC.
18118 * @class Roo.HtmlEditorCore
18119 * @extends Roo.Component
18120 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18122 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18125 Roo.HtmlEditorCore = function(config){
18128 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18133 * @event initialize
18134 * Fires when the editor is fully initialized (including the iframe)
18135 * @param {Roo.HtmlEditorCore} this
18140 * Fires when the editor is first receives the focus. Any insertion must wait
18141 * until after this event.
18142 * @param {Roo.HtmlEditorCore} this
18146 * @event beforesync
18147 * Fires before the textarea is updated with content from the editor iframe. Return false
18148 * to cancel the sync.
18149 * @param {Roo.HtmlEditorCore} this
18150 * @param {String} html
18154 * @event beforepush
18155 * Fires before the iframe editor is updated with content from the textarea. Return false
18156 * to cancel the push.
18157 * @param {Roo.HtmlEditorCore} this
18158 * @param {String} html
18163 * Fires when the textarea is updated with content from the editor iframe.
18164 * @param {Roo.HtmlEditorCore} this
18165 * @param {String} html
18170 * Fires when the iframe editor is updated with content from the textarea.
18171 * @param {Roo.HtmlEditorCore} this
18172 * @param {String} html
18177 * @event editorevent
18178 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18179 * @param {Roo.HtmlEditorCore} this
18185 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18187 // defaults : white / black...
18188 this.applyBlacklists();
18195 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18199 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18205 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18210 * @cfg {Number} height (in pixels)
18214 * @cfg {Number} width (in pixels)
18219 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18222 stylesheets: false,
18227 // private properties
18228 validationEvent : false,
18230 initialized : false,
18232 sourceEditMode : false,
18233 onFocus : Roo.emptyFn,
18235 hideMode:'offsets',
18239 // blacklist + whitelisted elements..
18246 * Protected method that will not generally be called directly. It
18247 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18248 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18250 getDocMarkup : function(){
18254 // inherit styels from page...??
18255 if (this.stylesheets === false) {
18257 Roo.get(document.head).select('style').each(function(node) {
18258 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18261 Roo.get(document.head).select('link').each(function(node) {
18262 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18265 } else if (!this.stylesheets.length) {
18267 st = '<style type="text/css">' +
18268 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18274 st += '<style type="text/css">' +
18275 'IMG { cursor: pointer } ' +
18279 return '<html><head>' + st +
18280 //<style type="text/css">' +
18281 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18283 ' </head><body class="roo-htmleditor-body"></body></html>';
18287 onRender : function(ct, position)
18290 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18291 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18294 this.el.dom.style.border = '0 none';
18295 this.el.dom.setAttribute('tabIndex', -1);
18296 this.el.addClass('x-hidden hide');
18300 if(Roo.isIE){ // fix IE 1px bogus margin
18301 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18305 this.frameId = Roo.id();
18309 var iframe = this.owner.wrap.createChild({
18311 cls: 'form-control', // bootstrap..
18313 name: this.frameId,
18314 frameBorder : 'no',
18315 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18320 this.iframe = iframe.dom;
18322 this.assignDocWin();
18324 this.doc.designMode = 'on';
18327 this.doc.write(this.getDocMarkup());
18331 var task = { // must defer to wait for browser to be ready
18333 //console.log("run task?" + this.doc.readyState);
18334 this.assignDocWin();
18335 if(this.doc.body || this.doc.readyState == 'complete'){
18337 this.doc.designMode="on";
18341 Roo.TaskMgr.stop(task);
18342 this.initEditor.defer(10, this);
18349 Roo.TaskMgr.start(task);
18354 onResize : function(w, h)
18356 Roo.log('resize: ' +w + ',' + h );
18357 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18361 if(typeof w == 'number'){
18363 this.iframe.style.width = w + 'px';
18365 if(typeof h == 'number'){
18367 this.iframe.style.height = h + 'px';
18369 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18376 * Toggles the editor between standard and source edit mode.
18377 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18379 toggleSourceEdit : function(sourceEditMode){
18381 this.sourceEditMode = sourceEditMode === true;
18383 if(this.sourceEditMode){
18385 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18388 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18389 //this.iframe.className = '';
18392 //this.setSize(this.owner.wrap.getSize());
18393 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18400 * Protected method that will not generally be called directly. If you need/want
18401 * custom HTML cleanup, this is the method you should override.
18402 * @param {String} html The HTML to be cleaned
18403 * return {String} The cleaned HTML
18405 cleanHtml : function(html){
18406 html = String(html);
18407 if(html.length > 5){
18408 if(Roo.isSafari){ // strip safari nonsense
18409 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18412 if(html == ' '){
18419 * HTML Editor -> Textarea
18420 * Protected method that will not generally be called directly. Syncs the contents
18421 * of the editor iframe with the textarea.
18423 syncValue : function(){
18424 if(this.initialized){
18425 var bd = (this.doc.body || this.doc.documentElement);
18426 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18427 var html = bd.innerHTML;
18429 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18430 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18432 html = '<div style="'+m[0]+'">' + html + '</div>';
18435 html = this.cleanHtml(html);
18436 // fix up the special chars.. normaly like back quotes in word...
18437 // however we do not want to do this with chinese..
18438 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18439 var cc = b.charCodeAt();
18441 (cc >= 0x4E00 && cc < 0xA000 ) ||
18442 (cc >= 0x3400 && cc < 0x4E00 ) ||
18443 (cc >= 0xf900 && cc < 0xfb00 )
18449 if(this.owner.fireEvent('beforesync', this, html) !== false){
18450 this.el.dom.value = html;
18451 this.owner.fireEvent('sync', this, html);
18457 * Protected method that will not generally be called directly. Pushes the value of the textarea
18458 * into the iframe editor.
18460 pushValue : function(){
18461 if(this.initialized){
18462 var v = this.el.dom.value.trim();
18464 // if(v.length < 1){
18468 if(this.owner.fireEvent('beforepush', this, v) !== false){
18469 var d = (this.doc.body || this.doc.documentElement);
18471 this.cleanUpPaste();
18472 this.el.dom.value = d.innerHTML;
18473 this.owner.fireEvent('push', this, v);
18479 deferFocus : function(){
18480 this.focus.defer(10, this);
18484 focus : function(){
18485 if(this.win && !this.sourceEditMode){
18492 assignDocWin: function()
18494 var iframe = this.iframe;
18497 this.doc = iframe.contentWindow.document;
18498 this.win = iframe.contentWindow;
18500 // if (!Roo.get(this.frameId)) {
18503 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18504 // this.win = Roo.get(this.frameId).dom.contentWindow;
18506 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18510 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18511 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18516 initEditor : function(){
18517 //console.log("INIT EDITOR");
18518 this.assignDocWin();
18522 this.doc.designMode="on";
18524 this.doc.write(this.getDocMarkup());
18527 var dbody = (this.doc.body || this.doc.documentElement);
18528 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18529 // this copies styles from the containing element into thsi one..
18530 // not sure why we need all of this..
18531 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18533 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18534 //ss['background-attachment'] = 'fixed'; // w3c
18535 dbody.bgProperties = 'fixed'; // ie
18536 //Roo.DomHelper.applyStyles(dbody, ss);
18537 Roo.EventManager.on(this.doc, {
18538 //'mousedown': this.onEditorEvent,
18539 'mouseup': this.onEditorEvent,
18540 'dblclick': this.onEditorEvent,
18541 'click': this.onEditorEvent,
18542 'keyup': this.onEditorEvent,
18547 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18549 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18550 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18552 this.initialized = true;
18554 this.owner.fireEvent('initialize', this);
18559 onDestroy : function(){
18565 //for (var i =0; i < this.toolbars.length;i++) {
18566 // // fixme - ask toolbars for heights?
18567 // this.toolbars[i].onDestroy();
18570 //this.wrap.dom.innerHTML = '';
18571 //this.wrap.remove();
18576 onFirstFocus : function(){
18578 this.assignDocWin();
18581 this.activated = true;
18584 if(Roo.isGecko){ // prevent silly gecko errors
18586 var s = this.win.getSelection();
18587 if(!s.focusNode || s.focusNode.nodeType != 3){
18588 var r = s.getRangeAt(0);
18589 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18594 this.execCmd('useCSS', true);
18595 this.execCmd('styleWithCSS', false);
18598 this.owner.fireEvent('activate', this);
18602 adjustFont: function(btn){
18603 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18604 //if(Roo.isSafari){ // safari
18607 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18608 if(Roo.isSafari){ // safari
18609 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18610 v = (v < 10) ? 10 : v;
18611 v = (v > 48) ? 48 : v;
18612 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18617 v = Math.max(1, v+adjust);
18619 this.execCmd('FontSize', v );
18622 onEditorEvent : function(e)
18624 this.owner.fireEvent('editorevent', this, e);
18625 // this.updateToolbar();
18626 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18629 insertTag : function(tg)
18631 // could be a bit smarter... -> wrap the current selected tRoo..
18632 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18634 range = this.createRange(this.getSelection());
18635 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18636 wrappingNode.appendChild(range.extractContents());
18637 range.insertNode(wrappingNode);
18644 this.execCmd("formatblock", tg);
18648 insertText : function(txt)
18652 var range = this.createRange();
18653 range.deleteContents();
18654 //alert(Sender.getAttribute('label'));
18656 range.insertNode(this.doc.createTextNode(txt));
18662 * Executes a Midas editor command on the editor document and performs necessary focus and
18663 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18664 * @param {String} cmd The Midas command
18665 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18667 relayCmd : function(cmd, value){
18669 this.execCmd(cmd, value);
18670 this.owner.fireEvent('editorevent', this);
18671 //this.updateToolbar();
18672 this.owner.deferFocus();
18676 * Executes a Midas editor command directly on the editor document.
18677 * For visual commands, you should use {@link #relayCmd} instead.
18678 * <b>This should only be called after the editor is initialized.</b>
18679 * @param {String} cmd The Midas command
18680 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18682 execCmd : function(cmd, value){
18683 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18690 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18692 * @param {String} text | dom node..
18694 insertAtCursor : function(text)
18699 if(!this.activated){
18705 var r = this.doc.selection.createRange();
18716 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18720 // from jquery ui (MIT licenced)
18722 var win = this.win;
18724 if (win.getSelection && win.getSelection().getRangeAt) {
18725 range = win.getSelection().getRangeAt(0);
18726 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18727 range.insertNode(node);
18728 } else if (win.document.selection && win.document.selection.createRange) {
18729 // no firefox support
18730 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18731 win.document.selection.createRange().pasteHTML(txt);
18733 // no firefox support
18734 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18735 this.execCmd('InsertHTML', txt);
18744 mozKeyPress : function(e){
18746 var c = e.getCharCode(), cmd;
18749 c = String.fromCharCode(c).toLowerCase();
18763 this.cleanUpPaste.defer(100, this);
18771 e.preventDefault();
18779 fixKeys : function(){ // load time branching for fastest keydown performance
18781 return function(e){
18782 var k = e.getKey(), r;
18785 r = this.doc.selection.createRange();
18788 r.pasteHTML('    ');
18795 r = this.doc.selection.createRange();
18797 var target = r.parentElement();
18798 if(!target || target.tagName.toLowerCase() != 'li'){
18800 r.pasteHTML('<br />');
18806 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18807 this.cleanUpPaste.defer(100, this);
18813 }else if(Roo.isOpera){
18814 return function(e){
18815 var k = e.getKey();
18819 this.execCmd('InsertHTML','    ');
18822 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18823 this.cleanUpPaste.defer(100, this);
18828 }else if(Roo.isSafari){
18829 return function(e){
18830 var k = e.getKey();
18834 this.execCmd('InsertText','\t');
18838 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18839 this.cleanUpPaste.defer(100, this);
18847 getAllAncestors: function()
18849 var p = this.getSelectedNode();
18852 a.push(p); // push blank onto stack..
18853 p = this.getParentElement();
18857 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18861 a.push(this.doc.body);
18865 lastSelNode : false,
18868 getSelection : function()
18870 this.assignDocWin();
18871 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18874 getSelectedNode: function()
18876 // this may only work on Gecko!!!
18878 // should we cache this!!!!
18883 var range = this.createRange(this.getSelection()).cloneRange();
18886 var parent = range.parentElement();
18888 var testRange = range.duplicate();
18889 testRange.moveToElementText(parent);
18890 if (testRange.inRange(range)) {
18893 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18896 parent = parent.parentElement;
18901 // is ancestor a text element.
18902 var ac = range.commonAncestorContainer;
18903 if (ac.nodeType == 3) {
18904 ac = ac.parentNode;
18907 var ar = ac.childNodes;
18910 var other_nodes = [];
18911 var has_other_nodes = false;
18912 for (var i=0;i<ar.length;i++) {
18913 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18916 // fullly contained node.
18918 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18923 // probably selected..
18924 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18925 other_nodes.push(ar[i]);
18929 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18934 has_other_nodes = true;
18936 if (!nodes.length && other_nodes.length) {
18937 nodes= other_nodes;
18939 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18945 createRange: function(sel)
18947 // this has strange effects when using with
18948 // top toolbar - not sure if it's a great idea.
18949 //this.editor.contentWindow.focus();
18950 if (typeof sel != "undefined") {
18952 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18954 return this.doc.createRange();
18957 return this.doc.createRange();
18960 getParentElement: function()
18963 this.assignDocWin();
18964 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18966 var range = this.createRange(sel);
18969 var p = range.commonAncestorContainer;
18970 while (p.nodeType == 3) { // text node
18981 * Range intersection.. the hard stuff...
18985 * [ -- selected range --- ]
18989 * if end is before start or hits it. fail.
18990 * if start is after end or hits it fail.
18992 * if either hits (but other is outside. - then it's not
18998 // @see http://www.thismuchiknow.co.uk/?p=64.
18999 rangeIntersectsNode : function(range, node)
19001 var nodeRange = node.ownerDocument.createRange();
19003 nodeRange.selectNode(node);
19005 nodeRange.selectNodeContents(node);
19008 var rangeStartRange = range.cloneRange();
19009 rangeStartRange.collapse(true);
19011 var rangeEndRange = range.cloneRange();
19012 rangeEndRange.collapse(false);
19014 var nodeStartRange = nodeRange.cloneRange();
19015 nodeStartRange.collapse(true);
19017 var nodeEndRange = nodeRange.cloneRange();
19018 nodeEndRange.collapse(false);
19020 return rangeStartRange.compareBoundaryPoints(
19021 Range.START_TO_START, nodeEndRange) == -1 &&
19022 rangeEndRange.compareBoundaryPoints(
19023 Range.START_TO_START, nodeStartRange) == 1;
19027 rangeCompareNode : function(range, node)
19029 var nodeRange = node.ownerDocument.createRange();
19031 nodeRange.selectNode(node);
19033 nodeRange.selectNodeContents(node);
19037 range.collapse(true);
19039 nodeRange.collapse(true);
19041 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19042 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19044 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19046 var nodeIsBefore = ss == 1;
19047 var nodeIsAfter = ee == -1;
19049 if (nodeIsBefore && nodeIsAfter)
19051 if (!nodeIsBefore && nodeIsAfter)
19052 return 1; //right trailed.
19054 if (nodeIsBefore && !nodeIsAfter)
19055 return 2; // left trailed.
19060 // private? - in a new class?
19061 cleanUpPaste : function()
19063 // cleans up the whole document..
19064 Roo.log('cleanuppaste');
19066 this.cleanUpChildren(this.doc.body);
19067 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19068 if (clean != this.doc.body.innerHTML) {
19069 this.doc.body.innerHTML = clean;
19074 cleanWordChars : function(input) {// change the chars to hex code
19075 var he = Roo.HtmlEditorCore;
19077 var output = input;
19078 Roo.each(he.swapCodes, function(sw) {
19079 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19081 output = output.replace(swapper, sw[1]);
19088 cleanUpChildren : function (n)
19090 if (!n.childNodes.length) {
19093 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19094 this.cleanUpChild(n.childNodes[i]);
19101 cleanUpChild : function (node)
19104 //console.log(node);
19105 if (node.nodeName == "#text") {
19106 // clean up silly Windows -- stuff?
19109 if (node.nodeName == "#comment") {
19110 node.parentNode.removeChild(node);
19111 // clean up silly Windows -- stuff?
19114 var lcname = node.tagName.toLowerCase();
19115 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19116 // whitelist of tags..
19118 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19120 node.parentNode.removeChild(node);
19125 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19127 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19128 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19130 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19131 // remove_keep_children = true;
19134 if (remove_keep_children) {
19135 this.cleanUpChildren(node);
19136 // inserts everything just before this node...
19137 while (node.childNodes.length) {
19138 var cn = node.childNodes[0];
19139 node.removeChild(cn);
19140 node.parentNode.insertBefore(cn, node);
19142 node.parentNode.removeChild(node);
19146 if (!node.attributes || !node.attributes.length) {
19147 this.cleanUpChildren(node);
19151 function cleanAttr(n,v)
19154 if (v.match(/^\./) || v.match(/^\//)) {
19157 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19160 if (v.match(/^#/)) {
19163 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19164 node.removeAttribute(n);
19168 var cwhite = this.cwhite;
19169 var cblack = this.cblack;
19171 function cleanStyle(n,v)
19173 if (v.match(/expression/)) { //XSS?? should we even bother..
19174 node.removeAttribute(n);
19178 var parts = v.split(/;/);
19181 Roo.each(parts, function(p) {
19182 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19186 var l = p.split(':').shift().replace(/\s+/g,'');
19187 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19189 if ( cwhite.length && cblack.indexOf(l) > -1) {
19190 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19191 //node.removeAttribute(n);
19195 // only allow 'c whitelisted system attributes'
19196 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19197 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19198 //node.removeAttribute(n);
19208 if (clean.length) {
19209 node.setAttribute(n, clean.join(';'));
19211 node.removeAttribute(n);
19217 for (var i = node.attributes.length-1; i > -1 ; i--) {
19218 var a = node.attributes[i];
19221 if (a.name.toLowerCase().substr(0,2)=='on') {
19222 node.removeAttribute(a.name);
19225 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19226 node.removeAttribute(a.name);
19229 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19230 cleanAttr(a.name,a.value); // fixme..
19233 if (a.name == 'style') {
19234 cleanStyle(a.name,a.value);
19237 /// clean up MS crap..
19238 // tecnically this should be a list of valid class'es..
19241 if (a.name == 'class') {
19242 if (a.value.match(/^Mso/)) {
19243 node.className = '';
19246 if (a.value.match(/body/)) {
19247 node.className = '';
19258 this.cleanUpChildren(node);
19264 * Clean up MS wordisms...
19266 cleanWord : function(node)
19271 this.cleanWord(this.doc.body);
19274 if (node.nodeName == "#text") {
19275 // clean up silly Windows -- stuff?
19278 if (node.nodeName == "#comment") {
19279 node.parentNode.removeChild(node);
19280 // clean up silly Windows -- stuff?
19284 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19285 node.parentNode.removeChild(node);
19289 // remove - but keep children..
19290 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19291 while (node.childNodes.length) {
19292 var cn = node.childNodes[0];
19293 node.removeChild(cn);
19294 node.parentNode.insertBefore(cn, node);
19296 node.parentNode.removeChild(node);
19297 this.iterateChildren(node, this.cleanWord);
19301 if (node.className.length) {
19303 var cn = node.className.split(/\W+/);
19305 Roo.each(cn, function(cls) {
19306 if (cls.match(/Mso[a-zA-Z]+/)) {
19311 node.className = cna.length ? cna.join(' ') : '';
19313 node.removeAttribute("class");
19317 if (node.hasAttribute("lang")) {
19318 node.removeAttribute("lang");
19321 if (node.hasAttribute("style")) {
19323 var styles = node.getAttribute("style").split(";");
19325 Roo.each(styles, function(s) {
19326 if (!s.match(/:/)) {
19329 var kv = s.split(":");
19330 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19333 // what ever is left... we allow.
19336 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19337 if (!nstyle.length) {
19338 node.removeAttribute('style');
19341 this.iterateChildren(node, this.cleanWord);
19347 * iterateChildren of a Node, calling fn each time, using this as the scole..
19348 * @param {DomNode} node node to iterate children of.
19349 * @param {Function} fn method of this class to call on each item.
19351 iterateChildren : function(node, fn)
19353 if (!node.childNodes.length) {
19356 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19357 fn.call(this, node.childNodes[i])
19363 * cleanTableWidths.
19365 * Quite often pasting from word etc.. results in tables with column and widths.
19366 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19369 cleanTableWidths : function(node)
19374 this.cleanTableWidths(this.doc.body);
19379 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19382 Roo.log(node.tagName);
19383 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19384 this.iterateChildren(node, this.cleanTableWidths);
19387 if (node.hasAttribute('width')) {
19388 node.removeAttribute('width');
19392 if (node.hasAttribute("style")) {
19395 var styles = node.getAttribute("style").split(";");
19397 Roo.each(styles, function(s) {
19398 if (!s.match(/:/)) {
19401 var kv = s.split(":");
19402 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
19405 // what ever is left... we allow.
19408 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19409 if (!nstyle.length) {
19410 node.removeAttribute('style');
19414 this.iterateChildren(node, this.cleanTableWidths);
19422 domToHTML : function(currentElement, depth, nopadtext) {
19424 depth = depth || 0;
19425 nopadtext = nopadtext || false;
19427 if (!currentElement) {
19428 return this.domToHTML(this.doc.body);
19431 //Roo.log(currentElement);
19433 var allText = false;
19434 var nodeName = currentElement.nodeName;
19435 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19437 if (nodeName == '#text') {
19439 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19444 if (nodeName != 'BODY') {
19447 // Prints the node tagName, such as <A>, <IMG>, etc
19450 for(i = 0; i < currentElement.attributes.length;i++) {
19452 var aname = currentElement.attributes.item(i).name;
19453 if (!currentElement.attributes.item(i).value.length) {
19456 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19459 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19468 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19471 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19476 // Traverse the tree
19478 var currentElementChild = currentElement.childNodes.item(i);
19479 var allText = true;
19480 var innerHTML = '';
19482 while (currentElementChild) {
19483 // Formatting code (indent the tree so it looks nice on the screen)
19484 var nopad = nopadtext;
19485 if (lastnode == 'SPAN') {
19489 if (currentElementChild.nodeName == '#text') {
19490 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19491 toadd = nopadtext ? toadd : toadd.trim();
19492 if (!nopad && toadd.length > 80) {
19493 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19495 innerHTML += toadd;
19498 currentElementChild = currentElement.childNodes.item(i);
19504 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19506 // Recursively traverse the tree structure of the child node
19507 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19508 lastnode = currentElementChild.nodeName;
19510 currentElementChild=currentElement.childNodes.item(i);
19516 // The remaining code is mostly for formatting the tree
19517 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19522 ret+= "</"+tagName+">";
19528 applyBlacklists : function()
19530 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19531 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19535 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19536 if (b.indexOf(tag) > -1) {
19539 this.white.push(tag);
19543 Roo.each(w, function(tag) {
19544 if (b.indexOf(tag) > -1) {
19547 if (this.white.indexOf(tag) > -1) {
19550 this.white.push(tag);
19555 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19556 if (w.indexOf(tag) > -1) {
19559 this.black.push(tag);
19563 Roo.each(b, function(tag) {
19564 if (w.indexOf(tag) > -1) {
19567 if (this.black.indexOf(tag) > -1) {
19570 this.black.push(tag);
19575 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19576 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19580 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19581 if (b.indexOf(tag) > -1) {
19584 this.cwhite.push(tag);
19588 Roo.each(w, function(tag) {
19589 if (b.indexOf(tag) > -1) {
19592 if (this.cwhite.indexOf(tag) > -1) {
19595 this.cwhite.push(tag);
19600 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19601 if (w.indexOf(tag) > -1) {
19604 this.cblack.push(tag);
19608 Roo.each(b, function(tag) {
19609 if (w.indexOf(tag) > -1) {
19612 if (this.cblack.indexOf(tag) > -1) {
19615 this.cblack.push(tag);
19620 setStylesheets : function(stylesheets)
19622 if(typeof(stylesheets) == 'string'){
19623 Roo.get(this.iframe.contentDocument.head).createChild({
19625 rel : 'stylesheet',
19634 Roo.each(stylesheets, function(s) {
19639 Roo.get(_this.iframe.contentDocument.head).createChild({
19641 rel : 'stylesheet',
19650 removeStylesheets : function()
19654 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19659 // hide stuff that is not compatible
19673 * @event specialkey
19677 * @cfg {String} fieldClass @hide
19680 * @cfg {String} focusClass @hide
19683 * @cfg {String} autoCreate @hide
19686 * @cfg {String} inputType @hide
19689 * @cfg {String} invalidClass @hide
19692 * @cfg {String} invalidText @hide
19695 * @cfg {String} msgFx @hide
19698 * @cfg {String} validateOnBlur @hide
19702 Roo.HtmlEditorCore.white = [
19703 'area', 'br', 'img', 'input', 'hr', 'wbr',
19705 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19706 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19707 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19708 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19709 'table', 'ul', 'xmp',
19711 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19714 'dir', 'menu', 'ol', 'ul', 'dl',
19720 Roo.HtmlEditorCore.black = [
19721 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19723 'base', 'basefont', 'bgsound', 'blink', 'body',
19724 'frame', 'frameset', 'head', 'html', 'ilayer',
19725 'iframe', 'layer', 'link', 'meta', 'object',
19726 'script', 'style' ,'title', 'xml' // clean later..
19728 Roo.HtmlEditorCore.clean = [
19729 'script', 'style', 'title', 'xml'
19731 Roo.HtmlEditorCore.remove = [
19736 Roo.HtmlEditorCore.ablack = [
19740 Roo.HtmlEditorCore.aclean = [
19741 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19745 Roo.HtmlEditorCore.pwhite= [
19746 'http', 'https', 'mailto'
19749 // white listed style attributes.
19750 Roo.HtmlEditorCore.cwhite= [
19751 // 'text-align', /// default is to allow most things..
19757 // black listed style attributes.
19758 Roo.HtmlEditorCore.cblack= [
19759 // 'font-size' -- this can be set by the project
19763 Roo.HtmlEditorCore.swapCodes =[
19782 * @class Roo.bootstrap.HtmlEditor
19783 * @extends Roo.bootstrap.TextArea
19784 * Bootstrap HtmlEditor class
19787 * Create a new HtmlEditor
19788 * @param {Object} config The config object
19791 Roo.bootstrap.HtmlEditor = function(config){
19792 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19793 if (!this.toolbars) {
19794 this.toolbars = [];
19796 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19799 * @event initialize
19800 * Fires when the editor is fully initialized (including the iframe)
19801 * @param {HtmlEditor} this
19806 * Fires when the editor is first receives the focus. Any insertion must wait
19807 * until after this event.
19808 * @param {HtmlEditor} this
19812 * @event beforesync
19813 * Fires before the textarea is updated with content from the editor iframe. Return false
19814 * to cancel the sync.
19815 * @param {HtmlEditor} this
19816 * @param {String} html
19820 * @event beforepush
19821 * Fires before the iframe editor is updated with content from the textarea. Return false
19822 * to cancel the push.
19823 * @param {HtmlEditor} this
19824 * @param {String} html
19829 * Fires when the textarea is updated with content from the editor iframe.
19830 * @param {HtmlEditor} this
19831 * @param {String} html
19836 * Fires when the iframe editor is updated with content from the textarea.
19837 * @param {HtmlEditor} this
19838 * @param {String} html
19842 * @event editmodechange
19843 * Fires when the editor switches edit modes
19844 * @param {HtmlEditor} this
19845 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19847 editmodechange: true,
19849 * @event editorevent
19850 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19851 * @param {HtmlEditor} this
19855 * @event firstfocus
19856 * Fires when on first focus - needed by toolbars..
19857 * @param {HtmlEditor} this
19862 * Auto save the htmlEditor value as a file into Events
19863 * @param {HtmlEditor} this
19867 * @event savedpreview
19868 * preview the saved version of htmlEditor
19869 * @param {HtmlEditor} this
19876 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19880 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19885 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19890 * @cfg {Number} height (in pixels)
19894 * @cfg {Number} width (in pixels)
19899 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19902 stylesheets: false,
19907 // private properties
19908 validationEvent : false,
19910 initialized : false,
19913 onFocus : Roo.emptyFn,
19915 hideMode:'offsets',
19918 tbContainer : false,
19920 toolbarContainer :function() {
19921 return this.wrap.select('.x-html-editor-tb',true).first();
19925 * Protected method that will not generally be called directly. It
19926 * is called when the editor creates its toolbar. Override this method if you need to
19927 * add custom toolbar buttons.
19928 * @param {HtmlEditor} editor
19930 createToolbar : function(){
19932 Roo.log("create toolbars");
19934 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19935 this.toolbars[0].render(this.toolbarContainer());
19939 // if (!editor.toolbars || !editor.toolbars.length) {
19940 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19943 // for (var i =0 ; i < editor.toolbars.length;i++) {
19944 // editor.toolbars[i] = Roo.factory(
19945 // typeof(editor.toolbars[i]) == 'string' ?
19946 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19947 // Roo.bootstrap.HtmlEditor);
19948 // editor.toolbars[i].init(editor);
19954 onRender : function(ct, position)
19956 // Roo.log("Call onRender: " + this.xtype);
19958 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19960 this.wrap = this.inputEl().wrap({
19961 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19964 this.editorcore.onRender(ct, position);
19966 if (this.resizable) {
19967 this.resizeEl = new Roo.Resizable(this.wrap, {
19971 minHeight : this.height,
19972 height: this.height,
19973 handles : this.resizable,
19976 resize : function(r, w, h) {
19977 _t.onResize(w,h); // -something
19983 this.createToolbar(this);
19986 if(!this.width && this.resizable){
19987 this.setSize(this.wrap.getSize());
19989 if (this.resizeEl) {
19990 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19991 // should trigger onReize..
19997 onResize : function(w, h)
19999 Roo.log('resize: ' +w + ',' + h );
20000 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20004 if(this.inputEl() ){
20005 if(typeof w == 'number'){
20006 var aw = w - this.wrap.getFrameWidth('lr');
20007 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20010 if(typeof h == 'number'){
20011 var tbh = -11; // fixme it needs to tool bar size!
20012 for (var i =0; i < this.toolbars.length;i++) {
20013 // fixme - ask toolbars for heights?
20014 tbh += this.toolbars[i].el.getHeight();
20015 //if (this.toolbars[i].footer) {
20016 // tbh += this.toolbars[i].footer.el.getHeight();
20024 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20025 ah -= 5; // knock a few pixes off for look..
20026 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20030 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20031 this.editorcore.onResize(ew,eh);
20036 * Toggles the editor between standard and source edit mode.
20037 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20039 toggleSourceEdit : function(sourceEditMode)
20041 this.editorcore.toggleSourceEdit(sourceEditMode);
20043 if(this.editorcore.sourceEditMode){
20044 Roo.log('editor - showing textarea');
20047 // Roo.log(this.syncValue());
20049 this.inputEl().removeClass(['hide', 'x-hidden']);
20050 this.inputEl().dom.removeAttribute('tabIndex');
20051 this.inputEl().focus();
20053 Roo.log('editor - hiding textarea');
20055 // Roo.log(this.pushValue());
20058 this.inputEl().addClass(['hide', 'x-hidden']);
20059 this.inputEl().dom.setAttribute('tabIndex', -1);
20060 //this.deferFocus();
20063 if(this.resizable){
20064 this.setSize(this.wrap.getSize());
20067 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20070 // private (for BoxComponent)
20071 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20073 // private (for BoxComponent)
20074 getResizeEl : function(){
20078 // private (for BoxComponent)
20079 getPositionEl : function(){
20084 initEvents : function(){
20085 this.originalValue = this.getValue();
20089 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20092 // markInvalid : Roo.emptyFn,
20094 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20097 // clearInvalid : Roo.emptyFn,
20099 setValue : function(v){
20100 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20101 this.editorcore.pushValue();
20106 deferFocus : function(){
20107 this.focus.defer(10, this);
20111 focus : function(){
20112 this.editorcore.focus();
20118 onDestroy : function(){
20124 for (var i =0; i < this.toolbars.length;i++) {
20125 // fixme - ask toolbars for heights?
20126 this.toolbars[i].onDestroy();
20129 this.wrap.dom.innerHTML = '';
20130 this.wrap.remove();
20135 onFirstFocus : function(){
20136 //Roo.log("onFirstFocus");
20137 this.editorcore.onFirstFocus();
20138 for (var i =0; i < this.toolbars.length;i++) {
20139 this.toolbars[i].onFirstFocus();
20145 syncValue : function()
20147 this.editorcore.syncValue();
20150 pushValue : function()
20152 this.editorcore.pushValue();
20156 // hide stuff that is not compatible
20170 * @event specialkey
20174 * @cfg {String} fieldClass @hide
20177 * @cfg {String} focusClass @hide
20180 * @cfg {String} autoCreate @hide
20183 * @cfg {String} inputType @hide
20186 * @cfg {String} invalidClass @hide
20189 * @cfg {String} invalidText @hide
20192 * @cfg {String} msgFx @hide
20195 * @cfg {String} validateOnBlur @hide
20204 Roo.namespace('Roo.bootstrap.htmleditor');
20206 * @class Roo.bootstrap.HtmlEditorToolbar1
20211 new Roo.bootstrap.HtmlEditor({
20214 new Roo.bootstrap.HtmlEditorToolbar1({
20215 disable : { fonts: 1 , format: 1, ..., ... , ...],
20221 * @cfg {Object} disable List of elements to disable..
20222 * @cfg {Array} btns List of additional buttons.
20226 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20229 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20232 Roo.apply(this, config);
20234 // default disabled, based on 'good practice'..
20235 this.disable = this.disable || {};
20236 Roo.applyIf(this.disable, {
20239 specialElements : true
20241 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20243 this.editor = config.editor;
20244 this.editorcore = config.editor.editorcore;
20246 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20248 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20249 // dont call parent... till later.
20251 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20256 editorcore : false,
20261 "h1","h2","h3","h4","h5","h6",
20263 "abbr", "acronym", "address", "cite", "samp", "var",
20267 onRender : function(ct, position)
20269 // Roo.log("Call onRender: " + this.xtype);
20271 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20273 this.el.dom.style.marginBottom = '0';
20275 var editorcore = this.editorcore;
20276 var editor= this.editor;
20279 var btn = function(id,cmd , toggle, handler){
20281 var event = toggle ? 'toggle' : 'click';
20286 xns: Roo.bootstrap,
20289 enableToggle:toggle !== false,
20291 pressed : toggle ? false : null,
20294 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20295 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20304 xns: Roo.bootstrap,
20305 glyphicon : 'font',
20309 xns: Roo.bootstrap,
20313 Roo.each(this.formats, function(f) {
20314 style.menu.items.push({
20316 xns: Roo.bootstrap,
20317 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20322 editorcore.insertTag(this.tagname);
20329 children.push(style);
20332 btn('bold',false,true);
20333 btn('italic',false,true);
20334 btn('align-left', 'justifyleft',true);
20335 btn('align-center', 'justifycenter',true);
20336 btn('align-right' , 'justifyright',true);
20337 btn('link', false, false, function(btn) {
20338 //Roo.log("create link?");
20339 var url = prompt(this.createLinkText, this.defaultLinkValue);
20340 if(url && url != 'http:/'+'/'){
20341 this.editorcore.relayCmd('createlink', url);
20344 btn('list','insertunorderedlist',true);
20345 btn('pencil', false,true, function(btn){
20348 this.toggleSourceEdit(btn.pressed);
20354 xns: Roo.bootstrap,
20359 xns: Roo.bootstrap,
20364 cog.menu.items.push({
20366 xns: Roo.bootstrap,
20367 html : Clean styles,
20372 editorcore.insertTag(this.tagname);
20381 this.xtype = 'NavSimplebar';
20383 for(var i=0;i< children.length;i++) {
20385 this.buttons.add(this.addxtypeChild(children[i]));
20389 editor.on('editorevent', this.updateToolbar, this);
20391 onBtnClick : function(id)
20393 this.editorcore.relayCmd(id);
20394 this.editorcore.focus();
20398 * Protected method that will not generally be called directly. It triggers
20399 * a toolbar update by reading the markup state of the current selection in the editor.
20401 updateToolbar: function(){
20403 if(!this.editorcore.activated){
20404 this.editor.onFirstFocus(); // is this neeed?
20408 var btns = this.buttons;
20409 var doc = this.editorcore.doc;
20410 btns.get('bold').setActive(doc.queryCommandState('bold'));
20411 btns.get('italic').setActive(doc.queryCommandState('italic'));
20412 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20414 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20415 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20416 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20418 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20419 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20422 var ans = this.editorcore.getAllAncestors();
20423 if (this.formatCombo) {
20426 var store = this.formatCombo.store;
20427 this.formatCombo.setValue("");
20428 for (var i =0; i < ans.length;i++) {
20429 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20431 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20439 // hides menus... - so this cant be on a menu...
20440 Roo.bootstrap.MenuMgr.hideAll();
20442 Roo.bootstrap.MenuMgr.hideAll();
20443 //this.editorsyncValue();
20445 onFirstFocus: function() {
20446 this.buttons.each(function(item){
20450 toggleSourceEdit : function(sourceEditMode){
20453 if(sourceEditMode){
20454 Roo.log("disabling buttons");
20455 this.buttons.each( function(item){
20456 if(item.cmd != 'pencil'){
20462 Roo.log("enabling buttons");
20463 if(this.editorcore.initialized){
20464 this.buttons.each( function(item){
20470 Roo.log("calling toggole on editor");
20471 // tell the editor that it's been pressed..
20472 this.editor.toggleSourceEdit(sourceEditMode);
20482 * @class Roo.bootstrap.Table.AbstractSelectionModel
20483 * @extends Roo.util.Observable
20484 * Abstract base class for grid SelectionModels. It provides the interface that should be
20485 * implemented by descendant classes. This class should not be directly instantiated.
20488 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20489 this.locked = false;
20490 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20494 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20495 /** @ignore Called by the grid automatically. Do not call directly. */
20496 init : function(grid){
20502 * Locks the selections.
20505 this.locked = true;
20509 * Unlocks the selections.
20511 unlock : function(){
20512 this.locked = false;
20516 * Returns true if the selections are locked.
20517 * @return {Boolean}
20519 isLocked : function(){
20520 return this.locked;
20524 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20525 * @class Roo.bootstrap.Table.RowSelectionModel
20526 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20527 * It supports multiple selections and keyboard selection/navigation.
20529 * @param {Object} config
20532 Roo.bootstrap.Table.RowSelectionModel = function(config){
20533 Roo.apply(this, config);
20534 this.selections = new Roo.util.MixedCollection(false, function(o){
20539 this.lastActive = false;
20543 * @event selectionchange
20544 * Fires when the selection changes
20545 * @param {SelectionModel} this
20547 "selectionchange" : true,
20549 * @event afterselectionchange
20550 * Fires after the selection changes (eg. by key press or clicking)
20551 * @param {SelectionModel} this
20553 "afterselectionchange" : true,
20555 * @event beforerowselect
20556 * Fires when a row is selected being selected, return false to cancel.
20557 * @param {SelectionModel} this
20558 * @param {Number} rowIndex The selected index
20559 * @param {Boolean} keepExisting False if other selections will be cleared
20561 "beforerowselect" : true,
20564 * Fires when a row is selected.
20565 * @param {SelectionModel} this
20566 * @param {Number} rowIndex The selected index
20567 * @param {Roo.data.Record} r The record
20569 "rowselect" : true,
20571 * @event rowdeselect
20572 * Fires when a row is deselected.
20573 * @param {SelectionModel} this
20574 * @param {Number} rowIndex The selected index
20576 "rowdeselect" : true
20578 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20579 this.locked = false;
20582 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20584 * @cfg {Boolean} singleSelect
20585 * True to allow selection of only one row at a time (defaults to false)
20587 singleSelect : false,
20590 initEvents : function(){
20592 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20593 this.grid.on("mousedown", this.handleMouseDown, this);
20594 }else{ // allow click to work like normal
20595 this.grid.on("rowclick", this.handleDragableRowClick, this);
20598 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20599 "up" : function(e){
20601 this.selectPrevious(e.shiftKey);
20602 }else if(this.last !== false && this.lastActive !== false){
20603 var last = this.last;
20604 this.selectRange(this.last, this.lastActive-1);
20605 this.grid.getView().focusRow(this.lastActive);
20606 if(last !== false){
20610 this.selectFirstRow();
20612 this.fireEvent("afterselectionchange", this);
20614 "down" : function(e){
20616 this.selectNext(e.shiftKey);
20617 }else if(this.last !== false && this.lastActive !== false){
20618 var last = this.last;
20619 this.selectRange(this.last, this.lastActive+1);
20620 this.grid.getView().focusRow(this.lastActive);
20621 if(last !== false){
20625 this.selectFirstRow();
20627 this.fireEvent("afterselectionchange", this);
20632 var view = this.grid.view;
20633 view.on("refresh", this.onRefresh, this);
20634 view.on("rowupdated", this.onRowUpdated, this);
20635 view.on("rowremoved", this.onRemove, this);
20639 onRefresh : function(){
20640 var ds = this.grid.dataSource, i, v = this.grid.view;
20641 var s = this.selections;
20642 s.each(function(r){
20643 if((i = ds.indexOfId(r.id)) != -1){
20652 onRemove : function(v, index, r){
20653 this.selections.remove(r);
20657 onRowUpdated : function(v, index, r){
20658 if(this.isSelected(r)){
20659 v.onRowSelect(index);
20665 * @param {Array} records The records to select
20666 * @param {Boolean} keepExisting (optional) True to keep existing selections
20668 selectRecords : function(records, keepExisting){
20670 this.clearSelections();
20672 var ds = this.grid.dataSource;
20673 for(var i = 0, len = records.length; i < len; i++){
20674 this.selectRow(ds.indexOf(records[i]), true);
20679 * Gets the number of selected rows.
20682 getCount : function(){
20683 return this.selections.length;
20687 * Selects the first row in the grid.
20689 selectFirstRow : function(){
20694 * Select the last row.
20695 * @param {Boolean} keepExisting (optional) True to keep existing selections
20697 selectLastRow : function(keepExisting){
20698 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20702 * Selects the row immediately following the last selected row.
20703 * @param {Boolean} keepExisting (optional) True to keep existing selections
20705 selectNext : function(keepExisting){
20706 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20707 this.selectRow(this.last+1, keepExisting);
20708 this.grid.getView().focusRow(this.last);
20713 * Selects the row that precedes the last selected row.
20714 * @param {Boolean} keepExisting (optional) True to keep existing selections
20716 selectPrevious : function(keepExisting){
20718 this.selectRow(this.last-1, keepExisting);
20719 this.grid.getView().focusRow(this.last);
20724 * Returns the selected records
20725 * @return {Array} Array of selected records
20727 getSelections : function(){
20728 return [].concat(this.selections.items);
20732 * Returns the first selected record.
20735 getSelected : function(){
20736 return this.selections.itemAt(0);
20741 * Clears all selections.
20743 clearSelections : function(fast){
20744 if(this.locked) return;
20746 var ds = this.grid.dataSource;
20747 var s = this.selections;
20748 s.each(function(r){
20749 this.deselectRow(ds.indexOfId(r.id));
20753 this.selections.clear();
20760 * Selects all rows.
20762 selectAll : function(){
20763 if(this.locked) return;
20764 this.selections.clear();
20765 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20766 this.selectRow(i, true);
20771 * Returns True if there is a selection.
20772 * @return {Boolean}
20774 hasSelection : function(){
20775 return this.selections.length > 0;
20779 * Returns True if the specified row is selected.
20780 * @param {Number/Record} record The record or index of the record to check
20781 * @return {Boolean}
20783 isSelected : function(index){
20784 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20785 return (r && this.selections.key(r.id) ? true : false);
20789 * Returns True if the specified record id is selected.
20790 * @param {String} id The id of record to check
20791 * @return {Boolean}
20793 isIdSelected : function(id){
20794 return (this.selections.key(id) ? true : false);
20798 handleMouseDown : function(e, t){
20799 var view = this.grid.getView(), rowIndex;
20800 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20803 if(e.shiftKey && this.last !== false){
20804 var last = this.last;
20805 this.selectRange(last, rowIndex, e.ctrlKey);
20806 this.last = last; // reset the last
20807 view.focusRow(rowIndex);
20809 var isSelected = this.isSelected(rowIndex);
20810 if(e.button !== 0 && isSelected){
20811 view.focusRow(rowIndex);
20812 }else if(e.ctrlKey && isSelected){
20813 this.deselectRow(rowIndex);
20814 }else if(!isSelected){
20815 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20816 view.focusRow(rowIndex);
20819 this.fireEvent("afterselectionchange", this);
20822 handleDragableRowClick : function(grid, rowIndex, e)
20824 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20825 this.selectRow(rowIndex, false);
20826 grid.view.focusRow(rowIndex);
20827 this.fireEvent("afterselectionchange", this);
20832 * Selects multiple rows.
20833 * @param {Array} rows Array of the indexes of the row to select
20834 * @param {Boolean} keepExisting (optional) True to keep existing selections
20836 selectRows : function(rows, keepExisting){
20838 this.clearSelections();
20840 for(var i = 0, len = rows.length; i < len; i++){
20841 this.selectRow(rows[i], true);
20846 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20847 * @param {Number} startRow The index of the first row in the range
20848 * @param {Number} endRow The index of the last row in the range
20849 * @param {Boolean} keepExisting (optional) True to retain existing selections
20851 selectRange : function(startRow, endRow, keepExisting){
20852 if(this.locked) return;
20854 this.clearSelections();
20856 if(startRow <= endRow){
20857 for(var i = startRow; i <= endRow; i++){
20858 this.selectRow(i, true);
20861 for(var i = startRow; i >= endRow; i--){
20862 this.selectRow(i, true);
20868 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20869 * @param {Number} startRow The index of the first row in the range
20870 * @param {Number} endRow The index of the last row in the range
20872 deselectRange : function(startRow, endRow, preventViewNotify){
20873 if(this.locked) return;
20874 for(var i = startRow; i <= endRow; i++){
20875 this.deselectRow(i, preventViewNotify);
20881 * @param {Number} row The index of the row to select
20882 * @param {Boolean} keepExisting (optional) True to keep existing selections
20884 selectRow : function(index, keepExisting, preventViewNotify){
20885 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20886 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20887 if(!keepExisting || this.singleSelect){
20888 this.clearSelections();
20890 var r = this.grid.dataSource.getAt(index);
20891 this.selections.add(r);
20892 this.last = this.lastActive = index;
20893 if(!preventViewNotify){
20894 this.grid.getView().onRowSelect(index);
20896 this.fireEvent("rowselect", this, index, r);
20897 this.fireEvent("selectionchange", this);
20903 * @param {Number} row The index of the row to deselect
20905 deselectRow : function(index, preventViewNotify){
20906 if(this.locked) return;
20907 if(this.last == index){
20910 if(this.lastActive == index){
20911 this.lastActive = false;
20913 var r = this.grid.dataSource.getAt(index);
20914 this.selections.remove(r);
20915 if(!preventViewNotify){
20916 this.grid.getView().onRowDeselect(index);
20918 this.fireEvent("rowdeselect", this, index);
20919 this.fireEvent("selectionchange", this);
20923 restoreLast : function(){
20925 this.last = this._last;
20930 acceptsNav : function(row, col, cm){
20931 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20935 onEditorKey : function(field, e){
20936 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20941 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20943 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20945 }else if(k == e.ENTER && !e.ctrlKey){
20949 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20951 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20953 }else if(k == e.ESC){
20957 g.startEditing(newCell[0], newCell[1]);
20962 * Ext JS Library 1.1.1
20963 * Copyright(c) 2006-2007, Ext JS, LLC.
20965 * Originally Released Under LGPL - original licence link has changed is not relivant.
20968 * <script type="text/javascript">
20972 * @class Roo.bootstrap.PagingToolbar
20974 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20976 * Create a new PagingToolbar
20977 * @param {Object} config The config object
20979 Roo.bootstrap.PagingToolbar = function(config)
20981 // old args format still supported... - xtype is prefered..
20982 // created from xtype...
20983 var ds = config.dataSource;
20984 this.toolbarItems = [];
20985 if (config.items) {
20986 this.toolbarItems = config.items;
20987 // config.items = [];
20990 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20997 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21001 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21003 * @cfg {Roo.data.Store} dataSource
21004 * The underlying data store providing the paged data
21007 * @cfg {String/HTMLElement/Element} container
21008 * container The id or element that will contain the toolbar
21011 * @cfg {Boolean} displayInfo
21012 * True to display the displayMsg (defaults to false)
21015 * @cfg {Number} pageSize
21016 * The number of records to display per page (defaults to 20)
21020 * @cfg {String} displayMsg
21021 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21023 displayMsg : 'Displaying {0} - {1} of {2}',
21025 * @cfg {String} emptyMsg
21026 * The message to display when no records are found (defaults to "No data to display")
21028 emptyMsg : 'No data to display',
21030 * Customizable piece of the default paging text (defaults to "Page")
21033 beforePageText : "Page",
21035 * Customizable piece of the default paging text (defaults to "of %0")
21038 afterPageText : "of {0}",
21040 * Customizable piece of the default paging text (defaults to "First Page")
21043 firstText : "First Page",
21045 * Customizable piece of the default paging text (defaults to "Previous Page")
21048 prevText : "Previous Page",
21050 * Customizable piece of the default paging text (defaults to "Next Page")
21053 nextText : "Next Page",
21055 * Customizable piece of the default paging text (defaults to "Last Page")
21058 lastText : "Last Page",
21060 * Customizable piece of the default paging text (defaults to "Refresh")
21063 refreshText : "Refresh",
21067 onRender : function(ct, position)
21069 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21070 this.navgroup.parentId = this.id;
21071 this.navgroup.onRender(this.el, null);
21072 // add the buttons to the navgroup
21074 if(this.displayInfo){
21075 Roo.log(this.el.select('ul.navbar-nav',true).first());
21076 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21077 this.displayEl = this.el.select('.x-paging-info', true).first();
21078 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21079 // this.displayEl = navel.el.select('span',true).first();
21085 Roo.each(_this.buttons, function(e){
21086 Roo.factory(e).onRender(_this.el, null);
21090 Roo.each(_this.toolbarItems, function(e) {
21091 _this.navgroup.addItem(e);
21095 this.first = this.navgroup.addItem({
21096 tooltip: this.firstText,
21098 icon : 'fa fa-backward',
21100 preventDefault: true,
21101 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21104 this.prev = this.navgroup.addItem({
21105 tooltip: this.prevText,
21107 icon : 'fa fa-step-backward',
21109 preventDefault: true,
21110 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21112 //this.addSeparator();
21115 var field = this.navgroup.addItem( {
21117 cls : 'x-paging-position',
21119 html : this.beforePageText +
21120 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21121 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21124 this.field = field.el.select('input', true).first();
21125 this.field.on("keydown", this.onPagingKeydown, this);
21126 this.field.on("focus", function(){this.dom.select();});
21129 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21130 //this.field.setHeight(18);
21131 //this.addSeparator();
21132 this.next = this.navgroup.addItem({
21133 tooltip: this.nextText,
21135 html : ' <i class="fa fa-step-forward">',
21137 preventDefault: true,
21138 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21140 this.last = this.navgroup.addItem({
21141 tooltip: this.lastText,
21142 icon : 'fa fa-forward',
21145 preventDefault: true,
21146 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21148 //this.addSeparator();
21149 this.loading = this.navgroup.addItem({
21150 tooltip: this.refreshText,
21151 icon: 'fa fa-refresh',
21152 preventDefault: true,
21153 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21159 updateInfo : function(){
21160 if(this.displayEl){
21161 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21162 var msg = count == 0 ?
21166 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21168 this.displayEl.update(msg);
21173 onLoad : function(ds, r, o){
21174 this.cursor = o.params ? o.params.start : 0;
21175 var d = this.getPageData(),
21179 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21180 this.field.dom.value = ap;
21181 this.first.setDisabled(ap == 1);
21182 this.prev.setDisabled(ap == 1);
21183 this.next.setDisabled(ap == ps);
21184 this.last.setDisabled(ap == ps);
21185 this.loading.enable();
21190 getPageData : function(){
21191 var total = this.ds.getTotalCount();
21194 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21195 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21200 onLoadError : function(){
21201 this.loading.enable();
21205 onPagingKeydown : function(e){
21206 var k = e.getKey();
21207 var d = this.getPageData();
21209 var v = this.field.dom.value, pageNum;
21210 if(!v || isNaN(pageNum = parseInt(v, 10))){
21211 this.field.dom.value = d.activePage;
21214 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21215 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21218 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))
21220 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21221 this.field.dom.value = pageNum;
21222 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21225 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21227 var v = this.field.dom.value, pageNum;
21228 var increment = (e.shiftKey) ? 10 : 1;
21229 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21231 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21232 this.field.dom.value = d.activePage;
21235 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21237 this.field.dom.value = parseInt(v, 10) + increment;
21238 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21239 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21246 beforeLoad : function(){
21248 this.loading.disable();
21253 onClick : function(which){
21262 ds.load({params:{start: 0, limit: this.pageSize}});
21265 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21268 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21271 var total = ds.getTotalCount();
21272 var extra = total % this.pageSize;
21273 var lastStart = extra ? (total - extra) : total-this.pageSize;
21274 ds.load({params:{start: lastStart, limit: this.pageSize}});
21277 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21283 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21284 * @param {Roo.data.Store} store The data store to unbind
21286 unbind : function(ds){
21287 ds.un("beforeload", this.beforeLoad, this);
21288 ds.un("load", this.onLoad, this);
21289 ds.un("loadexception", this.onLoadError, this);
21290 ds.un("remove", this.updateInfo, this);
21291 ds.un("add", this.updateInfo, this);
21292 this.ds = undefined;
21296 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21297 * @param {Roo.data.Store} store The data store to bind
21299 bind : function(ds){
21300 ds.on("beforeload", this.beforeLoad, this);
21301 ds.on("load", this.onLoad, this);
21302 ds.on("loadexception", this.onLoadError, this);
21303 ds.on("remove", this.updateInfo, this);
21304 ds.on("add", this.updateInfo, this);
21315 * @class Roo.bootstrap.MessageBar
21316 * @extends Roo.bootstrap.Component
21317 * Bootstrap MessageBar class
21318 * @cfg {String} html contents of the MessageBar
21319 * @cfg {String} weight (info | success | warning | danger) default info
21320 * @cfg {String} beforeClass insert the bar before the given class
21321 * @cfg {Boolean} closable (true | false) default false
21322 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21325 * Create a new Element
21326 * @param {Object} config The config object
21329 Roo.bootstrap.MessageBar = function(config){
21330 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21333 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21339 beforeClass: 'bootstrap-sticky-wrap',
21341 getAutoCreate : function(){
21345 cls: 'alert alert-dismissable alert-' + this.weight,
21350 html: this.html || ''
21356 cfg.cls += ' alert-messages-fixed';
21370 onRender : function(ct, position)
21372 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21375 var cfg = Roo.apply({}, this.getAutoCreate());
21379 cfg.cls += ' ' + this.cls;
21382 cfg.style = this.style;
21384 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21386 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21389 this.el.select('>button.close').on('click', this.hide, this);
21395 if (!this.rendered) {
21401 this.fireEvent('show', this);
21407 if (!this.rendered) {
21413 this.fireEvent('hide', this);
21416 update : function()
21418 // var e = this.el.dom.firstChild;
21420 // if(this.closable){
21421 // e = e.nextSibling;
21424 // e.data = this.html || '';
21426 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21442 * @class Roo.bootstrap.Graph
21443 * @extends Roo.bootstrap.Component
21444 * Bootstrap Graph class
21448 @cfg {String} graphtype bar | vbar | pie
21449 @cfg {number} g_x coodinator | centre x (pie)
21450 @cfg {number} g_y coodinator | centre y (pie)
21451 @cfg {number} g_r radius (pie)
21452 @cfg {number} g_height height of the chart (respected by all elements in the set)
21453 @cfg {number} g_width width of the chart (respected by all elements in the set)
21454 @cfg {Object} title The title of the chart
21457 -opts (object) options for the chart
21459 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21460 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21462 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.
21463 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21465 o stretch (boolean)
21467 -opts (object) options for the pie
21470 o startAngle (number)
21471 o endAngle (number)
21475 * Create a new Input
21476 * @param {Object} config The config object
21479 Roo.bootstrap.Graph = function(config){
21480 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21486 * The img click event for the img.
21487 * @param {Roo.EventObject} e
21493 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21504 //g_colors: this.colors,
21511 getAutoCreate : function(){
21522 onRender : function(ct,position){
21523 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21524 this.raphael = Raphael(this.el.dom);
21526 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21527 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21528 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21529 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21531 r.text(160, 10, "Single Series Chart").attr(txtattr);
21532 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21533 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21534 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21536 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21537 r.barchart(330, 10, 300, 220, data1);
21538 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21539 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21542 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21543 // r.barchart(30, 30, 560, 250, xdata, {
21544 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21545 // axis : "0 0 1 1",
21546 // axisxlabels : xdata
21547 // //yvalues : cols,
21550 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21552 // this.load(null,xdata,{
21553 // axis : "0 0 1 1",
21554 // axisxlabels : xdata
21559 load : function(graphtype,xdata,opts){
21560 this.raphael.clear();
21562 graphtype = this.graphtype;
21567 var r = this.raphael,
21568 fin = function () {
21569 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21571 fout = function () {
21572 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21574 pfin = function() {
21575 this.sector.stop();
21576 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21579 this.label[0].stop();
21580 this.label[0].attr({ r: 7.5 });
21581 this.label[1].attr({ "font-weight": 800 });
21584 pfout = function() {
21585 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21588 this.label[0].animate({ r: 5 }, 500, "bounce");
21589 this.label[1].attr({ "font-weight": 400 });
21595 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21598 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21601 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21602 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21604 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21611 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21616 setTitle: function(o)
21621 initEvents: function() {
21624 this.el.on('click', this.onClick, this);
21628 onClick : function(e)
21630 Roo.log('img onclick');
21631 this.fireEvent('click', this, e);
21643 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21646 * @class Roo.bootstrap.dash.NumberBox
21647 * @extends Roo.bootstrap.Component
21648 * Bootstrap NumberBox class
21649 * @cfg {String} headline Box headline
21650 * @cfg {String} content Box content
21651 * @cfg {String} icon Box icon
21652 * @cfg {String} footer Footer text
21653 * @cfg {String} fhref Footer href
21656 * Create a new NumberBox
21657 * @param {Object} config The config object
21661 Roo.bootstrap.dash.NumberBox = function(config){
21662 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21666 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21675 getAutoCreate : function(){
21679 cls : 'small-box ',
21687 cls : 'roo-headline',
21688 html : this.headline
21692 cls : 'roo-content',
21693 html : this.content
21707 cls : 'ion ' + this.icon
21716 cls : 'small-box-footer',
21717 href : this.fhref || '#',
21721 cfg.cn.push(footer);
21728 onRender : function(ct,position){
21729 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21736 setHeadline: function (value)
21738 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21741 setFooter: function (value, href)
21743 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21746 this.el.select('a.small-box-footer',true).first().attr('href', href);
21751 setContent: function (value)
21753 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21756 initEvents: function()
21770 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21773 * @class Roo.bootstrap.dash.TabBox
21774 * @extends Roo.bootstrap.Component
21775 * Bootstrap TabBox class
21776 * @cfg {String} title Title of the TabBox
21777 * @cfg {String} icon Icon of the TabBox
21778 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21779 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21782 * Create a new TabBox
21783 * @param {Object} config The config object
21787 Roo.bootstrap.dash.TabBox = function(config){
21788 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21793 * When a pane is added
21794 * @param {Roo.bootstrap.dash.TabPane} pane
21798 * @event activatepane
21799 * When a pane is activated
21800 * @param {Roo.bootstrap.dash.TabPane} pane
21802 "activatepane" : true
21810 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21815 tabScrollable : false,
21817 getChildContainer : function()
21819 return this.el.select('.tab-content', true).first();
21822 getAutoCreate : function(){
21826 cls: 'pull-left header',
21834 cls: 'fa ' + this.icon
21840 cls: 'nav nav-tabs pull-right',
21846 if(this.tabScrollable){
21853 cls: 'nav nav-tabs pull-right',
21864 cls: 'nav-tabs-custom',
21869 cls: 'tab-content no-padding',
21877 initEvents : function()
21879 //Roo.log('add add pane handler');
21880 this.on('addpane', this.onAddPane, this);
21883 * Updates the box title
21884 * @param {String} html to set the title to.
21886 setTitle : function(value)
21888 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21890 onAddPane : function(pane)
21892 this.panes.push(pane);
21893 //Roo.log('addpane');
21895 // tabs are rendere left to right..
21896 if(!this.showtabs){
21900 var ctr = this.el.select('.nav-tabs', true).first();
21903 var existing = ctr.select('.nav-tab',true);
21904 var qty = existing.getCount();;
21907 var tab = ctr.createChild({
21909 cls : 'nav-tab' + (qty ? '' : ' active'),
21917 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21920 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21922 pane.el.addClass('active');
21927 onTabClick : function(ev,un,ob,pane)
21929 //Roo.log('tab - prev default');
21930 ev.preventDefault();
21933 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21934 pane.tab.addClass('active');
21935 //Roo.log(pane.title);
21936 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21937 // technically we should have a deactivate event.. but maybe add later.
21938 // and it should not de-activate the selected tab...
21939 this.fireEvent('activatepane', pane);
21940 pane.el.addClass('active');
21941 pane.fireEvent('activate');
21946 getActivePane : function()
21949 Roo.each(this.panes, function(p) {
21950 if(p.el.hasClass('active')){
21971 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21973 * @class Roo.bootstrap.TabPane
21974 * @extends Roo.bootstrap.Component
21975 * Bootstrap TabPane class
21976 * @cfg {Boolean} active (false | true) Default false
21977 * @cfg {String} title title of panel
21981 * Create a new TabPane
21982 * @param {Object} config The config object
21985 Roo.bootstrap.dash.TabPane = function(config){
21986 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21992 * When a pane is activated
21993 * @param {Roo.bootstrap.dash.TabPane} pane
22000 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22005 // the tabBox that this is attached to.
22008 getAutoCreate : function()
22016 cfg.cls += ' active';
22021 initEvents : function()
22023 //Roo.log('trigger add pane handler');
22024 this.parent().fireEvent('addpane', this)
22028 * Updates the tab title
22029 * @param {String} html to set the title to.
22031 setTitle: function(str)
22037 this.tab.select('a', true).first().dom.innerHTML = str;
22054 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22057 * @class Roo.bootstrap.menu.Menu
22058 * @extends Roo.bootstrap.Component
22059 * Bootstrap Menu class - container for Menu
22060 * @cfg {String} html Text of the menu
22061 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22062 * @cfg {String} icon Font awesome icon
22063 * @cfg {String} pos Menu align to (top | bottom) default bottom
22067 * Create a new Menu
22068 * @param {Object} config The config object
22072 Roo.bootstrap.menu.Menu = function(config){
22073 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22077 * @event beforeshow
22078 * Fires before this menu is displayed
22079 * @param {Roo.bootstrap.menu.Menu} this
22083 * @event beforehide
22084 * Fires before this menu is hidden
22085 * @param {Roo.bootstrap.menu.Menu} this
22090 * Fires after this menu is displayed
22091 * @param {Roo.bootstrap.menu.Menu} this
22096 * Fires after this menu is hidden
22097 * @param {Roo.bootstrap.menu.Menu} this
22102 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22103 * @param {Roo.bootstrap.menu.Menu} this
22104 * @param {Roo.EventObject} e
22111 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22115 weight : 'default',
22120 getChildContainer : function() {
22121 if(this.isSubMenu){
22125 return this.el.select('ul.dropdown-menu', true).first();
22128 getAutoCreate : function()
22133 cls : 'roo-menu-text',
22141 cls : 'fa ' + this.icon
22152 cls : 'dropdown-button btn btn-' + this.weight,
22157 cls : 'dropdown-toggle btn btn-' + this.weight,
22167 cls : 'dropdown-menu'
22173 if(this.pos == 'top'){
22174 cfg.cls += ' dropup';
22177 if(this.isSubMenu){
22180 cls : 'dropdown-menu'
22187 onRender : function(ct, position)
22189 this.isSubMenu = ct.hasClass('dropdown-submenu');
22191 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22194 initEvents : function()
22196 if(this.isSubMenu){
22200 this.hidden = true;
22202 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22203 this.triggerEl.on('click', this.onTriggerPress, this);
22205 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22206 this.buttonEl.on('click', this.onClick, this);
22212 if(this.isSubMenu){
22216 return this.el.select('ul.dropdown-menu', true).first();
22219 onClick : function(e)
22221 this.fireEvent("click", this, e);
22224 onTriggerPress : function(e)
22226 if (this.isVisible()) {
22233 isVisible : function(){
22234 return !this.hidden;
22239 this.fireEvent("beforeshow", this);
22241 this.hidden = false;
22242 this.el.addClass('open');
22244 Roo.get(document).on("mouseup", this.onMouseUp, this);
22246 this.fireEvent("show", this);
22253 this.fireEvent("beforehide", this);
22255 this.hidden = true;
22256 this.el.removeClass('open');
22258 Roo.get(document).un("mouseup", this.onMouseUp);
22260 this.fireEvent("hide", this);
22263 onMouseUp : function()
22277 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22280 * @class Roo.bootstrap.menu.Item
22281 * @extends Roo.bootstrap.Component
22282 * Bootstrap MenuItem class
22283 * @cfg {Boolean} submenu (true | false) default false
22284 * @cfg {String} html text of the item
22285 * @cfg {String} href the link
22286 * @cfg {Boolean} disable (true | false) default false
22287 * @cfg {Boolean} preventDefault (true | false) default true
22288 * @cfg {String} icon Font awesome icon
22289 * @cfg {String} pos Submenu align to (left | right) default right
22293 * Create a new Item
22294 * @param {Object} config The config object
22298 Roo.bootstrap.menu.Item = function(config){
22299 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22303 * Fires when the mouse is hovering over this menu
22304 * @param {Roo.bootstrap.menu.Item} this
22305 * @param {Roo.EventObject} e
22310 * Fires when the mouse exits this menu
22311 * @param {Roo.bootstrap.menu.Item} this
22312 * @param {Roo.EventObject} e
22318 * The raw click event for the entire grid.
22319 * @param {Roo.EventObject} e
22325 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22330 preventDefault: true,
22335 getAutoCreate : function()
22340 cls : 'roo-menu-item-text',
22348 cls : 'fa ' + this.icon
22357 href : this.href || '#',
22364 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22368 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22370 if(this.pos == 'left'){
22371 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22378 initEvents : function()
22380 this.el.on('mouseover', this.onMouseOver, this);
22381 this.el.on('mouseout', this.onMouseOut, this);
22383 this.el.select('a', true).first().on('click', this.onClick, this);
22387 onClick : function(e)
22389 if(this.preventDefault){
22390 e.preventDefault();
22393 this.fireEvent("click", this, e);
22396 onMouseOver : function(e)
22398 if(this.submenu && this.pos == 'left'){
22399 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22402 this.fireEvent("mouseover", this, e);
22405 onMouseOut : function(e)
22407 this.fireEvent("mouseout", this, e);
22419 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22422 * @class Roo.bootstrap.menu.Separator
22423 * @extends Roo.bootstrap.Component
22424 * Bootstrap Separator class
22427 * Create a new Separator
22428 * @param {Object} config The config object
22432 Roo.bootstrap.menu.Separator = function(config){
22433 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22436 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22438 getAutoCreate : function(){
22459 * @class Roo.bootstrap.Tooltip
22460 * Bootstrap Tooltip class
22461 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22462 * to determine which dom element triggers the tooltip.
22464 * It needs to add support for additional attributes like tooltip-position
22467 * Create a new Toolti
22468 * @param {Object} config The config object
22471 Roo.bootstrap.Tooltip = function(config){
22472 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22475 Roo.apply(Roo.bootstrap.Tooltip, {
22477 * @function init initialize tooltip monitoring.
22481 currentTip : false,
22482 currentRegion : false,
22488 Roo.get(document).on('mouseover', this.enter ,this);
22489 Roo.get(document).on('mouseout', this.leave, this);
22492 this.currentTip = new Roo.bootstrap.Tooltip();
22495 enter : function(ev)
22497 var dom = ev.getTarget();
22499 //Roo.log(['enter',dom]);
22500 var el = Roo.fly(dom);
22501 if (this.currentEl) {
22503 //Roo.log(this.currentEl);
22504 //Roo.log(this.currentEl.contains(dom));
22505 if (this.currentEl == el) {
22508 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22516 if (this.currentTip.el) {
22517 this.currentTip.el.hide(); // force hiding...
22522 // you can not look for children, as if el is the body.. then everythign is the child..
22523 if (!el.attr('tooltip')) { //
22524 if (!el.select("[tooltip]").elements.length) {
22527 // is the mouse over this child...?
22528 bindEl = el.select("[tooltip]").first();
22529 var xy = ev.getXY();
22530 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22531 //Roo.log("not in region.");
22534 //Roo.log("child element over..");
22537 this.currentEl = bindEl;
22538 this.currentTip.bind(bindEl);
22539 this.currentRegion = Roo.lib.Region.getRegion(dom);
22540 this.currentTip.enter();
22543 leave : function(ev)
22545 var dom = ev.getTarget();
22546 //Roo.log(['leave',dom]);
22547 if (!this.currentEl) {
22552 if (dom != this.currentEl.dom) {
22555 var xy = ev.getXY();
22556 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22559 // only activate leave if mouse cursor is outside... bounding box..
22564 if (this.currentTip) {
22565 this.currentTip.leave();
22567 //Roo.log('clear currentEl');
22568 this.currentEl = false;
22573 'left' : ['r-l', [-2,0], 'right'],
22574 'right' : ['l-r', [2,0], 'left'],
22575 'bottom' : ['t-b', [0,2], 'top'],
22576 'top' : [ 'b-t', [0,-2], 'bottom']
22582 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22587 delay : null, // can be { show : 300 , hide: 500}
22591 hoverState : null, //???
22593 placement : 'bottom',
22595 getAutoCreate : function(){
22602 cls : 'tooltip-arrow'
22605 cls : 'tooltip-inner'
22612 bind : function(el)
22618 enter : function () {
22620 if (this.timeout != null) {
22621 clearTimeout(this.timeout);
22624 this.hoverState = 'in';
22625 //Roo.log("enter - show");
22626 if (!this.delay || !this.delay.show) {
22631 this.timeout = setTimeout(function () {
22632 if (_t.hoverState == 'in') {
22635 }, this.delay.show);
22639 clearTimeout(this.timeout);
22641 this.hoverState = 'out';
22642 if (!this.delay || !this.delay.hide) {
22648 this.timeout = setTimeout(function () {
22649 //Roo.log("leave - timeout");
22651 if (_t.hoverState == 'out') {
22653 Roo.bootstrap.Tooltip.currentEl = false;
22661 this.render(document.body);
22664 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22666 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22668 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22670 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22672 var placement = typeof this.placement == 'function' ?
22673 this.placement.call(this, this.el, on_el) :
22676 var autoToken = /\s?auto?\s?/i;
22677 var autoPlace = autoToken.test(placement);
22679 placement = placement.replace(autoToken, '') || 'top';
22683 //this.el.setXY([0,0]);
22685 //this.el.dom.style.display='block';
22686 this.el.addClass(placement);
22688 //this.el.appendTo(on_el);
22690 var p = this.getPosition();
22691 var box = this.el.getBox();
22696 var align = Roo.bootstrap.Tooltip.alignment[placement];
22697 this.el.alignTo(this.bindEl, align[0],align[1]);
22698 //var arrow = this.el.select('.arrow',true).first();
22699 //arrow.set(align[2],
22701 this.el.addClass('in fade');
22702 this.hoverState = null;
22704 if (this.el.hasClass('fade')) {
22715 //this.el.setXY([0,0]);
22716 this.el.removeClass('in');
22732 * @class Roo.bootstrap.LocationPicker
22733 * @extends Roo.bootstrap.Component
22734 * Bootstrap LocationPicker class
22735 * @cfg {Number} latitude Position when init default 0
22736 * @cfg {Number} longitude Position when init default 0
22737 * @cfg {Number} zoom default 15
22738 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22739 * @cfg {Boolean} mapTypeControl default false
22740 * @cfg {Boolean} disableDoubleClickZoom default false
22741 * @cfg {Boolean} scrollwheel default true
22742 * @cfg {Boolean} streetViewControl default false
22743 * @cfg {Number} radius default 0
22744 * @cfg {String} locationName
22745 * @cfg {Boolean} draggable default true
22746 * @cfg {Boolean} enableAutocomplete default false
22747 * @cfg {Boolean} enableReverseGeocode default true
22748 * @cfg {String} markerTitle
22751 * Create a new LocationPicker
22752 * @param {Object} config The config object
22756 Roo.bootstrap.LocationPicker = function(config){
22758 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22763 * Fires when the picker initialized.
22764 * @param {Roo.bootstrap.LocationPicker} this
22765 * @param {Google Location} location
22769 * @event positionchanged
22770 * Fires when the picker position changed.
22771 * @param {Roo.bootstrap.LocationPicker} this
22772 * @param {Google Location} location
22774 positionchanged : true,
22777 * Fires when the map resize.
22778 * @param {Roo.bootstrap.LocationPicker} this
22783 * Fires when the map show.
22784 * @param {Roo.bootstrap.LocationPicker} this
22789 * Fires when the map hide.
22790 * @param {Roo.bootstrap.LocationPicker} this
22795 * Fires when click the map.
22796 * @param {Roo.bootstrap.LocationPicker} this
22797 * @param {Map event} e
22801 * @event mapRightClick
22802 * Fires when right click the map.
22803 * @param {Roo.bootstrap.LocationPicker} this
22804 * @param {Map event} e
22806 mapRightClick : true,
22808 * @event markerClick
22809 * Fires when click the marker.
22810 * @param {Roo.bootstrap.LocationPicker} this
22811 * @param {Map event} e
22813 markerClick : true,
22815 * @event markerRightClick
22816 * Fires when right click the marker.
22817 * @param {Roo.bootstrap.LocationPicker} this
22818 * @param {Map event} e
22820 markerRightClick : true,
22822 * @event OverlayViewDraw
22823 * Fires when OverlayView Draw
22824 * @param {Roo.bootstrap.LocationPicker} this
22826 OverlayViewDraw : true,
22828 * @event OverlayViewOnAdd
22829 * Fires when OverlayView Draw
22830 * @param {Roo.bootstrap.LocationPicker} this
22832 OverlayViewOnAdd : true,
22834 * @event OverlayViewOnRemove
22835 * Fires when OverlayView Draw
22836 * @param {Roo.bootstrap.LocationPicker} this
22838 OverlayViewOnRemove : true,
22840 * @event OverlayViewShow
22841 * Fires when OverlayView Draw
22842 * @param {Roo.bootstrap.LocationPicker} this
22843 * @param {Pixel} cpx
22845 OverlayViewShow : true,
22847 * @event OverlayViewHide
22848 * Fires when OverlayView Draw
22849 * @param {Roo.bootstrap.LocationPicker} this
22851 OverlayViewHide : true
22856 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22858 gMapContext: false,
22864 mapTypeControl: false,
22865 disableDoubleClickZoom: false,
22867 streetViewControl: false,
22871 enableAutocomplete: false,
22872 enableReverseGeocode: true,
22875 getAutoCreate: function()
22880 cls: 'roo-location-picker'
22886 initEvents: function(ct, position)
22888 if(!this.el.getWidth() || this.isApplied()){
22892 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22897 initial: function()
22899 if(!this.mapTypeId){
22900 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22903 this.gMapContext = this.GMapContext();
22905 this.initOverlayView();
22907 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22911 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22912 _this.setPosition(_this.gMapContext.marker.position);
22915 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22916 _this.fireEvent('mapClick', this, event);
22920 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22921 _this.fireEvent('mapRightClick', this, event);
22925 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22926 _this.fireEvent('markerClick', this, event);
22930 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22931 _this.fireEvent('markerRightClick', this, event);
22935 this.setPosition(this.gMapContext.location);
22937 this.fireEvent('initial', this, this.gMapContext.location);
22940 initOverlayView: function()
22944 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22948 _this.fireEvent('OverlayViewDraw', _this);
22953 _this.fireEvent('OverlayViewOnAdd', _this);
22956 onRemove: function()
22958 _this.fireEvent('OverlayViewOnRemove', _this);
22961 show: function(cpx)
22963 _this.fireEvent('OverlayViewShow', _this, cpx);
22968 _this.fireEvent('OverlayViewHide', _this);
22974 fromLatLngToContainerPixel: function(event)
22976 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22979 isApplied: function()
22981 return this.getGmapContext() == false ? false : true;
22984 getGmapContext: function()
22986 return this.gMapContext
22989 GMapContext: function()
22991 var position = new google.maps.LatLng(this.latitude, this.longitude);
22993 var _map = new google.maps.Map(this.el.dom, {
22996 mapTypeId: this.mapTypeId,
22997 mapTypeControl: this.mapTypeControl,
22998 disableDoubleClickZoom: this.disableDoubleClickZoom,
22999 scrollwheel: this.scrollwheel,
23000 streetViewControl: this.streetViewControl,
23001 locationName: this.locationName,
23002 draggable: this.draggable,
23003 enableAutocomplete: this.enableAutocomplete,
23004 enableReverseGeocode: this.enableReverseGeocode
23007 var _marker = new google.maps.Marker({
23008 position: position,
23010 title: this.markerTitle,
23011 draggable: this.draggable
23018 location: position,
23019 radius: this.radius,
23020 locationName: this.locationName,
23021 addressComponents: {
23022 formatted_address: null,
23023 addressLine1: null,
23024 addressLine2: null,
23026 streetNumber: null,
23030 stateOrProvince: null
23033 domContainer: this.el.dom,
23034 geodecoder: new google.maps.Geocoder()
23038 drawCircle: function(center, radius, options)
23040 if (this.gMapContext.circle != null) {
23041 this.gMapContext.circle.setMap(null);
23045 options = Roo.apply({}, options, {
23046 strokeColor: "#0000FF",
23047 strokeOpacity: .35,
23049 fillColor: "#0000FF",
23053 options.map = this.gMapContext.map;
23054 options.radius = radius;
23055 options.center = center;
23056 this.gMapContext.circle = new google.maps.Circle(options);
23057 return this.gMapContext.circle;
23063 setPosition: function(location)
23065 this.gMapContext.location = location;
23066 this.gMapContext.marker.setPosition(location);
23067 this.gMapContext.map.panTo(location);
23068 this.drawCircle(location, this.gMapContext.radius, {});
23072 if (this.gMapContext.settings.enableReverseGeocode) {
23073 this.gMapContext.geodecoder.geocode({
23074 latLng: this.gMapContext.location
23075 }, function(results, status) {
23077 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23078 _this.gMapContext.locationName = results[0].formatted_address;
23079 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23081 _this.fireEvent('positionchanged', this, location);
23088 this.fireEvent('positionchanged', this, location);
23093 google.maps.event.trigger(this.gMapContext.map, "resize");
23095 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23097 this.fireEvent('resize', this);
23100 setPositionByLatLng: function(latitude, longitude)
23102 this.setPosition(new google.maps.LatLng(latitude, longitude));
23105 getCurrentPosition: function()
23108 latitude: this.gMapContext.location.lat(),
23109 longitude: this.gMapContext.location.lng()
23113 getAddressName: function()
23115 return this.gMapContext.locationName;
23118 getAddressComponents: function()
23120 return this.gMapContext.addressComponents;
23123 address_component_from_google_geocode: function(address_components)
23127 for (var i = 0; i < address_components.length; i++) {
23128 var component = address_components[i];
23129 if (component.types.indexOf("postal_code") >= 0) {
23130 result.postalCode = component.short_name;
23131 } else if (component.types.indexOf("street_number") >= 0) {
23132 result.streetNumber = component.short_name;
23133 } else if (component.types.indexOf("route") >= 0) {
23134 result.streetName = component.short_name;
23135 } else if (component.types.indexOf("neighborhood") >= 0) {
23136 result.city = component.short_name;
23137 } else if (component.types.indexOf("locality") >= 0) {
23138 result.city = component.short_name;
23139 } else if (component.types.indexOf("sublocality") >= 0) {
23140 result.district = component.short_name;
23141 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23142 result.stateOrProvince = component.short_name;
23143 } else if (component.types.indexOf("country") >= 0) {
23144 result.country = component.short_name;
23148 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23149 result.addressLine2 = "";
23153 setZoomLevel: function(zoom)
23155 this.gMapContext.map.setZoom(zoom);
23168 this.fireEvent('show', this);
23179 this.fireEvent('hide', this);
23184 Roo.apply(Roo.bootstrap.LocationPicker, {
23186 OverlayView : function(map, options)
23188 options = options || {};
23202 * @class Roo.bootstrap.Alert
23203 * @extends Roo.bootstrap.Component
23204 * Bootstrap Alert class
23205 * @cfg {String} title The title of alert
23206 * @cfg {String} html The content of alert
23207 * @cfg {String} weight ( success | info | warning | danger )
23208 * @cfg {String} faicon font-awesomeicon
23211 * Create a new alert
23212 * @param {Object} config The config object
23216 Roo.bootstrap.Alert = function(config){
23217 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23221 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23228 getAutoCreate : function()
23237 cls : 'roo-alert-icon'
23242 cls : 'roo-alert-title',
23247 cls : 'roo-alert-text',
23254 cfg.cn[0].cls += ' fa ' + this.faicon;
23258 cfg.cls += ' alert-' + this.weight;
23264 initEvents: function()
23266 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23269 setTitle : function(str)
23271 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23274 setText : function(str)
23276 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23279 setWeight : function(weight)
23282 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23285 this.weight = weight;
23287 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23290 setIcon : function(icon)
23293 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23298 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);