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.
1331 * Create a new Input
1332 * @param {Object} config The config object
1335 Roo.bootstrap.Img = function(config){
1336 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1342 * The img click event for the img.
1343 * @param {Roo.EventObject} e
1349 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1351 imgResponsive: true,
1357 getAutoCreate : function(){
1361 cls: (this.imgResponsive) ? 'img-responsive' : '',
1365 cfg.html = this.html || cfg.html;
1367 cfg.src = this.src || cfg.src;
1369 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1370 cfg.cls += ' img-' + this.border;
1387 a.target = this.target;
1393 return (this.href) ? a : cfg;
1396 initEvents: function() {
1399 this.el.on('click', this.onClick, this);
1403 onClick : function(e)
1405 Roo.log('img onclick');
1406 this.fireEvent('click', this, e);
1420 * @class Roo.bootstrap.Link
1421 * @extends Roo.bootstrap.Component
1422 * Bootstrap Link Class
1423 * @cfg {String} alt image alternative text
1424 * @cfg {String} href a tag href
1425 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1426 * @cfg {String} html the content of the link.
1427 * @cfg {String} anchor name for the anchor link
1429 * @cfg {Boolean} preventDefault (true | false) default false
1433 * Create a new Input
1434 * @param {Object} config The config object
1437 Roo.bootstrap.Link = function(config){
1438 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1444 * The img click event for the img.
1445 * @param {Roo.EventObject} e
1451 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1455 preventDefault: false,
1459 getAutoCreate : function()
1465 // anchor's do not require html/href...
1466 if (this.anchor === false) {
1467 cfg.html = this.html || 'html-missing';
1468 cfg.href = this.href || '#';
1470 cfg.name = this.anchor;
1471 if (this.html !== false) {
1472 cfg.html = this.html;
1474 if (this.href !== false) {
1475 cfg.href = this.href;
1479 if(this.alt !== false){
1484 if(this.target !== false) {
1485 cfg.target = this.target;
1491 initEvents: function() {
1493 if(!this.href || this.preventDefault){
1494 this.el.on('click', this.onClick, this);
1498 onClick : function(e)
1500 if(this.preventDefault){
1503 //Roo.log('img onclick');
1504 this.fireEvent('click', this, e);
1517 * @class Roo.bootstrap.Header
1518 * @extends Roo.bootstrap.Component
1519 * Bootstrap Header class
1520 * @cfg {String} html content of header
1521 * @cfg {Number} level (1|2|3|4|5|6) default 1
1524 * Create a new Header
1525 * @param {Object} config The config object
1529 Roo.bootstrap.Header = function(config){
1530 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1533 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1541 getAutoCreate : function(){
1546 tag: 'h' + (1 *this.level),
1547 html: this.html || ''
1559 * Ext JS Library 1.1.1
1560 * Copyright(c) 2006-2007, Ext JS, LLC.
1562 * Originally Released Under LGPL - original licence link has changed is not relivant.
1565 * <script type="text/javascript">
1569 * @class Roo.bootstrap.MenuMgr
1570 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1573 Roo.bootstrap.MenuMgr = function(){
1574 var menus, active, groups = {}, attached = false, lastShow = new Date();
1576 // private - called when first menu is created
1579 active = new Roo.util.MixedCollection();
1580 Roo.get(document).addKeyListener(27, function(){
1581 if(active.length > 0){
1589 if(active && active.length > 0){
1590 var c = active.clone();
1600 if(active.length < 1){
1601 Roo.get(document).un("mouseup", onMouseDown);
1609 var last = active.last();
1610 lastShow = new Date();
1613 Roo.get(document).on("mouseup", onMouseDown);
1618 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1619 m.parentMenu.activeChild = m;
1620 }else if(last && last.isVisible()){
1621 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1626 function onBeforeHide(m){
1628 m.activeChild.hide();
1630 if(m.autoHideTimer){
1631 clearTimeout(m.autoHideTimer);
1632 delete m.autoHideTimer;
1637 function onBeforeShow(m){
1638 var pm = m.parentMenu;
1639 if(!pm && !m.allowOtherMenus){
1641 }else if(pm && pm.activeChild && active != m){
1642 pm.activeChild.hide();
1646 // private this should really trigger on mouseup..
1647 function onMouseDown(e){
1648 Roo.log("on Mouse Up");
1649 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1659 function onBeforeCheck(mi, state){
1661 var g = groups[mi.group];
1662 for(var i = 0, l = g.length; i < l; i++){
1664 g[i].setChecked(false);
1673 * Hides all menus that are currently visible
1675 hideAll : function(){
1680 register : function(menu){
1684 menus[menu.id] = menu;
1685 menu.on("beforehide", onBeforeHide);
1686 menu.on("hide", onHide);
1687 menu.on("beforeshow", onBeforeShow);
1688 menu.on("show", onShow);
1690 if(g && menu.events["checkchange"]){
1694 groups[g].push(menu);
1695 menu.on("checkchange", onCheck);
1700 * Returns a {@link Roo.menu.Menu} object
1701 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1702 * be used to generate and return a new Menu instance.
1704 get : function(menu){
1705 if(typeof menu == "string"){ // menu id
1707 }else if(menu.events){ // menu instance
1710 /*else if(typeof menu.length == 'number'){ // array of menu items?
1711 return new Roo.bootstrap.Menu({items:menu});
1712 }else{ // otherwise, must be a config
1713 return new Roo.bootstrap.Menu(menu);
1720 unregister : function(menu){
1721 delete menus[menu.id];
1722 menu.un("beforehide", onBeforeHide);
1723 menu.un("hide", onHide);
1724 menu.un("beforeshow", onBeforeShow);
1725 menu.un("show", onShow);
1727 if(g && menu.events["checkchange"]){
1728 groups[g].remove(menu);
1729 menu.un("checkchange", onCheck);
1734 registerCheckable : function(menuItem){
1735 var g = menuItem.group;
1740 groups[g].push(menuItem);
1741 menuItem.on("beforecheckchange", onBeforeCheck);
1746 unregisterCheckable : function(menuItem){
1747 var g = menuItem.group;
1749 groups[g].remove(menuItem);
1750 menuItem.un("beforecheckchange", onBeforeCheck);
1762 * @class Roo.bootstrap.Menu
1763 * @extends Roo.bootstrap.Component
1764 * Bootstrap Menu class - container for MenuItems
1765 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1769 * @param {Object} config The config object
1773 Roo.bootstrap.Menu = function(config){
1774 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1775 if (this.registerMenu) {
1776 Roo.bootstrap.MenuMgr.register(this);
1781 * Fires before this menu is displayed
1782 * @param {Roo.menu.Menu} this
1787 * Fires before this menu is hidden
1788 * @param {Roo.menu.Menu} this
1793 * Fires after this menu is displayed
1794 * @param {Roo.menu.Menu} this
1799 * Fires after this menu is hidden
1800 * @param {Roo.menu.Menu} this
1805 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1806 * @param {Roo.menu.Menu} this
1807 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1808 * @param {Roo.EventObject} e
1813 * Fires when the mouse is hovering over this menu
1814 * @param {Roo.menu.Menu} this
1815 * @param {Roo.EventObject} e
1816 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1821 * Fires when the mouse exits this menu
1822 * @param {Roo.menu.Menu} this
1823 * @param {Roo.EventObject} e
1824 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1829 * Fires when a menu item contained in this menu is clicked
1830 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1831 * @param {Roo.EventObject} e
1835 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1838 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1842 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1845 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1847 registerMenu : true,
1849 menuItems :false, // stores the menu items..
1855 getChildContainer : function() {
1859 getAutoCreate : function(){
1861 //if (['right'].indexOf(this.align)!==-1) {
1862 // cfg.cn[1].cls += ' pull-right'
1868 cls : 'dropdown-menu' ,
1869 style : 'z-index:1000'
1873 if (this.type === 'submenu') {
1874 cfg.cls = 'submenu active';
1876 if (this.type === 'treeview') {
1877 cfg.cls = 'treeview-menu';
1882 initEvents : function() {
1884 // Roo.log("ADD event");
1885 // Roo.log(this.triggerEl.dom);
1886 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1888 this.triggerEl.addClass('dropdown-toggle');
1889 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1891 this.el.on("mouseover", this.onMouseOver, this);
1892 this.el.on("mouseout", this.onMouseOut, this);
1896 findTargetItem : function(e){
1897 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1901 //Roo.log(t); Roo.log(t.id);
1903 //Roo.log(this.menuitems);
1904 return this.menuitems.get(t.id);
1906 //return this.items.get(t.menuItemId);
1911 onClick : function(e){
1912 Roo.log("menu.onClick");
1913 var t = this.findTargetItem(e);
1914 if(!t || t.isContainer){
1919 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1920 if(t == this.activeItem && t.shouldDeactivate(e)){
1921 this.activeItem.deactivate();
1922 delete this.activeItem;
1926 this.setActiveItem(t, true);
1934 Roo.log('pass click event');
1938 this.fireEvent("click", this, t, e);
1942 onMouseOver : function(e){
1943 var t = this.findTargetItem(e);
1946 // if(t.canActivate && !t.disabled){
1947 // this.setActiveItem(t, true);
1951 this.fireEvent("mouseover", this, e, t);
1953 isVisible : function(){
1954 return !this.hidden;
1956 onMouseOut : function(e){
1957 var t = this.findTargetItem(e);
1960 // if(t == this.activeItem && t.shouldDeactivate(e)){
1961 // this.activeItem.deactivate();
1962 // delete this.activeItem;
1965 this.fireEvent("mouseout", this, e, t);
1970 * Displays this menu relative to another element
1971 * @param {String/HTMLElement/Roo.Element} element The element to align to
1972 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1973 * the element (defaults to this.defaultAlign)
1974 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1976 show : function(el, pos, parentMenu){
1977 this.parentMenu = parentMenu;
1981 this.fireEvent("beforeshow", this);
1982 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1985 * Displays this menu at a specific xy position
1986 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1987 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1989 showAt : function(xy, parentMenu, /* private: */_e){
1990 this.parentMenu = parentMenu;
1995 this.fireEvent("beforeshow", this);
1996 //xy = this.el.adjustForConstraints(xy);
2000 this.hideMenuItems();
2001 this.hidden = false;
2002 this.triggerEl.addClass('open');
2004 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2005 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2010 this.fireEvent("show", this);
2016 this.doFocus.defer(50, this);
2020 doFocus : function(){
2022 this.focusEl.focus();
2027 * Hides this menu and optionally all parent menus
2028 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2030 hide : function(deep){
2032 this.hideMenuItems();
2033 if(this.el && this.isVisible()){
2034 this.fireEvent("beforehide", this);
2035 if(this.activeItem){
2036 this.activeItem.deactivate();
2037 this.activeItem = null;
2039 this.triggerEl.removeClass('open');;
2041 this.fireEvent("hide", this);
2043 if(deep === true && this.parentMenu){
2044 this.parentMenu.hide(true);
2048 onTriggerPress : function(e)
2051 Roo.log('trigger press');
2052 //Roo.log(e.getTarget());
2053 // Roo.log(this.triggerEl.dom);
2054 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2058 if (this.isVisible()) {
2063 this.show(this.triggerEl, false, false);
2072 hideMenuItems : function()
2074 //$(backdrop).remove()
2075 Roo.select('.open',true).each(function(aa) {
2077 aa.removeClass('open');
2078 //var parent = getParent($(this))
2079 //var relatedTarget = { relatedTarget: this }
2081 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2082 //if (e.isDefaultPrevented()) return
2083 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2086 addxtypeChild : function (tree, cntr) {
2087 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2089 this.menuitems.add(comp);
2110 * @class Roo.bootstrap.MenuItem
2111 * @extends Roo.bootstrap.Component
2112 * Bootstrap MenuItem class
2113 * @cfg {String} html the menu label
2114 * @cfg {String} href the link
2115 * @cfg {Boolean} preventDefault (true | false) default true
2116 * @cfg {Boolean} isContainer (true | false) default false
2120 * Create a new MenuItem
2121 * @param {Object} config The config object
2125 Roo.bootstrap.MenuItem = function(config){
2126 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2131 * The raw click event for the entire grid.
2132 * @param {Roo.bootstrap.MenuItem} this
2133 * @param {Roo.EventObject} e
2139 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2143 preventDefault: true,
2144 isContainer : false,
2146 getAutoCreate : function(){
2148 if(this.isContainer){
2151 cls: 'dropdown-menu-item'
2157 cls: 'dropdown-menu-item',
2166 if (this.parent().type == 'treeview') {
2167 cfg.cls = 'treeview-menu';
2170 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2171 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2175 initEvents: function() {
2177 //this.el.select('a').on('click', this.onClick, this);
2180 onClick : function(e)
2182 Roo.log('item on click ');
2183 //if(this.preventDefault){
2184 // e.preventDefault();
2186 //this.parent().hideMenuItems();
2188 this.fireEvent('click', this, e);
2207 * @class Roo.bootstrap.MenuSeparator
2208 * @extends Roo.bootstrap.Component
2209 * Bootstrap MenuSeparator class
2212 * Create a new MenuItem
2213 * @param {Object} config The config object
2217 Roo.bootstrap.MenuSeparator = function(config){
2218 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2221 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2223 getAutoCreate : function(){
2242 * @class Roo.bootstrap.Modal
2243 * @extends Roo.bootstrap.Component
2244 * Bootstrap Modal class
2245 * @cfg {String} title Title of dialog
2246 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2247 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2248 * @cfg {Boolean} specificTitle default false
2249 * @cfg {Array} buttons Array of buttons or standard button set..
2250 * @cfg {String} buttonPosition (left|right|center) default right
2251 * @cfg {Boolean} animate default true
2252 * @cfg {Boolean} allow_close default true
2255 * Create a new Modal Dialog
2256 * @param {Object} config The config object
2259 Roo.bootstrap.Modal = function(config){
2260 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2265 * The raw btnclick event for the button
2266 * @param {Roo.EventObject} e
2270 this.buttons = this.buttons || [];
2273 this.tmpl = Roo.factory(this.tmpl);
2278 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2280 title : 'test dialog',
2290 specificTitle: false,
2292 buttonPosition: 'right',
2306 onRender : function(ct, position)
2308 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2311 var cfg = Roo.apply({}, this.getAutoCreate());
2314 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2316 //if (!cfg.name.length) {
2320 cfg.cls += ' ' + this.cls;
2323 cfg.style = this.style;
2325 this.el = Roo.get(document.body).createChild(cfg, position);
2327 //var type = this.el.dom.type;
2332 if(this.tabIndex !== undefined){
2333 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2337 this.bodyEl = this.el.select('.modal-body',true).first();
2338 this.closeEl = this.el.select('.modal-header .close', true).first();
2339 this.footerEl = this.el.select('.modal-footer',true).first();
2340 this.titleEl = this.el.select('.modal-title',true).first();
2344 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2345 this.maskEl.enableDisplayMode("block");
2347 //this.el.addClass("x-dlg-modal");
2349 if (this.buttons.length) {
2350 Roo.each(this.buttons, function(bb) {
2351 b = Roo.apply({}, bb);
2352 b.xns = b.xns || Roo.bootstrap;
2353 b.xtype = b.xtype || 'Button';
2354 if (typeof(b.listeners) == 'undefined') {
2355 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2358 var btn = Roo.factory(b);
2360 btn.onRender(this.el.select('.modal-footer div').first());
2364 // render the children.
2367 if(typeof(this.items) != 'undefined'){
2368 var items = this.items;
2371 for(var i =0;i < items.length;i++) {
2372 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2376 this.items = nitems;
2378 // where are these used - they used to be body/close/footer
2382 //this.el.addClass([this.fieldClass, this.cls]);
2385 getAutoCreate : function(){
2390 html : this.html || ''
2395 cls : 'modal-title',
2399 if(this.specificTitle){
2405 if (this.allow_close) {
2416 style : 'display: none',
2419 cls: "modal-dialog",
2422 cls : "modal-content",
2425 cls : 'modal-header',
2430 cls : 'modal-footer',
2434 cls: 'btn-' + this.buttonPosition
2451 modal.cls += ' fade';
2457 getChildContainer : function() {
2462 getButtonContainer : function() {
2463 return this.el.select('.modal-footer div',true).first();
2466 initEvents : function()
2468 if (this.allow_close) {
2469 this.closeEl.on('click', this.hide, this);
2475 if (!this.rendered) {
2479 this.el.setStyle('display', 'block');
2483 (function(){ _this.el.addClass('in'); }).defer(50);
2485 this.el.addClass('in');
2488 // not sure how we can show data in here..
2490 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2493 Roo.get(document.body).addClass("x-body-masked");
2494 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2496 this.el.setStyle('zIndex', '10001');
2498 this.fireEvent('show', this);
2505 Roo.get(document.body).removeClass("x-body-masked");
2506 this.el.removeClass('in');
2510 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2512 this.el.setStyle('display', 'none');
2515 this.fireEvent('hide', this);
2518 addButton : function(str, cb)
2522 var b = Roo.apply({}, { html : str } );
2523 b.xns = b.xns || Roo.bootstrap;
2524 b.xtype = b.xtype || 'Button';
2525 if (typeof(b.listeners) == 'undefined') {
2526 b.listeners = { click : cb.createDelegate(this) };
2529 var btn = Roo.factory(b);
2531 btn.onRender(this.el.select('.modal-footer div').first());
2537 setDefaultButton : function(btn)
2539 //this.el.select('.modal-footer').()
2541 resizeTo: function(w,h)
2545 setContentSize : function(w, h)
2549 onButtonClick: function(btn,e)
2552 this.fireEvent('btnclick', btn.name, e);
2555 * Set the title of the Dialog
2556 * @param {String} str new Title
2558 setTitle: function(str) {
2559 this.titleEl.dom.innerHTML = str;
2562 * Set the body of the Dialog
2563 * @param {String} str new Title
2565 setBody: function(str) {
2566 this.bodyEl.dom.innerHTML = str;
2569 * Set the body of the Dialog using the template
2570 * @param {Obj} data - apply this data to the template and replace the body contents.
2572 applyBody: function(obj)
2575 Roo.log("Error - using apply Body without a template");
2578 this.tmpl.overwrite(this.bodyEl, obj);
2584 Roo.apply(Roo.bootstrap.Modal, {
2586 * Button config that displays a single OK button
2595 * Button config that displays Yes and No buttons
2611 * Button config that displays OK and Cancel buttons
2626 * Button config that displays Yes, No and Cancel buttons
2649 * messagebox - can be used as a replace
2653 * @class Roo.MessageBox
2654 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2658 Roo.Msg.alert('Status', 'Changes saved successfully.');
2660 // Prompt for user data:
2661 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2663 // process text value...
2667 // Show a dialog using config options:
2669 title:'Save Changes?',
2670 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2671 buttons: Roo.Msg.YESNOCANCEL,
2678 Roo.bootstrap.MessageBox = function(){
2679 var dlg, opt, mask, waitTimer;
2680 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2681 var buttons, activeTextEl, bwidth;
2685 var handleButton = function(button){
2687 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2691 var handleHide = function(){
2693 dlg.el.removeClass(opt.cls);
2696 // Roo.TaskMgr.stop(waitTimer);
2697 // waitTimer = null;
2702 var updateButtons = function(b){
2705 buttons["ok"].hide();
2706 buttons["cancel"].hide();
2707 buttons["yes"].hide();
2708 buttons["no"].hide();
2709 //dlg.footer.dom.style.display = 'none';
2712 dlg.footerEl.dom.style.display = '';
2713 for(var k in buttons){
2714 if(typeof buttons[k] != "function"){
2717 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2718 width += buttons[k].el.getWidth()+15;
2728 var handleEsc = function(d, k, e){
2729 if(opt && opt.closable !== false){
2739 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2740 * @return {Roo.BasicDialog} The BasicDialog element
2742 getDialog : function(){
2744 dlg = new Roo.bootstrap.Modal( {
2747 //constraintoviewport:false,
2749 //collapsible : false,
2754 //buttonAlign:"center",
2755 closeClick : function(){
2756 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2759 handleButton("cancel");
2764 dlg.on("hide", handleHide);
2766 //dlg.addKeyListener(27, handleEsc);
2768 this.buttons = buttons;
2769 var bt = this.buttonText;
2770 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2771 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2772 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2773 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2775 bodyEl = dlg.bodyEl.createChild({
2777 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2778 '<textarea class="roo-mb-textarea"></textarea>' +
2779 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2781 msgEl = bodyEl.dom.firstChild;
2782 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2783 textboxEl.enableDisplayMode();
2784 textboxEl.addKeyListener([10,13], function(){
2785 if(dlg.isVisible() && opt && opt.buttons){
2788 }else if(opt.buttons.yes){
2789 handleButton("yes");
2793 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2794 textareaEl.enableDisplayMode();
2795 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2796 progressEl.enableDisplayMode();
2797 var pf = progressEl.dom.firstChild;
2799 pp = Roo.get(pf.firstChild);
2800 pp.setHeight(pf.offsetHeight);
2808 * Updates the message box body text
2809 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2810 * the XHTML-compliant non-breaking space character '&#160;')
2811 * @return {Roo.MessageBox} This message box
2813 updateText : function(text){
2814 if(!dlg.isVisible() && !opt.width){
2815 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2817 msgEl.innerHTML = text || ' ';
2819 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2820 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2822 Math.min(opt.width || cw , this.maxWidth),
2823 Math.max(opt.minWidth || this.minWidth, bwidth)
2826 activeTextEl.setWidth(w);
2828 if(dlg.isVisible()){
2829 dlg.fixedcenter = false;
2831 // to big, make it scroll. = But as usual stupid IE does not support
2834 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2835 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2836 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2838 bodyEl.dom.style.height = '';
2839 bodyEl.dom.style.overflowY = '';
2842 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2844 bodyEl.dom.style.overflowX = '';
2847 dlg.setContentSize(w, bodyEl.getHeight());
2848 if(dlg.isVisible()){
2849 dlg.fixedcenter = true;
2855 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2856 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2857 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2858 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2859 * @return {Roo.MessageBox} This message box
2861 updateProgress : function(value, text){
2863 this.updateText(text);
2865 if (pp) { // weird bug on my firefox - for some reason this is not defined
2866 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2872 * Returns true if the message box is currently displayed
2873 * @return {Boolean} True if the message box is visible, else false
2875 isVisible : function(){
2876 return dlg && dlg.isVisible();
2880 * Hides the message box if it is displayed
2883 if(this.isVisible()){
2889 * Displays a new message box, or reinitializes an existing message box, based on the config options
2890 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2891 * The following config object properties are supported:
2893 Property Type Description
2894 ---------- --------------- ------------------------------------------------------------------------------------
2895 animEl String/Element An id or Element from which the message box should animate as it opens and
2896 closes (defaults to undefined)
2897 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2898 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2899 closable Boolean False to hide the top-right close button (defaults to true). Note that
2900 progress and wait dialogs will ignore this property and always hide the
2901 close button as they can only be closed programmatically.
2902 cls String A custom CSS class to apply to the message box element
2903 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2904 displayed (defaults to 75)
2905 fn Function A callback function to execute after closing the dialog. The arguments to the
2906 function will be btn (the name of the button that was clicked, if applicable,
2907 e.g. "ok"), and text (the value of the active text field, if applicable).
2908 Progress and wait dialogs will ignore this option since they do not respond to
2909 user actions and can only be closed programmatically, so any required function
2910 should be called by the same code after it closes the dialog.
2911 icon String A CSS class that provides a background image to be used as an icon for
2912 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2913 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2914 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2915 modal Boolean False to allow user interaction with the page while the message box is
2916 displayed (defaults to true)
2917 msg String A string that will replace the existing message box body text (defaults
2918 to the XHTML-compliant non-breaking space character ' ')
2919 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2920 progress Boolean True to display a progress bar (defaults to false)
2921 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2922 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2923 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2924 title String The title text
2925 value String The string value to set into the active textbox element if displayed
2926 wait Boolean True to display a progress bar (defaults to false)
2927 width Number The width of the dialog in pixels
2934 msg: 'Please enter your address:',
2936 buttons: Roo.MessageBox.OKCANCEL,
2939 animEl: 'addAddressBtn'
2942 * @param {Object} config Configuration options
2943 * @return {Roo.MessageBox} This message box
2945 show : function(options)
2948 // this causes nightmares if you show one dialog after another
2949 // especially on callbacks..
2951 if(this.isVisible()){
2954 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2955 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2956 Roo.log("New Dialog Message:" + options.msg )
2957 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2958 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2961 var d = this.getDialog();
2963 d.setTitle(opt.title || " ");
2964 d.closeEl.setDisplayed(opt.closable !== false);
2965 activeTextEl = textboxEl;
2966 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2971 textareaEl.setHeight(typeof opt.multiline == "number" ?
2972 opt.multiline : this.defaultTextHeight);
2973 activeTextEl = textareaEl;
2982 progressEl.setDisplayed(opt.progress === true);
2983 this.updateProgress(0);
2984 activeTextEl.dom.value = opt.value || "";
2986 dlg.setDefaultButton(activeTextEl);
2988 var bs = opt.buttons;
2992 }else if(bs && bs.yes){
2993 db = buttons["yes"];
2995 dlg.setDefaultButton(db);
2997 bwidth = updateButtons(opt.buttons);
2998 this.updateText(opt.msg);
3000 d.el.addClass(opt.cls);
3002 d.proxyDrag = opt.proxyDrag === true;
3003 d.modal = opt.modal !== false;
3004 d.mask = opt.modal !== false ? mask : false;
3006 // force it to the end of the z-index stack so it gets a cursor in FF
3007 document.body.appendChild(dlg.el.dom);
3008 d.animateTarget = null;
3009 d.show(options.animEl);
3015 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3016 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3017 * and closing the message box when the process is complete.
3018 * @param {String} title The title bar text
3019 * @param {String} msg The message box body text
3020 * @return {Roo.MessageBox} This message box
3022 progress : function(title, msg){
3029 minWidth: this.minProgressWidth,
3036 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3037 * If a callback function is passed it will be called after the user clicks the button, and the
3038 * id of the button that was clicked will be passed as the only parameter to the callback
3039 * (could also be the top-right close button).
3040 * @param {String} title The title bar text
3041 * @param {String} msg The message box body text
3042 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3043 * @param {Object} scope (optional) The scope of the callback function
3044 * @return {Roo.MessageBox} This message box
3046 alert : function(title, msg, fn, scope){
3059 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3060 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3061 * You are responsible for closing the message box when the process is complete.
3062 * @param {String} msg The message box body text
3063 * @param {String} title (optional) The title bar text
3064 * @return {Roo.MessageBox} This message box
3066 wait : function(msg, title){
3077 waitTimer = Roo.TaskMgr.start({
3079 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3087 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3088 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3089 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3090 * @param {String} title The title bar text
3091 * @param {String} msg The message box body text
3092 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3093 * @param {Object} scope (optional) The scope of the callback function
3094 * @return {Roo.MessageBox} This message box
3096 confirm : function(title, msg, fn, scope){
3100 buttons: this.YESNO,
3109 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3110 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3111 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3112 * (could also be the top-right close button) and the text that was entered will be passed as the two
3113 * parameters to the callback.
3114 * @param {String} title The title bar text
3115 * @param {String} msg The message box body text
3116 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3117 * @param {Object} scope (optional) The scope of the callback function
3118 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3119 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3120 * @return {Roo.MessageBox} This message box
3122 prompt : function(title, msg, fn, scope, multiline){
3126 buttons: this.OKCANCEL,
3131 multiline: multiline,
3138 * Button config that displays a single OK button
3143 * Button config that displays Yes and No buttons
3146 YESNO : {yes:true, no:true},
3148 * Button config that displays OK and Cancel buttons
3151 OKCANCEL : {ok:true, cancel:true},
3153 * Button config that displays Yes, No and Cancel buttons
3156 YESNOCANCEL : {yes:true, no:true, cancel:true},
3159 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3162 defaultTextHeight : 75,
3164 * The maximum width in pixels of the message box (defaults to 600)
3169 * The minimum width in pixels of the message box (defaults to 100)
3174 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3175 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3178 minProgressWidth : 250,
3180 * An object containing the default button text strings that can be overriden for localized language support.
3181 * Supported properties are: ok, cancel, yes and no.
3182 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3195 * Shorthand for {@link Roo.MessageBox}
3197 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3198 Roo.Msg = Roo.Msg || Roo.MessageBox;
3207 * @class Roo.bootstrap.Navbar
3208 * @extends Roo.bootstrap.Component
3209 * Bootstrap Navbar class
3212 * Create a new Navbar
3213 * @param {Object} config The config object
3217 Roo.bootstrap.Navbar = function(config){
3218 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3222 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3231 getAutoCreate : function(){
3234 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3238 initEvents :function ()
3240 //Roo.log(this.el.select('.navbar-toggle',true));
3241 this.el.select('.navbar-toggle',true).on('click', function() {
3242 // Roo.log('click');
3243 this.el.select('.navbar-collapse',true).toggleClass('in');
3251 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3253 var size = this.el.getSize();
3254 this.maskEl.setSize(size.width, size.height);
3255 this.maskEl.enableDisplayMode("block");
3264 getChildContainer : function()
3266 if (this.el.select('.collapse').getCount()) {
3267 return this.el.select('.collapse',true).first();
3300 * @class Roo.bootstrap.NavSimplebar
3301 * @extends Roo.bootstrap.Navbar
3302 * Bootstrap Sidebar class
3304 * @cfg {Boolean} inverse is inverted color
3306 * @cfg {String} type (nav | pills | tabs)
3307 * @cfg {Boolean} arrangement stacked | justified
3308 * @cfg {String} align (left | right) alignment
3310 * @cfg {Boolean} main (true|false) main nav bar? default false
3311 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3313 * @cfg {String} tag (header|footer|nav|div) default is nav
3319 * Create a new Sidebar
3320 * @param {Object} config The config object
3324 Roo.bootstrap.NavSimplebar = function(config){
3325 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3328 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3344 getAutoCreate : function(){
3348 tag : this.tag || 'div',
3361 this.type = this.type || 'nav';
3362 if (['tabs','pills'].indexOf(this.type)!==-1) {
3363 cfg.cn[0].cls += ' nav-' + this.type
3367 if (this.type!=='nav') {
3368 Roo.log('nav type must be nav/tabs/pills')
3370 cfg.cn[0].cls += ' navbar-nav'
3376 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3377 cfg.cn[0].cls += ' nav-' + this.arrangement;
3381 if (this.align === 'right') {
3382 cfg.cn[0].cls += ' navbar-right';
3386 cfg.cls += ' navbar-inverse';
3413 * @class Roo.bootstrap.NavHeaderbar
3414 * @extends Roo.bootstrap.NavSimplebar
3415 * Bootstrap Sidebar class
3417 * @cfg {String} brand what is brand
3418 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3419 * @cfg {String} brand_href href of the brand
3420 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3421 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3422 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3423 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3426 * Create a new Sidebar
3427 * @param {Object} config The config object
3431 Roo.bootstrap.NavHeaderbar = function(config){
3432 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3436 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3443 desktopCenter : false,
3446 getAutoCreate : function(){
3449 tag: this.nav || 'nav',
3456 if (this.desktopCenter) {
3457 cn.push({cls : 'container', cn : []});
3464 cls: 'navbar-header',
3469 cls: 'navbar-toggle',
3470 'data-toggle': 'collapse',
3475 html: 'Toggle navigation'
3497 cls: 'collapse navbar-collapse',
3501 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3503 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3504 cfg.cls += ' navbar-' + this.position;
3506 // tag can override this..
3508 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3511 if (this.brand !== '') {
3514 href: this.brand_href ? this.brand_href : '#',
3515 cls: 'navbar-brand',
3523 cfg.cls += ' main-nav';
3531 getHeaderChildContainer : function()
3533 if (this.el.select('.navbar-header').getCount()) {
3534 return this.el.select('.navbar-header',true).first();
3537 return this.getChildContainer();
3541 initEvents : function()
3543 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3545 if (this.autohide) {
3550 Roo.get(document).on('scroll',function(e) {
3551 var ns = Roo.get(document).getScroll().top;
3552 var os = prevScroll;
3556 ft.removeClass('slideDown');
3557 ft.addClass('slideUp');
3560 ft.removeClass('slideUp');
3561 ft.addClass('slideDown');
3582 * @class Roo.bootstrap.NavSidebar
3583 * @extends Roo.bootstrap.Navbar
3584 * Bootstrap Sidebar class
3587 * Create a new Sidebar
3588 * @param {Object} config The config object
3592 Roo.bootstrap.NavSidebar = function(config){
3593 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3596 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3598 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3600 getAutoCreate : function(){
3605 cls: 'sidebar sidebar-nav'
3627 * @class Roo.bootstrap.NavGroup
3628 * @extends Roo.bootstrap.Component
3629 * Bootstrap NavGroup class
3630 * @cfg {String} align left | right
3631 * @cfg {Boolean} inverse false | true
3632 * @cfg {String} type (nav|pills|tab) default nav
3633 * @cfg {String} navId - reference Id for navbar.
3637 * Create a new nav group
3638 * @param {Object} config The config object
3641 Roo.bootstrap.NavGroup = function(config){
3642 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3645 Roo.bootstrap.NavGroup.register(this);
3649 * Fires when the active item changes
3650 * @param {Roo.bootstrap.NavGroup} this
3651 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3652 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3659 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3670 getAutoCreate : function()
3672 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3679 if (['tabs','pills'].indexOf(this.type)!==-1) {
3680 cfg.cls += ' nav-' + this.type
3682 if (this.type!=='nav') {
3683 Roo.log('nav type must be nav/tabs/pills')
3685 cfg.cls += ' navbar-nav'
3688 if (this.parent().sidebar) {
3691 cls: 'dashboard-menu sidebar-menu'
3697 if (this.form === true) {
3703 if (this.align === 'right') {
3704 cfg.cls += ' navbar-right';
3706 cfg.cls += ' navbar-left';
3710 if (this.align === 'right') {
3711 cfg.cls += ' navbar-right';
3715 cfg.cls += ' navbar-inverse';
3723 * sets the active Navigation item
3724 * @param {Roo.bootstrap.NavItem} the new current navitem
3726 setActiveItem : function(item)
3729 Roo.each(this.navItems, function(v){
3734 v.setActive(false, true);
3741 item.setActive(true, true);
3742 this.fireEvent('changed', this, item, prev);
3747 * gets the active Navigation item
3748 * @return {Roo.bootstrap.NavItem} the current navitem
3750 getActive : function()
3754 Roo.each(this.navItems, function(v){
3765 indexOfNav : function()
3769 Roo.each(this.navItems, function(v,i){
3780 * adds a Navigation item
3781 * @param {Roo.bootstrap.NavItem} the navitem to add
3783 addItem : function(cfg)
3785 var cn = new Roo.bootstrap.NavItem(cfg);
3787 cn.parentId = this.id;
3788 cn.onRender(this.el, null);
3792 * register a Navigation item
3793 * @param {Roo.bootstrap.NavItem} the navitem to add
3795 register : function(item)
3797 this.navItems.push( item);
3798 item.navId = this.navId;
3803 * clear all the Navigation item
3806 clearAll : function()
3809 this.el.dom.innerHTML = '';
3812 getNavItem: function(tabId)
3815 Roo.each(this.navItems, function(e) {
3816 if (e.tabId == tabId) {
3826 setActiveNext : function()
3828 var i = this.indexOfNav(this.getActive());
3829 if (i > this.navItems.length) {
3832 this.setActiveItem(this.navItems[i+1]);
3834 setActivePrev : function()
3836 var i = this.indexOfNav(this.getActive());
3840 this.setActiveItem(this.navItems[i-1]);
3842 clearWasActive : function(except) {
3843 Roo.each(this.navItems, function(e) {
3844 if (e.tabId != except.tabId && e.was_active) {
3845 e.was_active = false;
3852 getWasActive : function ()
3855 Roo.each(this.navItems, function(e) {
3870 Roo.apply(Roo.bootstrap.NavGroup, {
3874 * register a Navigation Group
3875 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3877 register : function(navgrp)
3879 this.groups[navgrp.navId] = navgrp;
3883 * fetch a Navigation Group based on the navigation ID
3884 * @param {string} the navgroup to add
3885 * @returns {Roo.bootstrap.NavGroup} the navgroup
3887 get: function(navId) {
3888 if (typeof(this.groups[navId]) == 'undefined') {
3890 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3892 return this.groups[navId] ;
3907 * @class Roo.bootstrap.NavItem
3908 * @extends Roo.bootstrap.Component
3909 * Bootstrap Navbar.NavItem class
3910 * @cfg {String} href link to
3911 * @cfg {String} html content of button
3912 * @cfg {String} badge text inside badge
3913 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3914 * @cfg {String} glyphicon name of glyphicon
3915 * @cfg {String} icon name of font awesome icon
3916 * @cfg {Boolean} active Is item active
3917 * @cfg {Boolean} disabled Is item disabled
3919 * @cfg {Boolean} preventDefault (true | false) default false
3920 * @cfg {String} tabId the tab that this item activates.
3921 * @cfg {String} tagtype (a|span) render as a href or span?
3922 * @cfg {Boolean} animateRef (true|false) link to element default false
3925 * Create a new Navbar Item
3926 * @param {Object} config The config object
3928 Roo.bootstrap.NavItem = function(config){
3929 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3934 * The raw click event for the entire grid.
3935 * @param {Roo.EventObject} e
3940 * Fires when the active item active state changes
3941 * @param {Roo.bootstrap.NavItem} this
3942 * @param {boolean} state the new state
3948 * Fires when scroll to element
3949 * @param {Roo.bootstrap.NavItem} this
3950 * @param {Object} options
3951 * @param {Roo.EventObject} e
3959 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3967 preventDefault : false,
3974 getAutoCreate : function(){
3982 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3984 if (this.disabled) {
3985 cfg.cls += ' disabled';
3988 if (this.href || this.html || this.glyphicon || this.icon) {
3992 href : this.href || "#",
3993 html: this.html || ''
3998 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4001 if(this.glyphicon) {
4002 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4007 cfg.cn[0].html += " <span class='caret'></span>";
4011 if (this.badge !== '') {
4013 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4021 initEvents: function()
4023 if (typeof (this.menu) != 'undefined') {
4024 this.menu.parentType = this.xtype;
4025 this.menu.triggerEl = this.el;
4026 this.menu = this.addxtype(Roo.apply({}, this.menu));
4029 this.el.select('a',true).on('click', this.onClick, this);
4031 if(this.tagtype == 'span'){
4032 this.el.select('span',true).on('click', this.onClick, this);
4035 // at this point parent should be available..
4036 this.parent().register(this);
4039 onClick : function(e)
4042 this.preventDefault ||
4049 if (this.disabled) {
4053 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4054 if (tg && tg.transition) {
4055 Roo.log("waiting for the transitionend");
4061 //Roo.log("fire event clicked");
4062 if(this.fireEvent('click', this, e) === false){
4066 if(this.tagtype == 'span'){
4070 //Roo.log(this.href);
4071 var ael = this.el.select('a',true).first();
4074 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4075 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4076 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4077 return; // ignore... - it's a 'hash' to another page.
4081 this.scrollToElement(e);
4085 var p = this.parent();
4087 if (['tabs','pills'].indexOf(p.type)!==-1) {
4088 if (typeof(p.setActiveItem) !== 'undefined') {
4089 p.setActiveItem(this);
4093 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4094 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4095 // remove the collapsed menu expand...
4096 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4100 isActive: function () {
4103 setActive : function(state, fire, is_was_active)
4105 if (this.active && !state & this.navId) {
4106 this.was_active = true;
4107 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4109 nv.clearWasActive(this);
4113 this.active = state;
4116 this.el.removeClass('active');
4117 } else if (!this.el.hasClass('active')) {
4118 this.el.addClass('active');
4121 this.fireEvent('changed', this, state);
4124 // show a panel if it's registered and related..
4126 if (!this.navId || !this.tabId || !state || is_was_active) {
4130 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4134 var pan = tg.getPanelByName(this.tabId);
4138 // if we can not flip to new panel - go back to old nav highlight..
4139 if (false == tg.showPanel(pan)) {
4140 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4142 var onav = nv.getWasActive();
4144 onav.setActive(true, false, true);
4153 // this should not be here...
4154 setDisabled : function(state)
4156 this.disabled = state;
4158 this.el.removeClass('disabled');
4159 } else if (!this.el.hasClass('disabled')) {
4160 this.el.addClass('disabled');
4166 * Fetch the element to display the tooltip on.
4167 * @return {Roo.Element} defaults to this.el
4169 tooltipEl : function()
4171 return this.el.select('' + this.tagtype + '', true).first();
4174 scrollToElement : function(e)
4176 var c = document.body;
4179 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4181 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4182 c = document.documentElement;
4185 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4191 var o = target.calcOffsetsTo(c);
4198 this.fireEvent('scrollto', this, options, e);
4200 Roo.get(c).scrollTo('top', options.value, true);
4213 * <span> icon </span>
4214 * <span> text </span>
4215 * <span>badge </span>
4219 * @class Roo.bootstrap.NavSidebarItem
4220 * @extends Roo.bootstrap.NavItem
4221 * Bootstrap Navbar.NavSidebarItem class
4223 * Create a new Navbar Button
4224 * @param {Object} config The config object
4226 Roo.bootstrap.NavSidebarItem = function(config){
4227 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4232 * The raw click event for the entire grid.
4233 * @param {Roo.EventObject} e
4238 * Fires when the active item active state changes
4239 * @param {Roo.bootstrap.NavSidebarItem} this
4240 * @param {boolean} state the new state
4248 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4251 getAutoCreate : function(){
4256 href : this.href || '#',
4268 html : this.html || ''
4273 cfg.cls += ' active';
4277 if (this.glyphicon || this.icon) {
4278 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4279 a.cn.push({ tag : 'i', cls : c }) ;
4284 if (this.badge !== '') {
4285 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4289 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4290 a.cls += 'dropdown-toggle treeview' ;
4314 * @class Roo.bootstrap.Row
4315 * @extends Roo.bootstrap.Component
4316 * Bootstrap Row class (contains columns...)
4320 * @param {Object} config The config object
4323 Roo.bootstrap.Row = function(config){
4324 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4327 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4329 getAutoCreate : function(){
4348 * @class Roo.bootstrap.Element
4349 * @extends Roo.bootstrap.Component
4350 * Bootstrap Element class
4351 * @cfg {String} html contents of the element
4352 * @cfg {String} tag tag of the element
4353 * @cfg {String} cls class of the element
4354 * @cfg {Boolean} preventDefault (true|false) default false
4355 * @cfg {Boolean} clickable (true|false) default false
4358 * Create a new Element
4359 * @param {Object} config The config object
4362 Roo.bootstrap.Element = function(config){
4363 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4369 * When a element is chick
4370 * @param {Roo.bootstrap.Element} this
4371 * @param {Roo.EventObject} e
4377 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4382 preventDefault: false,
4385 getAutoCreate : function(){
4396 initEvents: function()
4398 Roo.bootstrap.Element.superclass.initEvents.call(this);
4401 this.el.on('click', this.onClick, this);
4406 onClick : function(e)
4408 if(this.preventDefault){
4412 this.fireEvent('click', this, e);
4415 getValue : function()
4417 return this.el.dom.innerHTML;
4420 setValue : function(value)
4422 this.el.dom.innerHTML = value;
4437 * @class Roo.bootstrap.Pagination
4438 * @extends Roo.bootstrap.Component
4439 * Bootstrap Pagination class
4440 * @cfg {String} size xs | sm | md | lg
4441 * @cfg {Boolean} inverse false | true
4444 * Create a new Pagination
4445 * @param {Object} config The config object
4448 Roo.bootstrap.Pagination = function(config){
4449 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4452 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4458 getAutoCreate : function(){
4464 cfg.cls += ' inverse';
4470 cfg.cls += " " + this.cls;
4488 * @class Roo.bootstrap.PaginationItem
4489 * @extends Roo.bootstrap.Component
4490 * Bootstrap PaginationItem class
4491 * @cfg {String} html text
4492 * @cfg {String} href the link
4493 * @cfg {Boolean} preventDefault (true | false) default true
4494 * @cfg {Boolean} active (true | false) default false
4495 * @cfg {Boolean} disabled default false
4499 * Create a new PaginationItem
4500 * @param {Object} config The config object
4504 Roo.bootstrap.PaginationItem = function(config){
4505 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4510 * The raw click event for the entire grid.
4511 * @param {Roo.EventObject} e
4517 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4521 preventDefault: true,
4526 getAutoCreate : function(){
4532 href : this.href ? this.href : '#',
4533 html : this.html ? this.html : ''
4543 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4547 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4553 initEvents: function() {
4555 this.el.on('click', this.onClick, this);
4558 onClick : function(e)
4560 Roo.log('PaginationItem on click ');
4561 if(this.preventDefault){
4569 this.fireEvent('click', this, e);
4585 * @class Roo.bootstrap.Slider
4586 * @extends Roo.bootstrap.Component
4587 * Bootstrap Slider class
4590 * Create a new Slider
4591 * @param {Object} config The config object
4594 Roo.bootstrap.Slider = function(config){
4595 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4598 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4600 getAutoCreate : function(){
4604 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4608 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4620 * Ext JS Library 1.1.1
4621 * Copyright(c) 2006-2007, Ext JS, LLC.
4623 * Originally Released Under LGPL - original licence link has changed is not relivant.
4626 * <script type="text/javascript">
4631 * @class Roo.grid.ColumnModel
4632 * @extends Roo.util.Observable
4633 * This is the default implementation of a ColumnModel used by the Grid. It defines
4634 * the columns in the grid.
4637 var colModel = new Roo.grid.ColumnModel([
4638 {header: "Ticker", width: 60, sortable: true, locked: true},
4639 {header: "Company Name", width: 150, sortable: true},
4640 {header: "Market Cap.", width: 100, sortable: true},
4641 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4642 {header: "Employees", width: 100, sortable: true, resizable: false}
4647 * The config options listed for this class are options which may appear in each
4648 * individual column definition.
4649 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4651 * @param {Object} config An Array of column config objects. See this class's
4652 * config objects for details.
4654 Roo.grid.ColumnModel = function(config){
4656 * The config passed into the constructor
4658 this.config = config;
4661 // if no id, create one
4662 // if the column does not have a dataIndex mapping,
4663 // map it to the order it is in the config
4664 for(var i = 0, len = config.length; i < len; i++){
4666 if(typeof c.dataIndex == "undefined"){
4669 if(typeof c.renderer == "string"){
4670 c.renderer = Roo.util.Format[c.renderer];
4672 if(typeof c.id == "undefined"){
4675 if(c.editor && c.editor.xtype){
4676 c.editor = Roo.factory(c.editor, Roo.grid);
4678 if(c.editor && c.editor.isFormField){
4679 c.editor = new Roo.grid.GridEditor(c.editor);
4681 this.lookup[c.id] = c;
4685 * The width of columns which have no width specified (defaults to 100)
4688 this.defaultWidth = 100;
4691 * Default sortable of columns which have no sortable specified (defaults to false)
4694 this.defaultSortable = false;
4698 * @event widthchange
4699 * Fires when the width of a column changes.
4700 * @param {ColumnModel} this
4701 * @param {Number} columnIndex The column index
4702 * @param {Number} newWidth The new width
4704 "widthchange": true,
4706 * @event headerchange
4707 * Fires when the text of a header changes.
4708 * @param {ColumnModel} this
4709 * @param {Number} columnIndex The column index
4710 * @param {Number} newText The new header text
4712 "headerchange": true,
4714 * @event hiddenchange
4715 * Fires when a column is hidden or "unhidden".
4716 * @param {ColumnModel} this
4717 * @param {Number} columnIndex The column index
4718 * @param {Boolean} hidden true if hidden, false otherwise
4720 "hiddenchange": true,
4722 * @event columnmoved
4723 * Fires when a column is moved.
4724 * @param {ColumnModel} this
4725 * @param {Number} oldIndex
4726 * @param {Number} newIndex
4728 "columnmoved" : true,
4730 * @event columlockchange
4731 * Fires when a column's locked state is changed
4732 * @param {ColumnModel} this
4733 * @param {Number} colIndex
4734 * @param {Boolean} locked true if locked
4736 "columnlockchange" : true
4738 Roo.grid.ColumnModel.superclass.constructor.call(this);
4740 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4742 * @cfg {String} header The header text to display in the Grid view.
4745 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4746 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4747 * specified, the column's index is used as an index into the Record's data Array.
4750 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4751 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4754 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4755 * Defaults to the value of the {@link #defaultSortable} property.
4756 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4759 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4762 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4765 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4768 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4771 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4772 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4773 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4774 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4777 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4780 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4783 * @cfg {String} cursor (Optional)
4786 * @cfg {String} tooltip (Optional)
4789 * Returns the id of the column at the specified index.
4790 * @param {Number} index The column index
4791 * @return {String} the id
4793 getColumnId : function(index){
4794 return this.config[index].id;
4798 * Returns the column for a specified id.
4799 * @param {String} id The column id
4800 * @return {Object} the column
4802 getColumnById : function(id){
4803 return this.lookup[id];
4808 * Returns the column for a specified dataIndex.
4809 * @param {String} dataIndex The column dataIndex
4810 * @return {Object|Boolean} the column or false if not found
4812 getColumnByDataIndex: function(dataIndex){
4813 var index = this.findColumnIndex(dataIndex);
4814 return index > -1 ? this.config[index] : false;
4818 * Returns the index for a specified column id.
4819 * @param {String} id The column id
4820 * @return {Number} the index, or -1 if not found
4822 getIndexById : function(id){
4823 for(var i = 0, len = this.config.length; i < len; i++){
4824 if(this.config[i].id == id){
4832 * Returns the index for a specified column dataIndex.
4833 * @param {String} dataIndex The column dataIndex
4834 * @return {Number} the index, or -1 if not found
4837 findColumnIndex : function(dataIndex){
4838 for(var i = 0, len = this.config.length; i < len; i++){
4839 if(this.config[i].dataIndex == dataIndex){
4847 moveColumn : function(oldIndex, newIndex){
4848 var c = this.config[oldIndex];
4849 this.config.splice(oldIndex, 1);
4850 this.config.splice(newIndex, 0, c);
4851 this.dataMap = null;
4852 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4855 isLocked : function(colIndex){
4856 return this.config[colIndex].locked === true;
4859 setLocked : function(colIndex, value, suppressEvent){
4860 if(this.isLocked(colIndex) == value){
4863 this.config[colIndex].locked = value;
4865 this.fireEvent("columnlockchange", this, colIndex, value);
4869 getTotalLockedWidth : function(){
4871 for(var i = 0; i < this.config.length; i++){
4872 if(this.isLocked(i) && !this.isHidden(i)){
4873 this.totalWidth += this.getColumnWidth(i);
4879 getLockedCount : function(){
4880 for(var i = 0, len = this.config.length; i < len; i++){
4881 if(!this.isLocked(i)){
4888 * Returns the number of columns.
4891 getColumnCount : function(visibleOnly){
4892 if(visibleOnly === true){
4894 for(var i = 0, len = this.config.length; i < len; i++){
4895 if(!this.isHidden(i)){
4901 return this.config.length;
4905 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4906 * @param {Function} fn
4907 * @param {Object} scope (optional)
4908 * @return {Array} result
4910 getColumnsBy : function(fn, scope){
4912 for(var i = 0, len = this.config.length; i < len; i++){
4913 var c = this.config[i];
4914 if(fn.call(scope||this, c, i) === true){
4922 * Returns true if the specified column is sortable.
4923 * @param {Number} col The column index
4926 isSortable : function(col){
4927 if(typeof this.config[col].sortable == "undefined"){
4928 return this.defaultSortable;
4930 return this.config[col].sortable;
4934 * Returns the rendering (formatting) function defined for the column.
4935 * @param {Number} col The column index.
4936 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4938 getRenderer : function(col){
4939 if(!this.config[col].renderer){
4940 return Roo.grid.ColumnModel.defaultRenderer;
4942 return this.config[col].renderer;
4946 * Sets the rendering (formatting) function for a column.
4947 * @param {Number} col The column index
4948 * @param {Function} fn The function to use to process the cell's raw data
4949 * to return HTML markup for the grid view. The render function is called with
4950 * the following parameters:<ul>
4951 * <li>Data value.</li>
4952 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4953 * <li>css A CSS style string to apply to the table cell.</li>
4954 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4955 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4956 * <li>Row index</li>
4957 * <li>Column index</li>
4958 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4960 setRenderer : function(col, fn){
4961 this.config[col].renderer = fn;
4965 * Returns the width for the specified column.
4966 * @param {Number} col The column index
4969 getColumnWidth : function(col){
4970 return this.config[col].width * 1 || this.defaultWidth;
4974 * Sets the width for a column.
4975 * @param {Number} col The column index
4976 * @param {Number} width The new width
4978 setColumnWidth : function(col, width, suppressEvent){
4979 this.config[col].width = width;
4980 this.totalWidth = null;
4982 this.fireEvent("widthchange", this, col, width);
4987 * Returns the total width of all columns.
4988 * @param {Boolean} includeHidden True to include hidden column widths
4991 getTotalWidth : function(includeHidden){
4992 if(!this.totalWidth){
4993 this.totalWidth = 0;
4994 for(var i = 0, len = this.config.length; i < len; i++){
4995 if(includeHidden || !this.isHidden(i)){
4996 this.totalWidth += this.getColumnWidth(i);
5000 return this.totalWidth;
5004 * Returns the header for the specified column.
5005 * @param {Number} col The column index
5008 getColumnHeader : function(col){
5009 return this.config[col].header;
5013 * Sets the header for a column.
5014 * @param {Number} col The column index
5015 * @param {String} header The new header
5017 setColumnHeader : function(col, header){
5018 this.config[col].header = header;
5019 this.fireEvent("headerchange", this, col, header);
5023 * Returns the tooltip for the specified column.
5024 * @param {Number} col The column index
5027 getColumnTooltip : function(col){
5028 return this.config[col].tooltip;
5031 * Sets the tooltip for a column.
5032 * @param {Number} col The column index
5033 * @param {String} tooltip The new tooltip
5035 setColumnTooltip : function(col, tooltip){
5036 this.config[col].tooltip = tooltip;
5040 * Returns the dataIndex for the specified column.
5041 * @param {Number} col The column index
5044 getDataIndex : function(col){
5045 return this.config[col].dataIndex;
5049 * Sets the dataIndex for a column.
5050 * @param {Number} col The column index
5051 * @param {Number} dataIndex The new dataIndex
5053 setDataIndex : function(col, dataIndex){
5054 this.config[col].dataIndex = dataIndex;
5060 * Returns true if the cell is editable.
5061 * @param {Number} colIndex The column index
5062 * @param {Number} rowIndex The row index
5065 isCellEditable : function(colIndex, rowIndex){
5066 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5070 * Returns the editor defined for the cell/column.
5071 * return false or null to disable editing.
5072 * @param {Number} colIndex The column index
5073 * @param {Number} rowIndex The row index
5076 getCellEditor : function(colIndex, rowIndex){
5077 return this.config[colIndex].editor;
5081 * Sets if a column is editable.
5082 * @param {Number} col The column index
5083 * @param {Boolean} editable True if the column is editable
5085 setEditable : function(col, editable){
5086 this.config[col].editable = editable;
5091 * Returns true if the column is hidden.
5092 * @param {Number} colIndex The column index
5095 isHidden : function(colIndex){
5096 return this.config[colIndex].hidden;
5101 * Returns true if the column width cannot be changed
5103 isFixed : function(colIndex){
5104 return this.config[colIndex].fixed;
5108 * Returns true if the column can be resized
5111 isResizable : function(colIndex){
5112 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5115 * Sets if a column is hidden.
5116 * @param {Number} colIndex The column index
5117 * @param {Boolean} hidden True if the column is hidden
5119 setHidden : function(colIndex, hidden){
5120 this.config[colIndex].hidden = hidden;
5121 this.totalWidth = null;
5122 this.fireEvent("hiddenchange", this, colIndex, hidden);
5126 * Sets the editor for a column.
5127 * @param {Number} col The column index
5128 * @param {Object} editor The editor object
5130 setEditor : function(col, editor){
5131 this.config[col].editor = editor;
5135 Roo.grid.ColumnModel.defaultRenderer = function(value){
5136 if(typeof value == "string" && value.length < 1){
5142 // Alias for backwards compatibility
5143 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5146 * Ext JS Library 1.1.1
5147 * Copyright(c) 2006-2007, Ext JS, LLC.
5149 * Originally Released Under LGPL - original licence link has changed is not relivant.
5152 * <script type="text/javascript">
5156 * @class Roo.LoadMask
5157 * A simple utility class for generically masking elements while loading data. If the element being masked has
5158 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5159 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5160 * element's UpdateManager load indicator and will be destroyed after the initial load.
5162 * Create a new LoadMask
5163 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5164 * @param {Object} config The config object
5166 Roo.LoadMask = function(el, config){
5167 this.el = Roo.get(el);
5168 Roo.apply(this, config);
5170 this.store.on('beforeload', this.onBeforeLoad, this);
5171 this.store.on('load', this.onLoad, this);
5172 this.store.on('loadexception', this.onLoadException, this);
5173 this.removeMask = false;
5175 var um = this.el.getUpdateManager();
5176 um.showLoadIndicator = false; // disable the default indicator
5177 um.on('beforeupdate', this.onBeforeLoad, this);
5178 um.on('update', this.onLoad, this);
5179 um.on('failure', this.onLoad, this);
5180 this.removeMask = true;
5184 Roo.LoadMask.prototype = {
5186 * @cfg {Boolean} removeMask
5187 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5188 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5192 * The text to display in a centered loading message box (defaults to 'Loading...')
5196 * @cfg {String} msgCls
5197 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5199 msgCls : 'x-mask-loading',
5202 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5208 * Disables the mask to prevent it from being displayed
5210 disable : function(){
5211 this.disabled = true;
5215 * Enables the mask so that it can be displayed
5217 enable : function(){
5218 this.disabled = false;
5221 onLoadException : function()
5225 if (typeof(arguments[3]) != 'undefined') {
5226 Roo.MessageBox.alert("Error loading",arguments[3]);
5230 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5231 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5240 this.el.unmask(this.removeMask);
5245 this.el.unmask(this.removeMask);
5249 onBeforeLoad : function(){
5251 this.el.mask(this.msg, this.msgCls);
5256 destroy : function(){
5258 this.store.un('beforeload', this.onBeforeLoad, this);
5259 this.store.un('load', this.onLoad, this);
5260 this.store.un('loadexception', this.onLoadException, this);
5262 var um = this.el.getUpdateManager();
5263 um.un('beforeupdate', this.onBeforeLoad, this);
5264 um.un('update', this.onLoad, this);
5265 um.un('failure', this.onLoad, this);
5276 * @class Roo.bootstrap.Table
5277 * @extends Roo.bootstrap.Component
5278 * Bootstrap Table class
5279 * @cfg {String} cls table class
5280 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5281 * @cfg {String} bgcolor Specifies the background color for a table
5282 * @cfg {Number} border Specifies whether the table cells should have borders or not
5283 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5284 * @cfg {Number} cellspacing Specifies the space between cells
5285 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5286 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5287 * @cfg {String} sortable Specifies that the table should be sortable
5288 * @cfg {String} summary Specifies a summary of the content of a table
5289 * @cfg {Number} width Specifies the width of a table
5290 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5292 * @cfg {boolean} striped Should the rows be alternative striped
5293 * @cfg {boolean} bordered Add borders to the table
5294 * @cfg {boolean} hover Add hover highlighting
5295 * @cfg {boolean} condensed Format condensed
5296 * @cfg {boolean} responsive Format condensed
5297 * @cfg {Boolean} loadMask (true|false) default false
5298 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5299 * @cfg {Boolean} thead (true|false) generate thead, default true
5300 * @cfg {Boolean} RowSelection (true|false) default false
5301 * @cfg {Boolean} CellSelection (true|false) default false
5302 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5306 * Create a new Table
5307 * @param {Object} config The config object
5310 Roo.bootstrap.Table = function(config){
5311 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5314 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5315 this.sm = this.selModel;
5316 this.sm.xmodule = this.xmodule || false;
5318 if (this.cm && typeof(this.cm.config) == 'undefined') {
5319 this.colModel = new Roo.grid.ColumnModel(this.cm);
5320 this.cm = this.colModel;
5321 this.cm.xmodule = this.xmodule || false;
5324 this.store= Roo.factory(this.store, Roo.data);
5325 this.ds = this.store;
5326 this.ds.xmodule = this.xmodule || false;
5329 if (this.footer && this.store) {
5330 this.footer.dataSource = this.ds;
5331 this.footer = Roo.factory(this.footer);
5338 * Fires when a cell is clicked
5339 * @param {Roo.bootstrap.Table} this
5340 * @param {Roo.Element} el
5341 * @param {Number} rowIndex
5342 * @param {Number} columnIndex
5343 * @param {Roo.EventObject} e
5347 * @event celldblclick
5348 * Fires when a cell is double clicked
5349 * @param {Roo.bootstrap.Table} this
5350 * @param {Roo.Element} el
5351 * @param {Number} rowIndex
5352 * @param {Number} columnIndex
5353 * @param {Roo.EventObject} e
5355 "celldblclick" : true,
5358 * Fires when a row is clicked
5359 * @param {Roo.bootstrap.Table} this
5360 * @param {Roo.Element} el
5361 * @param {Number} rowIndex
5362 * @param {Roo.EventObject} e
5366 * @event rowdblclick
5367 * Fires when a row is double clicked
5368 * @param {Roo.bootstrap.Table} this
5369 * @param {Roo.Element} el
5370 * @param {Number} rowIndex
5371 * @param {Roo.EventObject} e
5373 "rowdblclick" : true,
5376 * Fires when a mouseover occur
5377 * @param {Roo.bootstrap.Table} this
5378 * @param {Roo.Element} el
5379 * @param {Number} rowIndex
5380 * @param {Number} columnIndex
5381 * @param {Roo.EventObject} e
5386 * Fires when a mouseout occur
5387 * @param {Roo.bootstrap.Table} this
5388 * @param {Roo.Element} el
5389 * @param {Number} rowIndex
5390 * @param {Number} columnIndex
5391 * @param {Roo.EventObject} e
5396 * Fires when a row is rendered, so you can change add a style to it.
5397 * @param {Roo.bootstrap.Table} this
5398 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5402 * @event rowsrendered
5403 * Fires when all the rows have been rendered
5404 * @param {Roo.bootstrap.Table} this
5406 'rowsrendered' : true
5411 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5435 RowSelection : false,
5436 CellSelection : false,
5439 // Roo.Element - the tbody
5442 getAutoCreate : function(){
5443 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5452 cfg.cls += ' table-striped';
5456 cfg.cls += ' table-hover';
5458 if (this.bordered) {
5459 cfg.cls += ' table-bordered';
5461 if (this.condensed) {
5462 cfg.cls += ' table-condensed';
5464 if (this.responsive) {
5465 cfg.cls += ' table-responsive';
5469 cfg.cls+= ' ' +this.cls;
5472 // this lot should be simplifed...
5475 cfg.align=this.align;
5478 cfg.bgcolor=this.bgcolor;
5481 cfg.border=this.border;
5483 if (this.cellpadding) {
5484 cfg.cellpadding=this.cellpadding;
5486 if (this.cellspacing) {
5487 cfg.cellspacing=this.cellspacing;
5490 cfg.frame=this.frame;
5493 cfg.rules=this.rules;
5495 if (this.sortable) {
5496 cfg.sortable=this.sortable;
5499 cfg.summary=this.summary;
5502 cfg.width=this.width;
5505 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5508 if(this.store || this.cm){
5510 cfg.cn.push(this.renderHeader());
5513 cfg.cn.push(this.renderBody());
5516 cfg.cn.push(this.renderFooter());
5519 cfg.cls+= ' TableGrid';
5522 return { cn : [ cfg ] };
5525 initEvents : function()
5527 if(!this.store || !this.cm){
5531 //Roo.log('initEvents with ds!!!!');
5533 this.mainBody = this.el.select('tbody', true).first();
5538 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5539 e.on('click', _this.sort, _this);
5542 this.el.on("click", this.onClick, this);
5543 this.el.on("dblclick", this.onDblClick, this);
5545 // why is this done????? = it breaks dialogs??
5546 //this.parent().el.setStyle('position', 'relative');
5550 this.footer.parentId = this.id;
5551 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5554 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5556 this.store.on('load', this.onLoad, this);
5557 this.store.on('beforeload', this.onBeforeLoad, this);
5558 this.store.on('update', this.onUpdate, this);
5559 this.store.on('add', this.onAdd, this);
5563 onMouseover : function(e, el)
5565 var cell = Roo.get(el);
5571 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5572 cell = cell.findParent('td', false, true);
5575 var row = cell.findParent('tr', false, true);
5576 var cellIndex = cell.dom.cellIndex;
5577 var rowIndex = row.dom.rowIndex - 1; // start from 0
5579 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5583 onMouseout : function(e, el)
5585 var cell = Roo.get(el);
5591 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5592 cell = cell.findParent('td', false, true);
5595 var row = cell.findParent('tr', false, true);
5596 var cellIndex = cell.dom.cellIndex;
5597 var rowIndex = row.dom.rowIndex - 1; // start from 0
5599 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5603 onClick : function(e, el)
5605 var cell = Roo.get(el);
5607 if(!cell || (!this.CellSelection && !this.RowSelection)){
5611 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5612 cell = cell.findParent('td', false, true);
5615 if(!cell || typeof(cell) == 'undefined'){
5619 var row = cell.findParent('tr', false, true);
5621 if(!row || typeof(row) == 'undefined'){
5625 var cellIndex = cell.dom.cellIndex;
5626 var rowIndex = this.getRowIndex(row);
5628 if(this.CellSelection){
5629 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5632 if(this.RowSelection){
5633 this.fireEvent('rowclick', this, row, rowIndex, e);
5639 onDblClick : function(e,el)
5641 var cell = Roo.get(el);
5643 if(!cell || (!this.CellSelection && !this.RowSelection)){
5647 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5648 cell = cell.findParent('td', false, true);
5651 if(!cell || typeof(cell) == 'undefined'){
5655 var row = cell.findParent('tr', false, true);
5657 if(!row || typeof(row) == 'undefined'){
5661 var cellIndex = cell.dom.cellIndex;
5662 var rowIndex = this.getRowIndex(row);
5664 if(this.CellSelection){
5665 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5668 if(this.RowSelection){
5669 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5673 sort : function(e,el)
5675 var col = Roo.get(el);
5677 if(!col.hasClass('sortable')){
5681 var sort = col.attr('sort');
5684 if(col.hasClass('glyphicon-arrow-up')){
5688 this.store.sortInfo = {field : sort, direction : dir};
5691 Roo.log("calling footer first");
5692 this.footer.onClick('first');
5695 this.store.load({ params : { start : 0 } });
5699 renderHeader : function()
5708 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5710 var config = cm.config[i];
5715 html: cm.getColumnHeader(i)
5718 if(typeof(config.tooltip) != 'undefined'){
5719 c.tooltip = config.tooltip;
5722 if(typeof(config.colspan) != 'undefined'){
5723 c.colspan = config.colspan;
5726 if(typeof(config.hidden) != 'undefined' && config.hidden){
5727 c.style += ' display:none;';
5730 if(typeof(config.dataIndex) != 'undefined'){
5731 c.sort = config.dataIndex;
5734 if(typeof(config.sortable) != 'undefined' && config.sortable){
5738 if(typeof(config.align) != 'undefined' && config.align.length){
5739 c.style += ' text-align:' + config.align + ';';
5742 if(typeof(config.width) != 'undefined'){
5743 c.style += ' width:' + config.width + 'px;';
5746 if(typeof(config.cls) != 'undefined'){
5747 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5756 renderBody : function()
5766 colspan : this.cm.getColumnCount()
5776 renderFooter : function()
5786 colspan : this.cm.getColumnCount()
5800 Roo.log('ds onload');
5805 var ds = this.store;
5807 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5808 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5810 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5811 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5814 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5815 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5819 var tbody = this.mainBody;
5821 if(ds.getCount() > 0){
5822 ds.data.each(function(d,rowIndex){
5823 var row = this.renderRow(cm, ds, rowIndex);
5825 tbody.createChild(row);
5829 if(row.cellObjects.length){
5830 Roo.each(row.cellObjects, function(r){
5831 _this.renderCellObject(r);
5838 Roo.each(this.el.select('tbody td', true).elements, function(e){
5839 e.on('mouseover', _this.onMouseover, _this);
5842 Roo.each(this.el.select('tbody td', true).elements, function(e){
5843 e.on('mouseout', _this.onMouseout, _this);
5845 this.fireEvent('rowsrendered', this);
5846 //if(this.loadMask){
5847 // this.maskEl.hide();
5852 onUpdate : function(ds,record)
5854 this.refreshRow(record);
5857 onRemove : function(ds, record, index, isUpdate){
5858 if(isUpdate !== true){
5859 this.fireEvent("beforerowremoved", this, index, record);
5861 var bt = this.mainBody.dom;
5863 var rows = this.el.select('tbody > tr', true).elements;
5865 if(typeof(rows[index]) != 'undefined'){
5866 bt.removeChild(rows[index].dom);
5869 // if(bt.rows[index]){
5870 // bt.removeChild(bt.rows[index]);
5873 if(isUpdate !== true){
5874 //this.stripeRows(index);
5875 //this.syncRowHeights(index, index);
5877 this.fireEvent("rowremoved", this, index, record);
5881 onAdd : function(ds, records, rowIndex)
5883 //Roo.log('on Add called');
5884 // - note this does not handle multiple adding very well..
5885 var bt = this.mainBody.dom;
5886 for (var i =0 ; i < records.length;i++) {
5887 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5888 //Roo.log(records[i]);
5889 //Roo.log(this.store.getAt(rowIndex+i));
5890 this.insertRow(this.store, rowIndex + i, false);
5897 refreshRow : function(record){
5898 var ds = this.store, index;
5899 if(typeof record == 'number'){
5901 record = ds.getAt(index);
5903 index = ds.indexOf(record);
5905 this.insertRow(ds, index, true);
5906 this.onRemove(ds, record, index+1, true);
5907 //this.syncRowHeights(index, index);
5909 this.fireEvent("rowupdated", this, index, record);
5912 insertRow : function(dm, rowIndex, isUpdate){
5915 this.fireEvent("beforerowsinserted", this, rowIndex);
5917 //var s = this.getScrollState();
5918 var row = this.renderRow(this.cm, this.store, rowIndex);
5919 // insert before rowIndex..
5920 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5924 if(row.cellObjects.length){
5925 Roo.each(row.cellObjects, function(r){
5926 _this.renderCellObject(r);
5931 this.fireEvent("rowsinserted", this, rowIndex);
5932 //this.syncRowHeights(firstRow, lastRow);
5933 //this.stripeRows(firstRow);
5940 getRowDom : function(rowIndex)
5942 var rows = this.el.select('tbody > tr', true).elements;
5944 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5947 // returns the object tree for a tr..
5950 renderRow : function(cm, ds, rowIndex)
5953 var d = ds.getAt(rowIndex);
5960 var cellObjects = [];
5962 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5963 var config = cm.config[i];
5965 var renderer = cm.getRenderer(i);
5969 if(typeof(renderer) !== 'undefined'){
5970 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5972 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5973 // and are rendered into the cells after the row is rendered - using the id for the element.
5975 if(typeof(value) === 'object'){
5985 rowIndex : rowIndex,
5990 this.fireEvent('rowclass', this, rowcfg);
5994 cls : rowcfg.rowClass,
5996 html: (typeof(value) === 'object') ? '' : value
6003 if(typeof(config.colspan) != 'undefined'){
6004 td.colspan = config.colspan;
6007 if(typeof(config.hidden) != 'undefined' && config.hidden){
6008 td.style += ' display:none;';
6011 if(typeof(config.align) != 'undefined' && config.align.length){
6012 td.style += ' text-align:' + config.align + ';';
6015 if(typeof(config.width) != 'undefined'){
6016 td.style += ' width:' + config.width + 'px;';
6019 if(typeof(config.cursor) != 'undefined'){
6020 td.style += ' cursor:' + config.cursor + ';';
6023 if(typeof(config.cls) != 'undefined'){
6024 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6031 row.cellObjects = cellObjects;
6039 onBeforeLoad : function()
6041 //Roo.log('ds onBeforeLoad');
6045 //if(this.loadMask){
6046 // this.maskEl.show();
6054 this.el.select('tbody', true).first().dom.innerHTML = '';
6057 * Show or hide a row.
6058 * @param {Number} rowIndex to show or hide
6059 * @param {Boolean} state hide
6061 setRowVisibility : function(rowIndex, state)
6063 var bt = this.mainBody.dom;
6065 var rows = this.el.select('tbody > tr', true).elements;
6067 if(typeof(rows[rowIndex]) == 'undefined'){
6070 rows[rowIndex].dom.style.display = state ? '' : 'none';
6074 getSelectionModel : function(){
6076 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6078 return this.selModel;
6081 * Render the Roo.bootstrap object from renderder
6083 renderCellObject : function(r)
6087 var t = r.cfg.render(r.container);
6090 Roo.each(r.cfg.cn, function(c){
6092 container: t.getChildContainer(),
6095 _this.renderCellObject(child);
6100 getRowIndex : function(row)
6104 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6127 * @class Roo.bootstrap.TableCell
6128 * @extends Roo.bootstrap.Component
6129 * Bootstrap TableCell class
6130 * @cfg {String} html cell contain text
6131 * @cfg {String} cls cell class
6132 * @cfg {String} tag cell tag (td|th) default td
6133 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6134 * @cfg {String} align Aligns the content in a cell
6135 * @cfg {String} axis Categorizes cells
6136 * @cfg {String} bgcolor Specifies the background color of a cell
6137 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6138 * @cfg {Number} colspan Specifies the number of columns a cell should span
6139 * @cfg {String} headers Specifies one or more header cells a cell is related to
6140 * @cfg {Number} height Sets the height of a cell
6141 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6142 * @cfg {Number} rowspan Sets the number of rows a cell should span
6143 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6144 * @cfg {String} valign Vertical aligns the content in a cell
6145 * @cfg {Number} width Specifies the width of a cell
6148 * Create a new TableCell
6149 * @param {Object} config The config object
6152 Roo.bootstrap.TableCell = function(config){
6153 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6156 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6176 getAutoCreate : function(){
6177 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6197 cfg.align=this.align
6203 cfg.bgcolor=this.bgcolor
6206 cfg.charoff=this.charoff
6209 cfg.colspan=this.colspan
6212 cfg.headers=this.headers
6215 cfg.height=this.height
6218 cfg.nowrap=this.nowrap
6221 cfg.rowspan=this.rowspan
6224 cfg.scope=this.scope
6227 cfg.valign=this.valign
6230 cfg.width=this.width
6249 * @class Roo.bootstrap.TableRow
6250 * @extends Roo.bootstrap.Component
6251 * Bootstrap TableRow class
6252 * @cfg {String} cls row class
6253 * @cfg {String} align Aligns the content in a table row
6254 * @cfg {String} bgcolor Specifies a background color for a table row
6255 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6256 * @cfg {String} valign Vertical aligns the content in a table row
6259 * Create a new TableRow
6260 * @param {Object} config The config object
6263 Roo.bootstrap.TableRow = function(config){
6264 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6267 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6275 getAutoCreate : function(){
6276 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6286 cfg.align = this.align;
6289 cfg.bgcolor = this.bgcolor;
6292 cfg.charoff = this.charoff;
6295 cfg.valign = this.valign;
6313 * @class Roo.bootstrap.TableBody
6314 * @extends Roo.bootstrap.Component
6315 * Bootstrap TableBody class
6316 * @cfg {String} cls element class
6317 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6318 * @cfg {String} align Aligns the content inside the element
6319 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6320 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6323 * Create a new TableBody
6324 * @param {Object} config The config object
6327 Roo.bootstrap.TableBody = function(config){
6328 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6331 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6339 getAutoCreate : function(){
6340 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6354 cfg.align = this.align;
6357 cfg.charoff = this.charoff;
6360 cfg.valign = this.valign;
6367 // initEvents : function()
6374 // this.store = Roo.factory(this.store, Roo.data);
6375 // this.store.on('load', this.onLoad, this);
6377 // this.store.load();
6381 // onLoad: function ()
6383 // this.fireEvent('load', this);
6393 * Ext JS Library 1.1.1
6394 * Copyright(c) 2006-2007, Ext JS, LLC.
6396 * Originally Released Under LGPL - original licence link has changed is not relivant.
6399 * <script type="text/javascript">
6402 // as we use this in bootstrap.
6403 Roo.namespace('Roo.form');
6405 * @class Roo.form.Action
6406 * Internal Class used to handle form actions
6408 * @param {Roo.form.BasicForm} el The form element or its id
6409 * @param {Object} config Configuration options
6414 // define the action interface
6415 Roo.form.Action = function(form, options){
6417 this.options = options || {};
6420 * Client Validation Failed
6423 Roo.form.Action.CLIENT_INVALID = 'client';
6425 * Server Validation Failed
6428 Roo.form.Action.SERVER_INVALID = 'server';
6430 * Connect to Server Failed
6433 Roo.form.Action.CONNECT_FAILURE = 'connect';
6435 * Reading Data from Server Failed
6438 Roo.form.Action.LOAD_FAILURE = 'load';
6440 Roo.form.Action.prototype = {
6442 failureType : undefined,
6443 response : undefined,
6447 run : function(options){
6452 success : function(response){
6457 handleResponse : function(response){
6461 // default connection failure
6462 failure : function(response){
6464 this.response = response;
6465 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6466 this.form.afterAction(this, false);
6469 processResponse : function(response){
6470 this.response = response;
6471 if(!response.responseText){
6474 this.result = this.handleResponse(response);
6478 // utility functions used internally
6479 getUrl : function(appendParams){
6480 var url = this.options.url || this.form.url || this.form.el.dom.action;
6482 var p = this.getParams();
6484 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6490 getMethod : function(){
6491 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6494 getParams : function(){
6495 var bp = this.form.baseParams;
6496 var p = this.options.params;
6498 if(typeof p == "object"){
6499 p = Roo.urlEncode(Roo.applyIf(p, bp));
6500 }else if(typeof p == 'string' && bp){
6501 p += '&' + Roo.urlEncode(bp);
6504 p = Roo.urlEncode(bp);
6509 createCallback : function(){
6511 success: this.success,
6512 failure: this.failure,
6514 timeout: (this.form.timeout*1000),
6515 upload: this.form.fileUpload ? this.success : undefined
6520 Roo.form.Action.Submit = function(form, options){
6521 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6524 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6527 haveProgress : false,
6528 uploadComplete : false,
6530 // uploadProgress indicator.
6531 uploadProgress : function()
6533 if (!this.form.progressUrl) {
6537 if (!this.haveProgress) {
6538 Roo.MessageBox.progress("Uploading", "Uploading");
6540 if (this.uploadComplete) {
6541 Roo.MessageBox.hide();
6545 this.haveProgress = true;
6547 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6549 var c = new Roo.data.Connection();
6551 url : this.form.progressUrl,
6556 success : function(req){
6557 //console.log(data);
6561 rdata = Roo.decode(req.responseText)
6563 Roo.log("Invalid data from server..");
6567 if (!rdata || !rdata.success) {
6569 Roo.MessageBox.alert(Roo.encode(rdata));
6572 var data = rdata.data;
6574 if (this.uploadComplete) {
6575 Roo.MessageBox.hide();
6580 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6581 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6584 this.uploadProgress.defer(2000,this);
6587 failure: function(data) {
6588 Roo.log('progress url failed ');
6599 // run get Values on the form, so it syncs any secondary forms.
6600 this.form.getValues();
6602 var o = this.options;
6603 var method = this.getMethod();
6604 var isPost = method == 'POST';
6605 if(o.clientValidation === false || this.form.isValid()){
6607 if (this.form.progressUrl) {
6608 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6609 (new Date() * 1) + '' + Math.random());
6614 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6615 form:this.form.el.dom,
6616 url:this.getUrl(!isPost),
6618 params:isPost ? this.getParams() : null,
6619 isUpload: this.form.fileUpload
6622 this.uploadProgress();
6624 }else if (o.clientValidation !== false){ // client validation failed
6625 this.failureType = Roo.form.Action.CLIENT_INVALID;
6626 this.form.afterAction(this, false);
6630 success : function(response)
6632 this.uploadComplete= true;
6633 if (this.haveProgress) {
6634 Roo.MessageBox.hide();
6638 var result = this.processResponse(response);
6639 if(result === true || result.success){
6640 this.form.afterAction(this, true);
6644 this.form.markInvalid(result.errors);
6645 this.failureType = Roo.form.Action.SERVER_INVALID;
6647 this.form.afterAction(this, false);
6649 failure : function(response)
6651 this.uploadComplete= true;
6652 if (this.haveProgress) {
6653 Roo.MessageBox.hide();
6656 this.response = response;
6657 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6658 this.form.afterAction(this, false);
6661 handleResponse : function(response){
6662 if(this.form.errorReader){
6663 var rs = this.form.errorReader.read(response);
6666 for(var i = 0, len = rs.records.length; i < len; i++) {
6667 var r = rs.records[i];
6671 if(errors.length < 1){
6675 success : rs.success,
6681 ret = Roo.decode(response.responseText);
6685 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6695 Roo.form.Action.Load = function(form, options){
6696 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6697 this.reader = this.form.reader;
6700 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6705 Roo.Ajax.request(Roo.apply(
6706 this.createCallback(), {
6707 method:this.getMethod(),
6708 url:this.getUrl(false),
6709 params:this.getParams()
6713 success : function(response){
6715 var result = this.processResponse(response);
6716 if(result === true || !result.success || !result.data){
6717 this.failureType = Roo.form.Action.LOAD_FAILURE;
6718 this.form.afterAction(this, false);
6721 this.form.clearInvalid();
6722 this.form.setValues(result.data);
6723 this.form.afterAction(this, true);
6726 handleResponse : function(response){
6727 if(this.form.reader){
6728 var rs = this.form.reader.read(response);
6729 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6731 success : rs.success,
6735 return Roo.decode(response.responseText);
6739 Roo.form.Action.ACTION_TYPES = {
6740 'load' : Roo.form.Action.Load,
6741 'submit' : Roo.form.Action.Submit
6750 * @class Roo.bootstrap.Form
6751 * @extends Roo.bootstrap.Component
6752 * Bootstrap Form class
6753 * @cfg {String} method GET | POST (default POST)
6754 * @cfg {String} labelAlign top | left (default top)
6755 * @cfg {String} align left | right - for navbars
6756 * @cfg {Boolean} loadMask load mask when submit (default true)
6761 * @param {Object} config The config object
6765 Roo.bootstrap.Form = function(config){
6766 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6769 * @event clientvalidation
6770 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6771 * @param {Form} this
6772 * @param {Boolean} valid true if the form has passed client-side validation
6774 clientvalidation: true,
6776 * @event beforeaction
6777 * Fires before any action is performed. Return false to cancel the action.
6778 * @param {Form} this
6779 * @param {Action} action The action to be performed
6783 * @event actionfailed
6784 * Fires when an action fails.
6785 * @param {Form} this
6786 * @param {Action} action The action that failed
6788 actionfailed : true,
6790 * @event actioncomplete
6791 * Fires when an action is completed.
6792 * @param {Form} this
6793 * @param {Action} action The action that completed
6795 actioncomplete : true
6800 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6803 * @cfg {String} method
6804 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6809 * The URL to use for form actions if one isn't supplied in the action options.
6812 * @cfg {Boolean} fileUpload
6813 * Set to true if this form is a file upload.
6817 * @cfg {Object} baseParams
6818 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6822 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6826 * @cfg {Sting} align (left|right) for navbar forms
6831 activeAction : null,
6834 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6835 * element by passing it or its id or mask the form itself by passing in true.
6838 waitMsgTarget : false,
6842 getAutoCreate : function(){
6846 method : this.method || 'POST',
6847 id : this.id || Roo.id(),
6850 if (this.parent().xtype.match(/^Nav/)) {
6851 cfg.cls = 'navbar-form navbar-' + this.align;
6855 if (this.labelAlign == 'left' ) {
6856 cfg.cls += ' form-horizontal';
6862 initEvents : function()
6864 this.el.on('submit', this.onSubmit, this);
6865 // this was added as random key presses on the form where triggering form submit.
6866 this.el.on('keypress', function(e) {
6867 if (e.getCharCode() != 13) {
6870 // we might need to allow it for textareas.. and some other items.
6871 // check e.getTarget().
6873 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6877 Roo.log("keypress blocked");
6885 onSubmit : function(e){
6890 * Returns true if client-side validation on the form is successful.
6893 isValid : function(){
6894 var items = this.getItems();
6896 items.each(function(f){
6905 * Returns true if any fields in this form have changed since their original load.
6908 isDirty : function(){
6910 var items = this.getItems();
6911 items.each(function(f){
6921 * Performs a predefined action (submit or load) or custom actions you define on this form.
6922 * @param {String} actionName The name of the action type
6923 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6924 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6925 * accept other config options):
6927 Property Type Description
6928 ---------------- --------------- ----------------------------------------------------------------------------------
6929 url String The url for the action (defaults to the form's url)
6930 method String The form method to use (defaults to the form's method, or POST if not defined)
6931 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6932 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6933 validate the form on the client (defaults to false)
6935 * @return {BasicForm} this
6937 doAction : function(action, options){
6938 if(typeof action == 'string'){
6939 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6941 if(this.fireEvent('beforeaction', this, action) !== false){
6942 this.beforeAction(action);
6943 action.run.defer(100, action);
6949 beforeAction : function(action){
6950 var o = action.options;
6953 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6955 // not really supported yet.. ??
6957 //if(this.waitMsgTarget === true){
6958 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6959 //}else if(this.waitMsgTarget){
6960 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6961 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6963 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6969 afterAction : function(action, success){
6970 this.activeAction = null;
6971 var o = action.options;
6973 //if(this.waitMsgTarget === true){
6975 //}else if(this.waitMsgTarget){
6976 // this.waitMsgTarget.unmask();
6978 // Roo.MessageBox.updateProgress(1);
6979 // Roo.MessageBox.hide();
6986 Roo.callback(o.success, o.scope, [this, action]);
6987 this.fireEvent('actioncomplete', this, action);
6991 // failure condition..
6992 // we have a scenario where updates need confirming.
6993 // eg. if a locking scenario exists..
6994 // we look for { errors : { needs_confirm : true }} in the response.
6996 (typeof(action.result) != 'undefined') &&
6997 (typeof(action.result.errors) != 'undefined') &&
6998 (typeof(action.result.errors.needs_confirm) != 'undefined')
7001 Roo.log("not supported yet");
7004 Roo.MessageBox.confirm(
7005 "Change requires confirmation",
7006 action.result.errorMsg,
7011 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7021 Roo.callback(o.failure, o.scope, [this, action]);
7022 // show an error message if no failed handler is set..
7023 if (!this.hasListener('actionfailed')) {
7024 Roo.log("need to add dialog support");
7026 Roo.MessageBox.alert("Error",
7027 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7028 action.result.errorMsg :
7029 "Saving Failed, please check your entries or try again"
7034 this.fireEvent('actionfailed', this, action);
7039 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7040 * @param {String} id The value to search for
7043 findField : function(id){
7044 var items = this.getItems();
7045 var field = items.get(id);
7047 items.each(function(f){
7048 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7055 return field || null;
7058 * Mark fields in this form invalid in bulk.
7059 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7060 * @return {BasicForm} this
7062 markInvalid : function(errors){
7063 if(errors instanceof Array){
7064 for(var i = 0, len = errors.length; i < len; i++){
7065 var fieldError = errors[i];
7066 var f = this.findField(fieldError.id);
7068 f.markInvalid(fieldError.msg);
7074 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7075 field.markInvalid(errors[id]);
7079 //Roo.each(this.childForms || [], function (f) {
7080 // f.markInvalid(errors);
7087 * Set values for fields in this form in bulk.
7088 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7089 * @return {BasicForm} this
7091 setValues : function(values){
7092 if(values instanceof Array){ // array of objects
7093 for(var i = 0, len = values.length; i < len; i++){
7095 var f = this.findField(v.id);
7097 f.setValue(v.value);
7098 if(this.trackResetOnLoad){
7099 f.originalValue = f.getValue();
7103 }else{ // object hash
7106 if(typeof values[id] != 'function' && (field = this.findField(id))){
7108 if (field.setFromData &&
7110 field.displayField &&
7111 // combos' with local stores can
7112 // be queried via setValue()
7113 // to set their value..
7114 (field.store && !field.store.isLocal)
7118 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7119 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7120 field.setFromData(sd);
7123 field.setValue(values[id]);
7127 if(this.trackResetOnLoad){
7128 field.originalValue = field.getValue();
7134 //Roo.each(this.childForms || [], function (f) {
7135 // f.setValues(values);
7142 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7143 * they are returned as an array.
7144 * @param {Boolean} asString
7147 getValues : function(asString){
7148 //if (this.childForms) {
7149 // copy values from the child forms
7150 // Roo.each(this.childForms, function (f) {
7151 // this.setValues(f.getValues());
7157 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7158 if(asString === true){
7161 return Roo.urlDecode(fs);
7165 * Returns the fields in this form as an object with key/value pairs.
7166 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7169 getFieldValues : function(with_hidden)
7171 var items = this.getItems();
7173 items.each(function(f){
7177 var v = f.getValue();
7178 if (f.inputType =='radio') {
7179 if (typeof(ret[f.getName()]) == 'undefined') {
7180 ret[f.getName()] = ''; // empty..
7183 if (!f.el.dom.checked) {
7191 // not sure if this supported any more..
7192 if ((typeof(v) == 'object') && f.getRawValue) {
7193 v = f.getRawValue() ; // dates..
7195 // combo boxes where name != hiddenName...
7196 if (f.name != f.getName()) {
7197 ret[f.name] = f.getRawValue();
7199 ret[f.getName()] = v;
7206 * Clears all invalid messages in this form.
7207 * @return {BasicForm} this
7209 clearInvalid : function(){
7210 var items = this.getItems();
7212 items.each(function(f){
7223 * @return {BasicForm} this
7226 var items = this.getItems();
7227 items.each(function(f){
7231 Roo.each(this.childForms || [], function (f) {
7238 getItems : function()
7240 var r=new Roo.util.MixedCollection(false, function(o){
7241 return o.id || (o.id = Roo.id());
7243 var iter = function(el) {
7250 Roo.each(el.items,function(e) {
7270 * Ext JS Library 1.1.1
7271 * Copyright(c) 2006-2007, Ext JS, LLC.
7273 * Originally Released Under LGPL - original licence link has changed is not relivant.
7276 * <script type="text/javascript">
7279 * @class Roo.form.VTypes
7280 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7283 Roo.form.VTypes = function(){
7284 // closure these in so they are only created once.
7285 var alpha = /^[a-zA-Z_]+$/;
7286 var alphanum = /^[a-zA-Z0-9_]+$/;
7287 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7288 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7290 // All these messages and functions are configurable
7293 * The function used to validate email addresses
7294 * @param {String} value The email address
7296 'email' : function(v){
7297 return email.test(v);
7300 * The error text to display when the email validation function returns false
7303 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7305 * The keystroke filter mask to be applied on email input
7308 'emailMask' : /[a-z0-9_\.\-@]/i,
7311 * The function used to validate URLs
7312 * @param {String} value The URL
7314 'url' : function(v){
7318 * The error text to display when the url validation function returns false
7321 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7324 * The function used to validate alpha values
7325 * @param {String} value The value
7327 'alpha' : function(v){
7328 return alpha.test(v);
7331 * The error text to display when the alpha validation function returns false
7334 'alphaText' : 'This field should only contain letters and _',
7336 * The keystroke filter mask to be applied on alpha input
7339 'alphaMask' : /[a-z_]/i,
7342 * The function used to validate alphanumeric values
7343 * @param {String} value The value
7345 'alphanum' : function(v){
7346 return alphanum.test(v);
7349 * The error text to display when the alphanumeric validation function returns false
7352 'alphanumText' : 'This field should only contain letters, numbers and _',
7354 * The keystroke filter mask to be applied on alphanumeric input
7357 'alphanumMask' : /[a-z0-9_]/i
7367 * @class Roo.bootstrap.Input
7368 * @extends Roo.bootstrap.Component
7369 * Bootstrap Input class
7370 * @cfg {Boolean} disabled is it disabled
7371 * @cfg {String} fieldLabel - the label associated
7372 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7373 * @cfg {String} name name of the input
7374 * @cfg {string} fieldLabel - the label associated
7375 * @cfg {string} inputType - input / file submit ...
7376 * @cfg {string} placeholder - placeholder to put in text.
7377 * @cfg {string} before - input group add on before
7378 * @cfg {string} after - input group add on after
7379 * @cfg {string} size - (lg|sm) or leave empty..
7380 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7381 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7382 * @cfg {Number} md colspan out of 12 for computer-sized screens
7383 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7384 * @cfg {string} value default value of the input
7385 * @cfg {Number} labelWidth set the width of label (0-12)
7386 * @cfg {String} labelAlign (top|left)
7387 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7388 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7390 * @cfg {String} align (left|center|right) Default left
7395 * Create a new Input
7396 * @param {Object} config The config object
7399 Roo.bootstrap.Input = function(config){
7400 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7405 * Fires when this field receives input focus.
7406 * @param {Roo.form.Field} this
7411 * Fires when this field loses input focus.
7412 * @param {Roo.form.Field} this
7417 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7418 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7419 * @param {Roo.form.Field} this
7420 * @param {Roo.EventObject} e The event object
7425 * Fires just before the field blurs if the field value has changed.
7426 * @param {Roo.form.Field} this
7427 * @param {Mixed} newValue The new value
7428 * @param {Mixed} oldValue The original value
7433 * Fires after the field has been marked as invalid.
7434 * @param {Roo.form.Field} this
7435 * @param {String} msg The validation message
7440 * Fires after the field has been validated with no errors.
7441 * @param {Roo.form.Field} this
7446 * Fires after the key up
7447 * @param {Roo.form.Field} this
7448 * @param {Roo.EventObject} e The event Object
7454 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7456 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7457 automatic validation (defaults to "keyup").
7459 validationEvent : "keyup",
7461 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7463 validateOnBlur : true,
7465 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7467 validationDelay : 250,
7469 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7471 focusClass : "x-form-focus", // not needed???
7475 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7477 invalidClass : "has-warning",
7480 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7482 validClass : "has-success",
7485 * @cfg {Boolean} hasFeedback (true|false) default true
7490 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7492 invalidFeedbackClass : "glyphicon-warning-sign",
7495 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7497 validFeedbackClass : "glyphicon-ok",
7500 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7502 selectOnFocus : false,
7505 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7509 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7514 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7516 disableKeyFilter : false,
7519 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7523 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7527 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7529 blankText : "This field is required",
7532 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7536 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7538 maxLength : Number.MAX_VALUE,
7540 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7542 minLengthText : "The minimum length for this field is {0}",
7544 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7546 maxLengthText : "The maximum length for this field is {0}",
7550 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7551 * If available, this function will be called only after the basic validators all return true, and will be passed the
7552 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7556 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7557 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7558 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7562 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7566 autocomplete: false,
7585 formatedValue : false,
7587 parentLabelAlign : function()
7590 while (parent.parent()) {
7591 parent = parent.parent();
7592 if (typeof(parent.labelAlign) !='undefined') {
7593 return parent.labelAlign;
7600 getAutoCreate : function(){
7602 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7608 if(this.inputType != 'hidden'){
7609 cfg.cls = 'form-group' //input-group
7615 type : this.inputType,
7617 cls : 'form-control',
7618 placeholder : this.placeholder || '',
7619 autocomplete : this.autocomplete || 'new-password'
7624 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7627 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7628 input.maxLength = this.maxLength;
7631 if (this.disabled) {
7632 input.disabled=true;
7635 if (this.readOnly) {
7636 input.readonly=true;
7640 input.name = this.name;
7643 input.cls += ' input-' + this.size;
7646 ['xs','sm','md','lg'].map(function(size){
7647 if (settings[size]) {
7648 cfg.cls += ' col-' + size + '-' + settings[size];
7652 var inputblock = input;
7656 cls: 'glyphicon form-control-feedback'
7659 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7662 cls : 'has-feedback',
7670 if (this.before || this.after) {
7673 cls : 'input-group',
7677 if (this.before && typeof(this.before) == 'string') {
7679 inputblock.cn.push({
7681 cls : 'roo-input-before input-group-addon',
7685 if (this.before && typeof(this.before) == 'object') {
7686 this.before = Roo.factory(this.before);
7687 Roo.log(this.before);
7688 inputblock.cn.push({
7690 cls : 'roo-input-before input-group-' +
7691 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7695 inputblock.cn.push(input);
7697 if (this.after && typeof(this.after) == 'string') {
7698 inputblock.cn.push({
7700 cls : 'roo-input-after input-group-addon',
7704 if (this.after && typeof(this.after) == 'object') {
7705 this.after = Roo.factory(this.after);
7706 Roo.log(this.after);
7707 inputblock.cn.push({
7709 cls : 'roo-input-after input-group-' +
7710 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7714 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7715 inputblock.cls += ' has-feedback';
7716 inputblock.cn.push(feedback);
7720 if (align ==='left' && this.fieldLabel.length) {
7721 Roo.log("left and has label");
7727 cls : 'control-label col-sm-' + this.labelWidth,
7728 html : this.fieldLabel
7732 cls : "col-sm-" + (12 - this.labelWidth),
7739 } else if ( this.fieldLabel.length) {
7745 //cls : 'input-group-addon',
7746 html : this.fieldLabel
7756 Roo.log(" no label && no align");
7765 Roo.log('input-parentType: ' + this.parentType);
7767 if (this.parentType === 'Navbar' && this.parent().bar) {
7768 cfg.cls += ' navbar-form';
7776 * return the real input element.
7778 inputEl: function ()
7780 return this.el.select('input.form-control',true).first();
7783 tooltipEl : function()
7785 return this.inputEl();
7788 setDisabled : function(v)
7790 var i = this.inputEl().dom;
7792 i.removeAttribute('disabled');
7796 i.setAttribute('disabled','true');
7798 initEvents : function()
7801 this.inputEl().on("keydown" , this.fireKey, this);
7802 this.inputEl().on("focus", this.onFocus, this);
7803 this.inputEl().on("blur", this.onBlur, this);
7805 this.inputEl().relayEvent('keyup', this);
7807 // reference to original value for reset
7808 this.originalValue = this.getValue();
7809 //Roo.form.TextField.superclass.initEvents.call(this);
7810 if(this.validationEvent == 'keyup'){
7811 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7812 this.inputEl().on('keyup', this.filterValidation, this);
7814 else if(this.validationEvent !== false){
7815 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7818 if(this.selectOnFocus){
7819 this.on("focus", this.preFocus, this);
7822 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7823 this.inputEl().on("keypress", this.filterKeys, this);
7826 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7827 this.el.on("click", this.autoSize, this);
7830 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7831 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7834 if (typeof(this.before) == 'object') {
7835 this.before.render(this.el.select('.roo-input-before',true).first());
7837 if (typeof(this.after) == 'object') {
7838 this.after.render(this.el.select('.roo-input-after',true).first());
7843 filterValidation : function(e){
7844 if(!e.isNavKeyPress()){
7845 this.validationTask.delay(this.validationDelay);
7849 * Validates the field value
7850 * @return {Boolean} True if the value is valid, else false
7852 validate : function(){
7853 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7854 if(this.disabled || this.validateValue(this.getRawValue())){
7865 * Validates a value according to the field's validation rules and marks the field as invalid
7866 * if the validation fails
7867 * @param {Mixed} value The value to validate
7868 * @return {Boolean} True if the value is valid, else false
7870 validateValue : function(value){
7871 if(value.length < 1) { // if it's blank
7872 if(this.allowBlank){
7878 if(value.length < this.minLength){
7881 if(value.length > this.maxLength){
7885 var vt = Roo.form.VTypes;
7886 if(!vt[this.vtype](value, this)){
7890 if(typeof this.validator == "function"){
7891 var msg = this.validator(value);
7897 if(this.regex && !this.regex.test(value)){
7907 fireKey : function(e){
7908 //Roo.log('field ' + e.getKey());
7909 if(e.isNavKeyPress()){
7910 this.fireEvent("specialkey", this, e);
7913 focus : function (selectText){
7915 this.inputEl().focus();
7916 if(selectText === true){
7917 this.inputEl().dom.select();
7923 onFocus : function(){
7924 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7925 // this.el.addClass(this.focusClass);
7928 this.hasFocus = true;
7929 this.startValue = this.getValue();
7930 this.fireEvent("focus", this);
7934 beforeBlur : Roo.emptyFn,
7938 onBlur : function(){
7940 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7941 //this.el.removeClass(this.focusClass);
7943 this.hasFocus = false;
7944 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7947 var v = this.getValue();
7948 if(String(v) !== String(this.startValue)){
7949 this.fireEvent('change', this, v, this.startValue);
7951 this.fireEvent("blur", this);
7955 * Resets the current field value to the originally loaded value and clears any validation messages
7958 this.setValue(this.originalValue);
7962 * Returns the name of the field
7963 * @return {Mixed} name The name field
7965 getName: function(){
7969 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7970 * @return {Mixed} value The field value
7972 getValue : function(){
7974 var v = this.inputEl().getValue();
7979 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7980 * @return {Mixed} value The field value
7982 getRawValue : function(){
7983 var v = this.inputEl().getValue();
7989 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7990 * @param {Mixed} value The value to set
7992 setRawValue : function(v){
7993 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7996 selectText : function(start, end){
7997 var v = this.getRawValue();
7999 start = start === undefined ? 0 : start;
8000 end = end === undefined ? v.length : end;
8001 var d = this.inputEl().dom;
8002 if(d.setSelectionRange){
8003 d.setSelectionRange(start, end);
8004 }else if(d.createTextRange){
8005 var range = d.createTextRange();
8006 range.moveStart("character", start);
8007 range.moveEnd("character", v.length-end);
8014 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8015 * @param {Mixed} value The value to set
8017 setValue : function(v){
8020 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8026 processValue : function(value){
8027 if(this.stripCharsRe){
8028 var newValue = value.replace(this.stripCharsRe, '');
8029 if(newValue !== value){
8030 this.setRawValue(newValue);
8037 preFocus : function(){
8039 if(this.selectOnFocus){
8040 this.inputEl().dom.select();
8043 filterKeys : function(e){
8045 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8048 var c = e.getCharCode(), cc = String.fromCharCode(c);
8049 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8052 if(!this.maskRe.test(cc)){
8057 * Clear any invalid styles/messages for this field
8059 clearInvalid : function(){
8061 if(!this.el || this.preventMark){ // not rendered
8064 this.el.removeClass(this.invalidClass);
8066 this.fireEvent('valid', this);
8070 * Mark this field as valid
8072 markValid : function(){
8073 if(!this.el || this.preventMark){ // not rendered
8077 this.el.removeClass([this.invalidClass, this.validClass]);
8079 if(this.disabled || this.allowBlank){
8083 this.el.addClass(this.validClass);
8085 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8087 var feedback = this.el.select('.form-control-feedback', true).first();
8090 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8091 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8096 this.fireEvent('valid', this);
8100 * Mark this field as invalid
8101 * @param {String} msg The validation message
8103 markInvalid : function(msg){
8104 if(!this.el || this.preventMark){ // not rendered
8108 this.el.removeClass([this.invalidClass, this.validClass]);
8110 if(this.disabled || this.allowBlank){
8114 this.el.addClass(this.invalidClass);
8116 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8118 var feedback = this.el.select('.form-control-feedback', true).first();
8121 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8123 if(this.getValue().length){
8124 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8131 this.fireEvent('invalid', this, msg);
8134 SafariOnKeyDown : function(event)
8136 // this is a workaround for a password hang bug on chrome/ webkit.
8138 var isSelectAll = false;
8140 if(this.inputEl().dom.selectionEnd > 0){
8141 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8143 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8144 event.preventDefault();
8149 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8151 event.preventDefault();
8152 // this is very hacky as keydown always get's upper case.
8154 var cc = String.fromCharCode(event.getCharCode());
8155 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8159 adjustWidth : function(tag, w){
8160 tag = tag.toLowerCase();
8161 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8162 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8166 if(tag == 'textarea'){
8169 }else if(Roo.isOpera){
8173 if(tag == 'textarea'){
8192 * @class Roo.bootstrap.TextArea
8193 * @extends Roo.bootstrap.Input
8194 * Bootstrap TextArea class
8195 * @cfg {Number} cols Specifies the visible width of a text area
8196 * @cfg {Number} rows Specifies the visible number of lines in a text area
8197 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8198 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8199 * @cfg {string} html text
8202 * Create a new TextArea
8203 * @param {Object} config The config object
8206 Roo.bootstrap.TextArea = function(config){
8207 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8211 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8221 getAutoCreate : function(){
8223 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8234 value : this.value || '',
8235 html: this.html || '',
8236 cls : 'form-control',
8237 placeholder : this.placeholder || ''
8241 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8242 input.maxLength = this.maxLength;
8246 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8250 input.cols = this.cols;
8253 if (this.readOnly) {
8254 input.readonly = true;
8258 input.name = this.name;
8262 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8266 ['xs','sm','md','lg'].map(function(size){
8267 if (settings[size]) {
8268 cfg.cls += ' col-' + size + '-' + settings[size];
8272 var inputblock = input;
8274 if(this.hasFeedback && !this.allowBlank){
8278 cls: 'glyphicon form-control-feedback'
8282 cls : 'has-feedback',
8291 if (this.before || this.after) {
8294 cls : 'input-group',
8298 inputblock.cn.push({
8300 cls : 'input-group-addon',
8305 inputblock.cn.push(input);
8307 if(this.hasFeedback && !this.allowBlank){
8308 inputblock.cls += ' has-feedback';
8309 inputblock.cn.push(feedback);
8313 inputblock.cn.push({
8315 cls : 'input-group-addon',
8322 if (align ==='left' && this.fieldLabel.length) {
8323 Roo.log("left and has label");
8329 cls : 'control-label col-sm-' + this.labelWidth,
8330 html : this.fieldLabel
8334 cls : "col-sm-" + (12 - this.labelWidth),
8341 } else if ( this.fieldLabel.length) {
8347 //cls : 'input-group-addon',
8348 html : this.fieldLabel
8358 Roo.log(" no label && no align");
8368 if (this.disabled) {
8369 input.disabled=true;
8376 * return the real textarea element.
8378 inputEl: function ()
8380 return this.el.select('textarea.form-control',true).first();
8388 * trigger field - base class for combo..
8393 * @class Roo.bootstrap.TriggerField
8394 * @extends Roo.bootstrap.Input
8395 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8396 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8397 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8398 * for which you can provide a custom implementation. For example:
8400 var trigger = new Roo.bootstrap.TriggerField();
8401 trigger.onTriggerClick = myTriggerFn;
8402 trigger.applyTo('my-field');
8405 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8406 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8407 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8408 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8409 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8412 * Create a new TriggerField.
8413 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8414 * to the base TextField)
8416 Roo.bootstrap.TriggerField = function(config){
8417 this.mimicing = false;
8418 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8421 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8423 * @cfg {String} triggerClass A CSS class to apply to the trigger
8426 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8430 /** @cfg {Boolean} grow @hide */
8431 /** @cfg {Number} growMin @hide */
8432 /** @cfg {Number} growMax @hide */
8438 autoSize: Roo.emptyFn,
8445 actionMode : 'wrap',
8450 getAutoCreate : function(){
8452 var align = this.labelAlign || this.parentLabelAlign();
8457 cls: 'form-group' //input-group
8464 type : this.inputType,
8465 cls : 'form-control',
8466 autocomplete: 'new-password',
8467 placeholder : this.placeholder || ''
8471 input.name = this.name;
8474 input.cls += ' input-' + this.size;
8477 if (this.disabled) {
8478 input.disabled=true;
8481 var inputblock = input;
8483 if(this.hasFeedback && !this.allowBlank){
8487 cls: 'glyphicon form-control-feedback'
8491 cls : 'has-feedback',
8499 if (this.before || this.after) {
8502 cls : 'input-group',
8506 inputblock.cn.push({
8508 cls : 'input-group-addon',
8513 inputblock.cn.push(input);
8515 if(this.hasFeedback && !this.allowBlank){
8516 inputblock.cls += ' has-feedback';
8517 inputblock.cn.push(feedback);
8521 inputblock.cn.push({
8523 cls : 'input-group-addon',
8536 cls: 'form-hidden-field'
8544 Roo.log('multiple');
8552 cls: 'form-hidden-field'
8556 cls: 'select2-choices',
8560 cls: 'select2-search-field',
8573 cls: 'select2-container input-group',
8578 // cls: 'typeahead typeahead-long dropdown-menu',
8579 // style: 'display:none'
8584 if(!this.multiple && this.showToggleBtn){
8590 if (this.caret != false) {
8593 cls: 'fa fa-' + this.caret
8600 cls : 'input-group-addon btn dropdown-toggle',
8605 cls: 'combobox-clear',
8619 combobox.cls += ' select2-container-multi';
8622 if (align ==='left' && this.fieldLabel.length) {
8624 Roo.log("left and has label");
8630 cls : 'control-label col-sm-' + this.labelWidth,
8631 html : this.fieldLabel
8635 cls : "col-sm-" + (12 - this.labelWidth),
8642 } else if ( this.fieldLabel.length) {
8648 //cls : 'input-group-addon',
8649 html : this.fieldLabel
8659 Roo.log(" no label && no align");
8666 ['xs','sm','md','lg'].map(function(size){
8667 if (settings[size]) {
8668 cfg.cls += ' col-' + size + '-' + settings[size];
8679 onResize : function(w, h){
8680 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8681 // if(typeof w == 'number'){
8682 // var x = w - this.trigger.getWidth();
8683 // this.inputEl().setWidth(this.adjustWidth('input', x));
8684 // this.trigger.setStyle('left', x+'px');
8689 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8692 getResizeEl : function(){
8693 return this.inputEl();
8697 getPositionEl : function(){
8698 return this.inputEl();
8702 alignErrorIcon : function(){
8703 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8707 initEvents : function(){
8711 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8712 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8713 if(!this.multiple && this.showToggleBtn){
8714 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8715 if(this.hideTrigger){
8716 this.trigger.setDisplayed(false);
8718 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8722 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8725 //this.trigger.addClassOnOver('x-form-trigger-over');
8726 //this.trigger.addClassOnClick('x-form-trigger-click');
8729 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8733 createList : function()
8735 this.list = Roo.get(document.body).createChild({
8737 cls: 'typeahead typeahead-long dropdown-menu',
8738 style: 'display:none'
8741 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8746 initTrigger : function(){
8751 onDestroy : function(){
8753 this.trigger.removeAllListeners();
8754 // this.trigger.remove();
8757 // this.wrap.remove();
8759 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8763 onFocus : function(){
8764 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8767 this.wrap.addClass('x-trigger-wrap-focus');
8768 this.mimicing = true;
8769 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8770 if(this.monitorTab){
8771 this.el.on("keydown", this.checkTab, this);
8778 checkTab : function(e){
8779 if(e.getKey() == e.TAB){
8785 onBlur : function(){
8790 mimicBlur : function(e, t){
8792 if(!this.wrap.contains(t) && this.validateBlur()){
8799 triggerBlur : function(){
8800 this.mimicing = false;
8801 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8802 if(this.monitorTab){
8803 this.el.un("keydown", this.checkTab, this);
8805 //this.wrap.removeClass('x-trigger-wrap-focus');
8806 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8810 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8811 validateBlur : function(e, t){
8816 onDisable : function(){
8817 this.inputEl().dom.disabled = true;
8818 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8820 // this.wrap.addClass('x-item-disabled');
8825 onEnable : function(){
8826 this.inputEl().dom.disabled = false;
8827 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8829 // this.el.removeClass('x-item-disabled');
8834 onShow : function(){
8835 var ae = this.getActionEl();
8838 ae.dom.style.display = '';
8839 ae.dom.style.visibility = 'visible';
8845 onHide : function(){
8846 var ae = this.getActionEl();
8847 ae.dom.style.display = 'none';
8851 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8852 * by an implementing function.
8854 * @param {EventObject} e
8856 onTriggerClick : Roo.emptyFn
8860 * Ext JS Library 1.1.1
8861 * Copyright(c) 2006-2007, Ext JS, LLC.
8863 * Originally Released Under LGPL - original licence link has changed is not relivant.
8866 * <script type="text/javascript">
8871 * @class Roo.data.SortTypes
8873 * Defines the default sorting (casting?) comparison functions used when sorting data.
8875 Roo.data.SortTypes = {
8877 * Default sort that does nothing
8878 * @param {Mixed} s The value being converted
8879 * @return {Mixed} The comparison value
8886 * The regular expression used to strip tags
8890 stripTagsRE : /<\/?[^>]+>/gi,
8893 * Strips all HTML tags to sort on text only
8894 * @param {Mixed} s The value being converted
8895 * @return {String} The comparison value
8897 asText : function(s){
8898 return String(s).replace(this.stripTagsRE, "");
8902 * Strips all HTML tags to sort on text only - Case insensitive
8903 * @param {Mixed} s The value being converted
8904 * @return {String} The comparison value
8906 asUCText : function(s){
8907 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8911 * Case insensitive string
8912 * @param {Mixed} s The value being converted
8913 * @return {String} The comparison value
8915 asUCString : function(s) {
8916 return String(s).toUpperCase();
8921 * @param {Mixed} s The value being converted
8922 * @return {Number} The comparison value
8924 asDate : function(s) {
8928 if(s instanceof Date){
8931 return Date.parse(String(s));
8936 * @param {Mixed} s The value being converted
8937 * @return {Float} The comparison value
8939 asFloat : function(s) {
8940 var val = parseFloat(String(s).replace(/,/g, ""));
8941 if(isNaN(val)) val = 0;
8947 * @param {Mixed} s The value being converted
8948 * @return {Number} The comparison value
8950 asInt : function(s) {
8951 var val = parseInt(String(s).replace(/,/g, ""));
8952 if(isNaN(val)) val = 0;
8957 * Ext JS Library 1.1.1
8958 * Copyright(c) 2006-2007, Ext JS, LLC.
8960 * Originally Released Under LGPL - original licence link has changed is not relivant.
8963 * <script type="text/javascript">
8967 * @class Roo.data.Record
8968 * Instances of this class encapsulate both record <em>definition</em> information, and record
8969 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8970 * to access Records cached in an {@link Roo.data.Store} object.<br>
8972 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8973 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8976 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8978 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8979 * {@link #create}. The parameters are the same.
8980 * @param {Array} data An associative Array of data values keyed by the field name.
8981 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8982 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8983 * not specified an integer id is generated.
8985 Roo.data.Record = function(data, id){
8986 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8991 * Generate a constructor for a specific record layout.
8992 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8993 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8994 * Each field definition object may contain the following properties: <ul>
8995 * <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,
8996 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8997 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8998 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8999 * is being used, then this is a string containing the javascript expression to reference the data relative to
9000 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9001 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9002 * this may be omitted.</p></li>
9003 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9004 * <ul><li>auto (Default, implies no conversion)</li>
9009 * <li>date</li></ul></p></li>
9010 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9011 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9012 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9013 * by the Reader into an object that will be stored in the Record. It is passed the
9014 * following parameters:<ul>
9015 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9017 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9019 * <br>usage:<br><pre><code>
9020 var TopicRecord = Roo.data.Record.create(
9021 {name: 'title', mapping: 'topic_title'},
9022 {name: 'author', mapping: 'username'},
9023 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9024 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9025 {name: 'lastPoster', mapping: 'user2'},
9026 {name: 'excerpt', mapping: 'post_text'}
9029 var myNewRecord = new TopicRecord({
9030 title: 'Do my job please',
9033 lastPost: new Date(),
9034 lastPoster: 'Animal',
9035 excerpt: 'No way dude!'
9037 myStore.add(myNewRecord);
9042 Roo.data.Record.create = function(o){
9044 f.superclass.constructor.apply(this, arguments);
9046 Roo.extend(f, Roo.data.Record);
9047 var p = f.prototype;
9048 p.fields = new Roo.util.MixedCollection(false, function(field){
9051 for(var i = 0, len = o.length; i < len; i++){
9052 p.fields.add(new Roo.data.Field(o[i]));
9054 f.getField = function(name){
9055 return p.fields.get(name);
9060 Roo.data.Record.AUTO_ID = 1000;
9061 Roo.data.Record.EDIT = 'edit';
9062 Roo.data.Record.REJECT = 'reject';
9063 Roo.data.Record.COMMIT = 'commit';
9065 Roo.data.Record.prototype = {
9067 * Readonly flag - true if this record has been modified.
9076 join : function(store){
9081 * Set the named field to the specified value.
9082 * @param {String} name The name of the field to set.
9083 * @param {Object} value The value to set the field to.
9085 set : function(name, value){
9086 if(this.data[name] == value){
9093 if(typeof this.modified[name] == 'undefined'){
9094 this.modified[name] = this.data[name];
9096 this.data[name] = value;
9097 if(!this.editing && this.store){
9098 this.store.afterEdit(this);
9103 * Get the value of the named field.
9104 * @param {String} name The name of the field to get the value of.
9105 * @return {Object} The value of the field.
9107 get : function(name){
9108 return this.data[name];
9112 beginEdit : function(){
9113 this.editing = true;
9118 cancelEdit : function(){
9119 this.editing = false;
9120 delete this.modified;
9124 endEdit : function(){
9125 this.editing = false;
9126 if(this.dirty && this.store){
9127 this.store.afterEdit(this);
9132 * Usually called by the {@link Roo.data.Store} which owns the Record.
9133 * Rejects all changes made to the Record since either creation, or the last commit operation.
9134 * Modified fields are reverted to their original values.
9136 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9137 * of reject operations.
9139 reject : function(){
9140 var m = this.modified;
9142 if(typeof m[n] != "function"){
9143 this.data[n] = m[n];
9147 delete this.modified;
9148 this.editing = false;
9150 this.store.afterReject(this);
9155 * Usually called by the {@link Roo.data.Store} which owns the Record.
9156 * Commits all changes made to the Record since either creation, or the last commit operation.
9158 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9159 * of commit operations.
9161 commit : function(){
9163 delete this.modified;
9164 this.editing = false;
9166 this.store.afterCommit(this);
9171 hasError : function(){
9172 return this.error != null;
9176 clearError : function(){
9181 * Creates a copy of this record.
9182 * @param {String} id (optional) A new record id if you don't want to use this record's id
9185 copy : function(newId) {
9186 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9190 * Ext JS Library 1.1.1
9191 * Copyright(c) 2006-2007, Ext JS, LLC.
9193 * Originally Released Under LGPL - original licence link has changed is not relivant.
9196 * <script type="text/javascript">
9202 * @class Roo.data.Store
9203 * @extends Roo.util.Observable
9204 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9205 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9207 * 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
9208 * has no knowledge of the format of the data returned by the Proxy.<br>
9210 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9211 * instances from the data object. These records are cached and made available through accessor functions.
9213 * Creates a new Store.
9214 * @param {Object} config A config object containing the objects needed for the Store to access data,
9215 * and read the data into Records.
9217 Roo.data.Store = function(config){
9218 this.data = new Roo.util.MixedCollection(false);
9219 this.data.getKey = function(o){
9222 this.baseParams = {};
9229 "multisort" : "_multisort"
9232 if(config && config.data){
9233 this.inlineData = config.data;
9237 Roo.apply(this, config);
9239 if(this.reader){ // reader passed
9240 this.reader = Roo.factory(this.reader, Roo.data);
9241 this.reader.xmodule = this.xmodule || false;
9242 if(!this.recordType){
9243 this.recordType = this.reader.recordType;
9245 if(this.reader.onMetaChange){
9246 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9250 if(this.recordType){
9251 this.fields = this.recordType.prototype.fields;
9257 * @event datachanged
9258 * Fires when the data cache has changed, and a widget which is using this Store
9259 * as a Record cache should refresh its view.
9260 * @param {Store} this
9265 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9266 * @param {Store} this
9267 * @param {Object} meta The JSON metadata
9272 * Fires when Records have been added to the Store
9273 * @param {Store} this
9274 * @param {Roo.data.Record[]} records The array of Records added
9275 * @param {Number} index The index at which the record(s) were added
9280 * Fires when a Record has been removed from the Store
9281 * @param {Store} this
9282 * @param {Roo.data.Record} record The Record that was removed
9283 * @param {Number} index The index at which the record was removed
9288 * Fires when a Record has been updated
9289 * @param {Store} this
9290 * @param {Roo.data.Record} record The Record that was updated
9291 * @param {String} operation The update operation being performed. Value may be one of:
9293 Roo.data.Record.EDIT
9294 Roo.data.Record.REJECT
9295 Roo.data.Record.COMMIT
9301 * Fires when the data cache has been cleared.
9302 * @param {Store} this
9307 * Fires before a request is made for a new data object. If the beforeload handler returns false
9308 * the load action will be canceled.
9309 * @param {Store} this
9310 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9314 * @event beforeloadadd
9315 * Fires after a new set of Records has been loaded.
9316 * @param {Store} this
9317 * @param {Roo.data.Record[]} records The Records that were loaded
9318 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9320 beforeloadadd : true,
9323 * Fires after a new set of Records has been loaded, before they are added to the store.
9324 * @param {Store} this
9325 * @param {Roo.data.Record[]} records The Records that were loaded
9326 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9327 * @params {Object} return from reader
9331 * @event loadexception
9332 * Fires if an exception occurs in the Proxy during loading.
9333 * Called with the signature of the Proxy's "loadexception" event.
9334 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9337 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9338 * @param {Object} load options
9339 * @param {Object} jsonData from your request (normally this contains the Exception)
9341 loadexception : true
9345 this.proxy = Roo.factory(this.proxy, Roo.data);
9346 this.proxy.xmodule = this.xmodule || false;
9347 this.relayEvents(this.proxy, ["loadexception"]);
9349 this.sortToggle = {};
9350 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9352 Roo.data.Store.superclass.constructor.call(this);
9354 if(this.inlineData){
9355 this.loadData(this.inlineData);
9356 delete this.inlineData;
9360 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9362 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9363 * without a remote query - used by combo/forms at present.
9367 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9370 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9373 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9374 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9377 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9378 * on any HTTP request
9381 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9384 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9388 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9389 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9394 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9395 * loaded or when a record is removed. (defaults to false).
9397 pruneModifiedRecords : false,
9403 * Add Records to the Store and fires the add event.
9404 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9406 add : function(records){
9407 records = [].concat(records);
9408 for(var i = 0, len = records.length; i < len; i++){
9409 records[i].join(this);
9411 var index = this.data.length;
9412 this.data.addAll(records);
9413 this.fireEvent("add", this, records, index);
9417 * Remove a Record from the Store and fires the remove event.
9418 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9420 remove : function(record){
9421 var index = this.data.indexOf(record);
9422 this.data.removeAt(index);
9423 if(this.pruneModifiedRecords){
9424 this.modified.remove(record);
9426 this.fireEvent("remove", this, record, index);
9430 * Remove all Records from the Store and fires the clear event.
9432 removeAll : function(){
9434 if(this.pruneModifiedRecords){
9437 this.fireEvent("clear", this);
9441 * Inserts Records to the Store at the given index and fires the add event.
9442 * @param {Number} index The start index at which to insert the passed Records.
9443 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9445 insert : function(index, records){
9446 records = [].concat(records);
9447 for(var i = 0, len = records.length; i < len; i++){
9448 this.data.insert(index, records[i]);
9449 records[i].join(this);
9451 this.fireEvent("add", this, records, index);
9455 * Get the index within the cache of the passed Record.
9456 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9457 * @return {Number} The index of the passed Record. Returns -1 if not found.
9459 indexOf : function(record){
9460 return this.data.indexOf(record);
9464 * Get the index within the cache of the Record with the passed id.
9465 * @param {String} id The id of the Record to find.
9466 * @return {Number} The index of the Record. Returns -1 if not found.
9468 indexOfId : function(id){
9469 return this.data.indexOfKey(id);
9473 * Get the Record with the specified id.
9474 * @param {String} id The id of the Record to find.
9475 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9477 getById : function(id){
9478 return this.data.key(id);
9482 * Get the Record at the specified index.
9483 * @param {Number} index The index of the Record to find.
9484 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9486 getAt : function(index){
9487 return this.data.itemAt(index);
9491 * Returns a range of Records between specified indices.
9492 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9493 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9494 * @return {Roo.data.Record[]} An array of Records
9496 getRange : function(start, end){
9497 return this.data.getRange(start, end);
9501 storeOptions : function(o){
9502 o = Roo.apply({}, o);
9505 this.lastOptions = o;
9509 * Loads the Record cache from the configured Proxy using the configured Reader.
9511 * If using remote paging, then the first load call must specify the <em>start</em>
9512 * and <em>limit</em> properties in the options.params property to establish the initial
9513 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9515 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9516 * and this call will return before the new data has been loaded. Perform any post-processing
9517 * in a callback function, or in a "load" event handler.</strong>
9519 * @param {Object} options An object containing properties which control loading options:<ul>
9520 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9521 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9522 * passed the following arguments:<ul>
9523 * <li>r : Roo.data.Record[]</li>
9524 * <li>options: Options object from the load call</li>
9525 * <li>success: Boolean success indicator</li></ul></li>
9526 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9527 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9530 load : function(options){
9531 options = options || {};
9532 if(this.fireEvent("beforeload", this, options) !== false){
9533 this.storeOptions(options);
9534 var p = Roo.apply(options.params || {}, this.baseParams);
9535 // if meta was not loaded from remote source.. try requesting it.
9536 if (!this.reader.metaFromRemote) {
9539 if(this.sortInfo && this.remoteSort){
9540 var pn = this.paramNames;
9541 p[pn["sort"]] = this.sortInfo.field;
9542 p[pn["dir"]] = this.sortInfo.direction;
9544 if (this.multiSort) {
9545 var pn = this.paramNames;
9546 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9549 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9554 * Reloads the Record cache from the configured Proxy using the configured Reader and
9555 * the options from the last load operation performed.
9556 * @param {Object} options (optional) An object containing properties which may override the options
9557 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9558 * the most recently used options are reused).
9560 reload : function(options){
9561 this.load(Roo.applyIf(options||{}, this.lastOptions));
9565 // Called as a callback by the Reader during a load operation.
9566 loadRecords : function(o, options, success){
9567 if(!o || success === false){
9568 if(success !== false){
9569 this.fireEvent("load", this, [], options, o);
9571 if(options.callback){
9572 options.callback.call(options.scope || this, [], options, false);
9576 // if data returned failure - throw an exception.
9577 if (o.success === false) {
9578 // show a message if no listener is registered.
9579 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9580 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9582 // loadmask wil be hooked into this..
9583 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9586 var r = o.records, t = o.totalRecords || r.length;
9588 this.fireEvent("beforeloadadd", this, r, options, o);
9590 if(!options || options.add !== true){
9591 if(this.pruneModifiedRecords){
9594 for(var i = 0, len = r.length; i < len; i++){
9598 this.data = this.snapshot;
9599 delete this.snapshot;
9602 this.data.addAll(r);
9603 this.totalLength = t;
9605 this.fireEvent("datachanged", this);
9607 this.totalLength = Math.max(t, this.data.length+r.length);
9610 this.fireEvent("load", this, r, options, o);
9611 if(options.callback){
9612 options.callback.call(options.scope || this, r, options, true);
9618 * Loads data from a passed data block. A Reader which understands the format of the data
9619 * must have been configured in the constructor.
9620 * @param {Object} data The data block from which to read the Records. The format of the data expected
9621 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9622 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9624 loadData : function(o, append){
9625 var r = this.reader.readRecords(o);
9626 this.loadRecords(r, {add: append}, true);
9630 * Gets the number of cached records.
9632 * <em>If using paging, this may not be the total size of the dataset. If the data object
9633 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9634 * the data set size</em>
9636 getCount : function(){
9637 return this.data.length || 0;
9641 * Gets the total number of records in the dataset as returned by the server.
9643 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9644 * the dataset size</em>
9646 getTotalCount : function(){
9647 return this.totalLength || 0;
9651 * Returns the sort state of the Store as an object with two properties:
9653 field {String} The name of the field by which the Records are sorted
9654 direction {String} The sort order, "ASC" or "DESC"
9657 getSortState : function(){
9658 return this.sortInfo;
9662 applySort : function(){
9663 if(this.sortInfo && !this.remoteSort){
9664 var s = this.sortInfo, f = s.field;
9665 var st = this.fields.get(f).sortType;
9666 var fn = function(r1, r2){
9667 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9668 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9670 this.data.sort(s.direction, fn);
9671 if(this.snapshot && this.snapshot != this.data){
9672 this.snapshot.sort(s.direction, fn);
9678 * Sets the default sort column and order to be used by the next load operation.
9679 * @param {String} fieldName The name of the field to sort by.
9680 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9682 setDefaultSort : function(field, dir){
9683 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9688 * If remote sorting is used, the sort is performed on the server, and the cache is
9689 * reloaded. If local sorting is used, the cache is sorted internally.
9690 * @param {String} fieldName The name of the field to sort by.
9691 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9693 sort : function(fieldName, dir){
9694 var f = this.fields.get(fieldName);
9696 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9698 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9699 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9704 this.sortToggle[f.name] = dir;
9705 this.sortInfo = {field: f.name, direction: dir};
9706 if(!this.remoteSort){
9708 this.fireEvent("datachanged", this);
9710 this.load(this.lastOptions);
9715 * Calls the specified function for each of the Records in the cache.
9716 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9717 * Returning <em>false</em> aborts and exits the iteration.
9718 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9720 each : function(fn, scope){
9721 this.data.each(fn, scope);
9725 * Gets all records modified since the last commit. Modified records are persisted across load operations
9726 * (e.g., during paging).
9727 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9729 getModifiedRecords : function(){
9730 return this.modified;
9734 createFilterFn : function(property, value, anyMatch){
9735 if(!value.exec){ // not a regex
9736 value = String(value);
9737 if(value.length == 0){
9740 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9743 return value.test(r.data[property]);
9748 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9749 * @param {String} property A field on your records
9750 * @param {Number} start The record index to start at (defaults to 0)
9751 * @param {Number} end The last record index to include (defaults to length - 1)
9752 * @return {Number} The sum
9754 sum : function(property, start, end){
9755 var rs = this.data.items, v = 0;
9757 end = (end || end === 0) ? end : rs.length-1;
9759 for(var i = start; i <= end; i++){
9760 v += (rs[i].data[property] || 0);
9766 * Filter the records by a specified property.
9767 * @param {String} field A field on your records
9768 * @param {String/RegExp} value Either a string that the field
9769 * should start with or a RegExp to test against the field
9770 * @param {Boolean} anyMatch True to match any part not just the beginning
9772 filter : function(property, value, anyMatch){
9773 var fn = this.createFilterFn(property, value, anyMatch);
9774 return fn ? this.filterBy(fn) : this.clearFilter();
9778 * Filter by a function. The specified function will be called with each
9779 * record in this data source. If the function returns true the record is included,
9780 * otherwise it is filtered.
9781 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9782 * @param {Object} scope (optional) The scope of the function (defaults to this)
9784 filterBy : function(fn, scope){
9785 this.snapshot = this.snapshot || this.data;
9786 this.data = this.queryBy(fn, scope||this);
9787 this.fireEvent("datachanged", this);
9791 * Query the records by a specified property.
9792 * @param {String} field A field on your records
9793 * @param {String/RegExp} value Either a string that the field
9794 * should start with or a RegExp to test against the field
9795 * @param {Boolean} anyMatch True to match any part not just the beginning
9796 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9798 query : function(property, value, anyMatch){
9799 var fn = this.createFilterFn(property, value, anyMatch);
9800 return fn ? this.queryBy(fn) : this.data.clone();
9804 * Query by a function. The specified function will be called with each
9805 * record in this data source. If the function returns true the record is included
9807 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9808 * @param {Object} scope (optional) The scope of the function (defaults to this)
9809 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9811 queryBy : function(fn, scope){
9812 var data = this.snapshot || this.data;
9813 return data.filterBy(fn, scope||this);
9817 * Collects unique values for a particular dataIndex from this store.
9818 * @param {String} dataIndex The property to collect
9819 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9820 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9821 * @return {Array} An array of the unique values
9823 collect : function(dataIndex, allowNull, bypassFilter){
9824 var d = (bypassFilter === true && this.snapshot) ?
9825 this.snapshot.items : this.data.items;
9826 var v, sv, r = [], l = {};
9827 for(var i = 0, len = d.length; i < len; i++){
9828 v = d[i].data[dataIndex];
9830 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9839 * Revert to a view of the Record cache with no filtering applied.
9840 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9842 clearFilter : function(suppressEvent){
9843 if(this.snapshot && this.snapshot != this.data){
9844 this.data = this.snapshot;
9845 delete this.snapshot;
9846 if(suppressEvent !== true){
9847 this.fireEvent("datachanged", this);
9853 afterEdit : function(record){
9854 if(this.modified.indexOf(record) == -1){
9855 this.modified.push(record);
9857 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9861 afterReject : function(record){
9862 this.modified.remove(record);
9863 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9867 afterCommit : function(record){
9868 this.modified.remove(record);
9869 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9873 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9874 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9876 commitChanges : function(){
9877 var m = this.modified.slice(0);
9879 for(var i = 0, len = m.length; i < len; i++){
9885 * Cancel outstanding changes on all changed records.
9887 rejectChanges : function(){
9888 var m = this.modified.slice(0);
9890 for(var i = 0, len = m.length; i < len; i++){
9895 onMetaChange : function(meta, rtype, o){
9896 this.recordType = rtype;
9897 this.fields = rtype.prototype.fields;
9898 delete this.snapshot;
9899 this.sortInfo = meta.sortInfo || this.sortInfo;
9901 this.fireEvent('metachange', this, this.reader.meta);
9904 moveIndex : function(data, type)
9906 var index = this.indexOf(data);
9908 var newIndex = index + type;
9912 this.insert(newIndex, data);
9917 * Ext JS Library 1.1.1
9918 * Copyright(c) 2006-2007, Ext JS, LLC.
9920 * Originally Released Under LGPL - original licence link has changed is not relivant.
9923 * <script type="text/javascript">
9927 * @class Roo.data.SimpleStore
9928 * @extends Roo.data.Store
9929 * Small helper class to make creating Stores from Array data easier.
9930 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9931 * @cfg {Array} fields An array of field definition objects, or field name strings.
9932 * @cfg {Array} data The multi-dimensional array of data
9934 * @param {Object} config
9936 Roo.data.SimpleStore = function(config){
9937 Roo.data.SimpleStore.superclass.constructor.call(this, {
9939 reader: new Roo.data.ArrayReader({
9942 Roo.data.Record.create(config.fields)
9944 proxy : new Roo.data.MemoryProxy(config.data)
9948 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9950 * Ext JS Library 1.1.1
9951 * Copyright(c) 2006-2007, Ext JS, LLC.
9953 * Originally Released Under LGPL - original licence link has changed is not relivant.
9956 * <script type="text/javascript">
9961 * @extends Roo.data.Store
9962 * @class Roo.data.JsonStore
9963 * Small helper class to make creating Stores for JSON data easier. <br/>
9965 var store = new Roo.data.JsonStore({
9966 url: 'get-images.php',
9968 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9971 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9972 * JsonReader and HttpProxy (unless inline data is provided).</b>
9973 * @cfg {Array} fields An array of field definition objects, or field name strings.
9975 * @param {Object} config
9977 Roo.data.JsonStore = function(c){
9978 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9979 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9980 reader: new Roo.data.JsonReader(c, c.fields)
9983 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9985 * Ext JS Library 1.1.1
9986 * Copyright(c) 2006-2007, Ext JS, LLC.
9988 * Originally Released Under LGPL - original licence link has changed is not relivant.
9991 * <script type="text/javascript">
9995 Roo.data.Field = function(config){
9996 if(typeof config == "string"){
9997 config = {name: config};
9999 Roo.apply(this, config);
10002 this.type = "auto";
10005 var st = Roo.data.SortTypes;
10006 // named sortTypes are supported, here we look them up
10007 if(typeof this.sortType == "string"){
10008 this.sortType = st[this.sortType];
10011 // set default sortType for strings and dates
10012 if(!this.sortType){
10015 this.sortType = st.asUCString;
10018 this.sortType = st.asDate;
10021 this.sortType = st.none;
10026 var stripRe = /[\$,%]/g;
10028 // prebuilt conversion function for this field, instead of
10029 // switching every time we're reading a value
10031 var cv, dateFormat = this.dateFormat;
10036 cv = function(v){ return v; };
10039 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10043 return v !== undefined && v !== null && v !== '' ?
10044 parseInt(String(v).replace(stripRe, ""), 10) : '';
10049 return v !== undefined && v !== null && v !== '' ?
10050 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10055 cv = function(v){ return v === true || v === "true" || v == 1; };
10062 if(v instanceof Date){
10066 if(dateFormat == "timestamp"){
10067 return new Date(v*1000);
10069 return Date.parseDate(v, dateFormat);
10071 var parsed = Date.parse(v);
10072 return parsed ? new Date(parsed) : null;
10081 Roo.data.Field.prototype = {
10089 * Ext JS Library 1.1.1
10090 * Copyright(c) 2006-2007, Ext JS, LLC.
10092 * Originally Released Under LGPL - original licence link has changed is not relivant.
10095 * <script type="text/javascript">
10098 // Base class for reading structured data from a data source. This class is intended to be
10099 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10102 * @class Roo.data.DataReader
10103 * Base class for reading structured data from a data source. This class is intended to be
10104 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10107 Roo.data.DataReader = function(meta, recordType){
10111 this.recordType = recordType instanceof Array ?
10112 Roo.data.Record.create(recordType) : recordType;
10115 Roo.data.DataReader.prototype = {
10117 * Create an empty record
10118 * @param {Object} data (optional) - overlay some values
10119 * @return {Roo.data.Record} record created.
10121 newRow : function(d) {
10123 this.recordType.prototype.fields.each(function(c) {
10125 case 'int' : da[c.name] = 0; break;
10126 case 'date' : da[c.name] = new Date(); break;
10127 case 'float' : da[c.name] = 0.0; break;
10128 case 'boolean' : da[c.name] = false; break;
10129 default : da[c.name] = ""; break;
10133 return new this.recordType(Roo.apply(da, d));
10138 * Ext JS Library 1.1.1
10139 * Copyright(c) 2006-2007, Ext JS, LLC.
10141 * Originally Released Under LGPL - original licence link has changed is not relivant.
10144 * <script type="text/javascript">
10148 * @class Roo.data.DataProxy
10149 * @extends Roo.data.Observable
10150 * This class is an abstract base class for implementations which provide retrieval of
10151 * unformatted data objects.<br>
10153 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10154 * (of the appropriate type which knows how to parse the data object) to provide a block of
10155 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10157 * Custom implementations must implement the load method as described in
10158 * {@link Roo.data.HttpProxy#load}.
10160 Roo.data.DataProxy = function(){
10163 * @event beforeload
10164 * Fires before a network request is made to retrieve a data object.
10165 * @param {Object} This DataProxy object.
10166 * @param {Object} params The params parameter to the load function.
10171 * Fires before the load method's callback is called.
10172 * @param {Object} This DataProxy object.
10173 * @param {Object} o The data object.
10174 * @param {Object} arg The callback argument object passed to the load function.
10178 * @event loadexception
10179 * Fires if an Exception occurs during data retrieval.
10180 * @param {Object} This DataProxy object.
10181 * @param {Object} o The data object.
10182 * @param {Object} arg The callback argument object passed to the load function.
10183 * @param {Object} e The Exception.
10185 loadexception : true
10187 Roo.data.DataProxy.superclass.constructor.call(this);
10190 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10193 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10197 * Ext JS Library 1.1.1
10198 * Copyright(c) 2006-2007, Ext JS, LLC.
10200 * Originally Released Under LGPL - original licence link has changed is not relivant.
10203 * <script type="text/javascript">
10206 * @class Roo.data.MemoryProxy
10207 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10208 * to the Reader when its load method is called.
10210 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10212 Roo.data.MemoryProxy = function(data){
10216 Roo.data.MemoryProxy.superclass.constructor.call(this);
10220 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10222 * Load data from the requested source (in this case an in-memory
10223 * data object passed to the constructor), read the data object into
10224 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10225 * process that block using the passed callback.
10226 * @param {Object} params This parameter is not used by the MemoryProxy class.
10227 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10228 * object into a block of Roo.data.Records.
10229 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10230 * The function must be passed <ul>
10231 * <li>The Record block object</li>
10232 * <li>The "arg" argument from the load function</li>
10233 * <li>A boolean success indicator</li>
10235 * @param {Object} scope The scope in which to call the callback
10236 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10238 load : function(params, reader, callback, scope, arg){
10239 params = params || {};
10242 result = reader.readRecords(this.data);
10244 this.fireEvent("loadexception", this, arg, null, e);
10245 callback.call(scope, null, arg, false);
10248 callback.call(scope, result, arg, true);
10252 update : function(params, records){
10257 * Ext JS Library 1.1.1
10258 * Copyright(c) 2006-2007, Ext JS, LLC.
10260 * Originally Released Under LGPL - original licence link has changed is not relivant.
10263 * <script type="text/javascript">
10266 * @class Roo.data.HttpProxy
10267 * @extends Roo.data.DataProxy
10268 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10269 * configured to reference a certain URL.<br><br>
10271 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10272 * from which the running page was served.<br><br>
10274 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10276 * Be aware that to enable the browser to parse an XML document, the server must set
10277 * the Content-Type header in the HTTP response to "text/xml".
10279 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10280 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10281 * will be used to make the request.
10283 Roo.data.HttpProxy = function(conn){
10284 Roo.data.HttpProxy.superclass.constructor.call(this);
10285 // is conn a conn config or a real conn?
10287 this.useAjax = !conn || !conn.events;
10291 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10292 // thse are take from connection...
10295 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10298 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10299 * extra parameters to each request made by this object. (defaults to undefined)
10302 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10303 * to each request made by this object. (defaults to undefined)
10306 * @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)
10309 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10312 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10318 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10322 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10323 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10324 * a finer-grained basis than the DataProxy events.
10326 getConnection : function(){
10327 return this.useAjax ? Roo.Ajax : this.conn;
10331 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10332 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10333 * process that block using the passed callback.
10334 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10335 * for the request to the remote server.
10336 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10337 * object into a block of Roo.data.Records.
10338 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10339 * The function must be passed <ul>
10340 * <li>The Record block object</li>
10341 * <li>The "arg" argument from the load function</li>
10342 * <li>A boolean success indicator</li>
10344 * @param {Object} scope The scope in which to call the callback
10345 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10347 load : function(params, reader, callback, scope, arg){
10348 if(this.fireEvent("beforeload", this, params) !== false){
10350 params : params || {},
10352 callback : callback,
10357 callback : this.loadResponse,
10361 Roo.applyIf(o, this.conn);
10362 if(this.activeRequest){
10363 Roo.Ajax.abort(this.activeRequest);
10365 this.activeRequest = Roo.Ajax.request(o);
10367 this.conn.request(o);
10370 callback.call(scope||this, null, arg, false);
10375 loadResponse : function(o, success, response){
10376 delete this.activeRequest;
10378 this.fireEvent("loadexception", this, o, response);
10379 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10384 result = o.reader.read(response);
10386 this.fireEvent("loadexception", this, o, response, e);
10387 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10391 this.fireEvent("load", this, o, o.request.arg);
10392 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10396 update : function(dataSet){
10401 updateResponse : function(dataSet){
10406 * Ext JS Library 1.1.1
10407 * Copyright(c) 2006-2007, Ext JS, LLC.
10409 * Originally Released Under LGPL - original licence link has changed is not relivant.
10412 * <script type="text/javascript">
10416 * @class Roo.data.ScriptTagProxy
10417 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10418 * other than the originating domain of the running page.<br><br>
10420 * <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
10421 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10423 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10424 * source code that is used as the source inside a <script> tag.<br><br>
10426 * In order for the browser to process the returned data, the server must wrap the data object
10427 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10428 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10429 * depending on whether the callback name was passed:
10432 boolean scriptTag = false;
10433 String cb = request.getParameter("callback");
10436 response.setContentType("text/javascript");
10438 response.setContentType("application/x-json");
10440 Writer out = response.getWriter();
10442 out.write(cb + "(");
10444 out.print(dataBlock.toJsonString());
10451 * @param {Object} config A configuration object.
10453 Roo.data.ScriptTagProxy = function(config){
10454 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10455 Roo.apply(this, config);
10456 this.head = document.getElementsByTagName("head")[0];
10459 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10461 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10463 * @cfg {String} url The URL from which to request the data object.
10466 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10470 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10471 * the server the name of the callback function set up by the load call to process the returned data object.
10472 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10473 * javascript output which calls this named function passing the data object as its only parameter.
10475 callbackParam : "callback",
10477 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10478 * name to the request.
10483 * Load data from the configured URL, read the data object into
10484 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10485 * process that block using the passed callback.
10486 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10487 * for the request to the remote server.
10488 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10489 * object into a block of Roo.data.Records.
10490 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10491 * The function must be passed <ul>
10492 * <li>The Record block object</li>
10493 * <li>The "arg" argument from the load function</li>
10494 * <li>A boolean success indicator</li>
10496 * @param {Object} scope The scope in which to call the callback
10497 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10499 load : function(params, reader, callback, scope, arg){
10500 if(this.fireEvent("beforeload", this, params) !== false){
10502 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10504 var url = this.url;
10505 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10507 url += "&_dc=" + (new Date().getTime());
10509 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10512 cb : "stcCallback"+transId,
10513 scriptId : "stcScript"+transId,
10517 callback : callback,
10523 window[trans.cb] = function(o){
10524 conn.handleResponse(o, trans);
10527 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10529 if(this.autoAbort !== false){
10533 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10535 var script = document.createElement("script");
10536 script.setAttribute("src", url);
10537 script.setAttribute("type", "text/javascript");
10538 script.setAttribute("id", trans.scriptId);
10539 this.head.appendChild(script);
10541 this.trans = trans;
10543 callback.call(scope||this, null, arg, false);
10548 isLoading : function(){
10549 return this.trans ? true : false;
10553 * Abort the current server request.
10555 abort : function(){
10556 if(this.isLoading()){
10557 this.destroyTrans(this.trans);
10562 destroyTrans : function(trans, isLoaded){
10563 this.head.removeChild(document.getElementById(trans.scriptId));
10564 clearTimeout(trans.timeoutId);
10566 window[trans.cb] = undefined;
10568 delete window[trans.cb];
10571 // if hasn't been loaded, wait for load to remove it to prevent script error
10572 window[trans.cb] = function(){
10573 window[trans.cb] = undefined;
10575 delete window[trans.cb];
10582 handleResponse : function(o, trans){
10583 this.trans = false;
10584 this.destroyTrans(trans, true);
10587 result = trans.reader.readRecords(o);
10589 this.fireEvent("loadexception", this, o, trans.arg, e);
10590 trans.callback.call(trans.scope||window, null, trans.arg, false);
10593 this.fireEvent("load", this, o, trans.arg);
10594 trans.callback.call(trans.scope||window, result, trans.arg, true);
10598 handleFailure : function(trans){
10599 this.trans = false;
10600 this.destroyTrans(trans, false);
10601 this.fireEvent("loadexception", this, null, trans.arg);
10602 trans.callback.call(trans.scope||window, null, trans.arg, false);
10606 * Ext JS Library 1.1.1
10607 * Copyright(c) 2006-2007, Ext JS, LLC.
10609 * Originally Released Under LGPL - original licence link has changed is not relivant.
10612 * <script type="text/javascript">
10616 * @class Roo.data.JsonReader
10617 * @extends Roo.data.DataReader
10618 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10619 * based on mappings in a provided Roo.data.Record constructor.
10621 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10622 * in the reply previously.
10627 var RecordDef = Roo.data.Record.create([
10628 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10629 {name: 'occupation'} // This field will use "occupation" as the mapping.
10631 var myReader = new Roo.data.JsonReader({
10632 totalProperty: "results", // The property which contains the total dataset size (optional)
10633 root: "rows", // The property which contains an Array of row objects
10634 id: "id" // The property within each row object that provides an ID for the record (optional)
10638 * This would consume a JSON file like this:
10640 { 'results': 2, 'rows': [
10641 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10642 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10645 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10646 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10647 * paged from the remote server.
10648 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10649 * @cfg {String} root name of the property which contains the Array of row objects.
10650 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10652 * Create a new JsonReader
10653 * @param {Object} meta Metadata configuration options
10654 * @param {Object} recordType Either an Array of field definition objects,
10655 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10657 Roo.data.JsonReader = function(meta, recordType){
10660 // set some defaults:
10661 Roo.applyIf(meta, {
10662 totalProperty: 'total',
10663 successProperty : 'success',
10668 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10670 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10673 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10674 * Used by Store query builder to append _requestMeta to params.
10677 metaFromRemote : false,
10679 * This method is only used by a DataProxy which has retrieved data from a remote server.
10680 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10681 * @return {Object} data A data block which is used by an Roo.data.Store object as
10682 * a cache of Roo.data.Records.
10684 read : function(response){
10685 var json = response.responseText;
10687 var o = /* eval:var:o */ eval("("+json+")");
10689 throw {message: "JsonReader.read: Json object not found"};
10695 this.metaFromRemote = true;
10696 this.meta = o.metaData;
10697 this.recordType = Roo.data.Record.create(o.metaData.fields);
10698 this.onMetaChange(this.meta, this.recordType, o);
10700 return this.readRecords(o);
10703 // private function a store will implement
10704 onMetaChange : function(meta, recordType, o){
10711 simpleAccess: function(obj, subsc) {
10718 getJsonAccessor: function(){
10720 return function(expr) {
10722 return(re.test(expr))
10723 ? new Function("obj", "return obj." + expr)
10728 return Roo.emptyFn;
10733 * Create a data block containing Roo.data.Records from an XML document.
10734 * @param {Object} o An object which contains an Array of row objects in the property specified
10735 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10736 * which contains the total size of the dataset.
10737 * @return {Object} data A data block which is used by an Roo.data.Store object as
10738 * a cache of Roo.data.Records.
10740 readRecords : function(o){
10742 * After any data loads, the raw JSON data is available for further custom processing.
10746 var s = this.meta, Record = this.recordType,
10747 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10749 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10751 if(s.totalProperty) {
10752 this.getTotal = this.getJsonAccessor(s.totalProperty);
10754 if(s.successProperty) {
10755 this.getSuccess = this.getJsonAccessor(s.successProperty);
10757 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10759 var g = this.getJsonAccessor(s.id);
10760 this.getId = function(rec) {
10762 return (r === undefined || r === "") ? null : r;
10765 this.getId = function(){return null;};
10768 for(var jj = 0; jj < fl; jj++){
10770 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10771 this.ef[jj] = this.getJsonAccessor(map);
10775 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10776 if(s.totalProperty){
10777 var vt = parseInt(this.getTotal(o), 10);
10782 if(s.successProperty){
10783 var vs = this.getSuccess(o);
10784 if(vs === false || vs === 'false'){
10789 for(var i = 0; i < c; i++){
10792 var id = this.getId(n);
10793 for(var j = 0; j < fl; j++){
10795 var v = this.ef[j](n);
10797 Roo.log('missing convert for ' + f.name);
10801 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10803 var record = new Record(values, id);
10805 records[i] = record;
10811 totalRecords : totalRecords
10816 * Ext JS Library 1.1.1
10817 * Copyright(c) 2006-2007, Ext JS, LLC.
10819 * Originally Released Under LGPL - original licence link has changed is not relivant.
10822 * <script type="text/javascript">
10826 * @class Roo.data.ArrayReader
10827 * @extends Roo.data.DataReader
10828 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10829 * Each element of that Array represents a row of data fields. The
10830 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10831 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10835 var RecordDef = Roo.data.Record.create([
10836 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10837 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10839 var myReader = new Roo.data.ArrayReader({
10840 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10844 * This would consume an Array like this:
10846 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10848 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10850 * Create a new JsonReader
10851 * @param {Object} meta Metadata configuration options.
10852 * @param {Object} recordType Either an Array of field definition objects
10853 * as specified to {@link Roo.data.Record#create},
10854 * or an {@link Roo.data.Record} object
10855 * created using {@link Roo.data.Record#create}.
10857 Roo.data.ArrayReader = function(meta, recordType){
10858 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10861 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10863 * Create a data block containing Roo.data.Records from an XML document.
10864 * @param {Object} o An Array of row objects which represents the dataset.
10865 * @return {Object} data A data block which is used by an Roo.data.Store object as
10866 * a cache of Roo.data.Records.
10868 readRecords : function(o){
10869 var sid = this.meta ? this.meta.id : null;
10870 var recordType = this.recordType, fields = recordType.prototype.fields;
10873 for(var i = 0; i < root.length; i++){
10876 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10877 for(var j = 0, jlen = fields.length; j < jlen; j++){
10878 var f = fields.items[j];
10879 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10880 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10882 values[f.name] = v;
10884 var record = new recordType(values, id);
10886 records[records.length] = record;
10890 totalRecords : records.length
10899 * @class Roo.bootstrap.ComboBox
10900 * @extends Roo.bootstrap.TriggerField
10901 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10902 * @cfg {Boolean} append (true|false) default false
10903 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10904 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10905 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10906 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10907 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10909 * Create a new ComboBox.
10910 * @param {Object} config Configuration options
10912 Roo.bootstrap.ComboBox = function(config){
10913 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10917 * Fires when the dropdown list is expanded
10918 * @param {Roo.bootstrap.ComboBox} combo This combo box
10923 * Fires when the dropdown list is collapsed
10924 * @param {Roo.bootstrap.ComboBox} combo This combo box
10928 * @event beforeselect
10929 * Fires before a list item is selected. Return false to cancel the selection.
10930 * @param {Roo.bootstrap.ComboBox} combo This combo box
10931 * @param {Roo.data.Record} record The data record returned from the underlying store
10932 * @param {Number} index The index of the selected item in the dropdown list
10934 'beforeselect' : true,
10937 * Fires when a list item is selected
10938 * @param {Roo.bootstrap.ComboBox} combo This combo box
10939 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10940 * @param {Number} index The index of the selected item in the dropdown list
10944 * @event beforequery
10945 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10946 * The event object passed has these properties:
10947 * @param {Roo.bootstrap.ComboBox} combo This combo box
10948 * @param {String} query The query
10949 * @param {Boolean} forceAll true to force "all" query
10950 * @param {Boolean} cancel true to cancel the query
10951 * @param {Object} e The query event object
10953 'beforequery': true,
10956 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10957 * @param {Roo.bootstrap.ComboBox} combo This combo box
10962 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10963 * @param {Roo.bootstrap.ComboBox} combo This combo box
10964 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10969 * Fires when the remove value from the combobox array
10970 * @param {Roo.bootstrap.ComboBox} combo This combo box
10974 * @event specialfilter
10975 * Fires when specialfilter
10976 * @param {Roo.bootstrap.ComboBox} combo This combo box
10978 'specialfilter' : true
10983 this.tickItems = [];
10985 this.selectedIndex = -1;
10986 if(this.mode == 'local'){
10987 if(config.queryDelay === undefined){
10988 this.queryDelay = 10;
10990 if(config.minChars === undefined){
10996 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10999 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11000 * rendering into an Roo.Editor, defaults to false)
11003 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11004 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11007 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11010 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11011 * the dropdown list (defaults to undefined, with no header element)
11015 * @cfg {String/Roo.Template} tpl The template to use to render the output
11019 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11021 listWidth: undefined,
11023 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11024 * mode = 'remote' or 'text' if mode = 'local')
11026 displayField: undefined,
11029 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11030 * mode = 'remote' or 'value' if mode = 'local').
11031 * Note: use of a valueField requires the user make a selection
11032 * in order for a value to be mapped.
11034 valueField: undefined,
11038 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11039 * field's data value (defaults to the underlying DOM element's name)
11041 hiddenName: undefined,
11043 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11047 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11049 selectedClass: 'active',
11052 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11056 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11057 * anchor positions (defaults to 'tl-bl')
11059 listAlign: 'tl-bl?',
11061 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11065 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11066 * query specified by the allQuery config option (defaults to 'query')
11068 triggerAction: 'query',
11070 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11071 * (defaults to 4, does not apply if editable = false)
11075 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11076 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11080 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11081 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11085 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11086 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11090 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11091 * when editable = true (defaults to false)
11093 selectOnFocus:false,
11095 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11097 queryParam: 'query',
11099 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11100 * when mode = 'remote' (defaults to 'Loading...')
11102 loadingText: 'Loading...',
11104 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11108 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11112 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11113 * traditional select (defaults to true)
11117 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11121 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11125 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11126 * listWidth has a higher value)
11130 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11131 * allow the user to set arbitrary text into the field (defaults to false)
11133 forceSelection:false,
11135 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11136 * if typeAhead = true (defaults to 250)
11138 typeAheadDelay : 250,
11140 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11141 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11143 valueNotFoundText : undefined,
11145 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11147 blockFocus : false,
11150 * @cfg {Boolean} disableClear Disable showing of clear button.
11152 disableClear : false,
11154 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11156 alwaysQuery : false,
11159 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11164 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11166 invalidClass : "has-warning",
11169 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11171 validClass : "has-success",
11174 * @cfg {Boolean} specialFilter (true|false) special filter default false
11176 specialFilter : false,
11188 btnPosition : 'right',
11189 triggerList : true,
11190 showToggleBtn : true,
11191 // element that contains real text value.. (when hidden is used..)
11193 getAutoCreate : function()
11200 if(!this.tickable){
11201 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11206 * ComboBox with tickable selections
11209 var align = this.labelAlign || this.parentLabelAlign();
11212 cls : 'form-group roo-combobox-tickable' //input-group
11217 cls : 'tickable-buttons',
11222 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11229 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11236 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11243 buttons.cn.unshift({
11245 cls: 'select2-search-field-input'
11251 Roo.each(buttons.cn, function(c){
11253 c.cls += ' btn-' + _this.size;
11256 if (_this.disabled) {
11267 cls: 'form-hidden-field'
11271 cls: 'select2-choices',
11275 cls: 'select2-search-field',
11287 cls: 'select2-container input-group select2-container-multi',
11292 // cls: 'typeahead typeahead-long dropdown-menu',
11293 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11298 if(this.hasFeedback && !this.allowBlank){
11302 cls: 'glyphicon form-control-feedback'
11305 combobox.cn.push(feedback);
11308 if (align ==='left' && this.fieldLabel.length) {
11310 Roo.log("left and has label");
11316 cls : 'control-label col-sm-' + this.labelWidth,
11317 html : this.fieldLabel
11321 cls : "col-sm-" + (12 - this.labelWidth),
11328 } else if ( this.fieldLabel.length) {
11334 //cls : 'input-group-addon',
11335 html : this.fieldLabel
11345 Roo.log(" no label && no align");
11352 ['xs','sm','md','lg'].map(function(size){
11353 if (settings[size]) {
11354 cfg.cls += ' col-' + size + '-' + settings[size];
11363 initEvents: function()
11367 throw "can not find store for combo";
11369 this.store = Roo.factory(this.store, Roo.data);
11372 this.initTickableEvents();
11376 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11378 if(this.hiddenName){
11380 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11382 this.hiddenField.dom.value =
11383 this.hiddenValue !== undefined ? this.hiddenValue :
11384 this.value !== undefined ? this.value : '';
11386 // prevent input submission
11387 this.el.dom.removeAttribute('name');
11388 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11393 // this.el.dom.setAttribute('autocomplete', 'off');
11396 var cls = 'x-combo-list';
11398 //this.list = new Roo.Layer({
11399 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11405 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11406 _this.list.setWidth(lw);
11409 this.list.on('mouseover', this.onViewOver, this);
11410 this.list.on('mousemove', this.onViewMove, this);
11412 this.list.on('scroll', this.onViewScroll, this);
11415 this.list.swallowEvent('mousewheel');
11416 this.assetHeight = 0;
11419 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11420 this.assetHeight += this.header.getHeight();
11423 this.innerList = this.list.createChild({cls:cls+'-inner'});
11424 this.innerList.on('mouseover', this.onViewOver, this);
11425 this.innerList.on('mousemove', this.onViewMove, this);
11426 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11428 if(this.allowBlank && !this.pageSize && !this.disableClear){
11429 this.footer = this.list.createChild({cls:cls+'-ft'});
11430 this.pageTb = new Roo.Toolbar(this.footer);
11434 this.footer = this.list.createChild({cls:cls+'-ft'});
11435 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11436 {pageSize: this.pageSize});
11440 if (this.pageTb && this.allowBlank && !this.disableClear) {
11442 this.pageTb.add(new Roo.Toolbar.Fill(), {
11443 cls: 'x-btn-icon x-btn-clear',
11445 handler: function()
11448 _this.clearValue();
11449 _this.onSelect(false, -1);
11454 this.assetHeight += this.footer.getHeight();
11459 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11462 this.view = new Roo.View(this.list, this.tpl, {
11463 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11465 //this.view.wrapEl.setDisplayed(false);
11466 this.view.on('click', this.onViewClick, this);
11470 this.store.on('beforeload', this.onBeforeLoad, this);
11471 this.store.on('load', this.onLoad, this);
11472 this.store.on('loadexception', this.onLoadException, this);
11474 if(this.resizable){
11475 this.resizer = new Roo.Resizable(this.list, {
11476 pinned:true, handles:'se'
11478 this.resizer.on('resize', function(r, w, h){
11479 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11480 this.listWidth = w;
11481 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11482 this.restrictHeight();
11484 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11487 if(!this.editable){
11488 this.editable = true;
11489 this.setEditable(false);
11494 if (typeof(this.events.add.listeners) != 'undefined') {
11496 this.addicon = this.wrap.createChild(
11497 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11499 this.addicon.on('click', function(e) {
11500 this.fireEvent('add', this);
11503 if (typeof(this.events.edit.listeners) != 'undefined') {
11505 this.editicon = this.wrap.createChild(
11506 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11507 if (this.addicon) {
11508 this.editicon.setStyle('margin-left', '40px');
11510 this.editicon.on('click', function(e) {
11512 // we fire even if inothing is selected..
11513 this.fireEvent('edit', this, this.lastData );
11519 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11520 "up" : function(e){
11521 this.inKeyMode = true;
11525 "down" : function(e){
11526 if(!this.isExpanded()){
11527 this.onTriggerClick();
11529 this.inKeyMode = true;
11534 "enter" : function(e){
11535 // this.onViewClick();
11539 if(this.fireEvent("specialkey", this, e)){
11540 this.onViewClick(false);
11546 "esc" : function(e){
11550 "tab" : function(e){
11553 if(this.fireEvent("specialkey", this, e)){
11554 this.onViewClick(false);
11562 doRelay : function(foo, bar, hname){
11563 if(hname == 'down' || this.scope.isExpanded()){
11564 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11573 this.queryDelay = Math.max(this.queryDelay || 10,
11574 this.mode == 'local' ? 10 : 250);
11577 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11579 if(this.typeAhead){
11580 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11582 if(this.editable !== false){
11583 this.inputEl().on("keyup", this.onKeyUp, this);
11585 if(this.forceSelection){
11586 this.inputEl().on('blur', this.doForce, this);
11590 this.choices = this.el.select('ul.select2-choices', true).first();
11591 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11595 initTickableEvents: function()
11599 if(this.hiddenName){
11601 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11603 this.hiddenField.dom.value =
11604 this.hiddenValue !== undefined ? this.hiddenValue :
11605 this.value !== undefined ? this.value : '';
11607 // prevent input submission
11608 this.el.dom.removeAttribute('name');
11609 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11614 // this.list = this.el.select('ul.dropdown-menu',true).first();
11616 this.choices = this.el.select('ul.select2-choices', true).first();
11617 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11618 if(this.triggerList){
11619 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11622 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11623 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11625 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11626 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11628 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11629 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11631 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11632 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11633 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11636 this.cancelBtn.hide();
11641 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11642 _this.list.setWidth(lw);
11645 this.list.on('mouseover', this.onViewOver, this);
11646 this.list.on('mousemove', this.onViewMove, this);
11648 this.list.on('scroll', this.onViewScroll, this);
11651 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>';
11654 this.view = new Roo.View(this.list, this.tpl, {
11655 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11658 //this.view.wrapEl.setDisplayed(false);
11659 this.view.on('click', this.onViewClick, this);
11663 this.store.on('beforeload', this.onBeforeLoad, this);
11664 this.store.on('load', this.onLoad, this);
11665 this.store.on('loadexception', this.onLoadException, this);
11668 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11669 "up" : function(e){
11670 this.inKeyMode = true;
11674 "down" : function(e){
11675 this.inKeyMode = true;
11679 "enter" : function(e){
11680 if(this.fireEvent("specialkey", this, e)){
11681 this.onViewClick(false);
11687 "esc" : function(e){
11688 this.onTickableFooterButtonClick(e, false, false);
11691 "tab" : function(e){
11692 this.fireEvent("specialkey", this, e);
11694 this.onTickableFooterButtonClick(e, false, false);
11701 doRelay : function(e, fn, key){
11702 if(this.scope.isExpanded()){
11703 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11712 this.queryDelay = Math.max(this.queryDelay || 10,
11713 this.mode == 'local' ? 10 : 250);
11716 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11718 if(this.typeAhead){
11719 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11722 if(this.editable !== false){
11723 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11728 onDestroy : function(){
11730 this.view.setStore(null);
11731 this.view.el.removeAllListeners();
11732 this.view.el.remove();
11733 this.view.purgeListeners();
11736 this.list.dom.innerHTML = '';
11740 this.store.un('beforeload', this.onBeforeLoad, this);
11741 this.store.un('load', this.onLoad, this);
11742 this.store.un('loadexception', this.onLoadException, this);
11744 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11748 fireKey : function(e){
11749 if(e.isNavKeyPress() && !this.list.isVisible()){
11750 this.fireEvent("specialkey", this, e);
11755 onResize: function(w, h){
11756 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11758 // if(typeof w != 'number'){
11759 // // we do not handle it!?!?
11762 // var tw = this.trigger.getWidth();
11763 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11764 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11766 // this.inputEl().setWidth( this.adjustWidth('input', x));
11768 // //this.trigger.setStyle('left', x+'px');
11770 // if(this.list && this.listWidth === undefined){
11771 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11772 // this.list.setWidth(lw);
11773 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11781 * Allow or prevent the user from directly editing the field text. If false is passed,
11782 * the user will only be able to select from the items defined in the dropdown list. This method
11783 * is the runtime equivalent of setting the 'editable' config option at config time.
11784 * @param {Boolean} value True to allow the user to directly edit the field text
11786 setEditable : function(value){
11787 if(value == this.editable){
11790 this.editable = value;
11792 this.inputEl().dom.setAttribute('readOnly', true);
11793 this.inputEl().on('mousedown', this.onTriggerClick, this);
11794 this.inputEl().addClass('x-combo-noedit');
11796 this.inputEl().dom.setAttribute('readOnly', false);
11797 this.inputEl().un('mousedown', this.onTriggerClick, this);
11798 this.inputEl().removeClass('x-combo-noedit');
11804 onBeforeLoad : function(combo,opts){
11805 if(!this.hasFocus){
11809 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11811 this.restrictHeight();
11812 this.selectedIndex = -1;
11816 onLoad : function(){
11818 this.hasQuery = false;
11820 if(!this.hasFocus){
11824 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11825 this.loading.hide();
11828 if(this.store.getCount() > 0){
11830 this.restrictHeight();
11831 if(this.lastQuery == this.allQuery){
11832 if(this.editable && !this.tickable){
11833 this.inputEl().dom.select();
11837 !this.selectByValue(this.value, true) &&
11840 !this.store.lastOptions ||
11841 typeof(this.store.lastOptions.add) == 'undefined' ||
11842 this.store.lastOptions.add != true
11845 this.select(0, true);
11848 if(this.autoFocus){
11851 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11852 this.taTask.delay(this.typeAheadDelay);
11856 this.onEmptyResults();
11862 onLoadException : function()
11864 this.hasQuery = false;
11866 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11867 this.loading.hide();
11870 if(this.tickable && this.editable){
11876 Roo.log(this.store.reader.jsonData);
11877 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11879 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11885 onTypeAhead : function(){
11886 if(this.store.getCount() > 0){
11887 var r = this.store.getAt(0);
11888 var newValue = r.data[this.displayField];
11889 var len = newValue.length;
11890 var selStart = this.getRawValue().length;
11892 if(selStart != len){
11893 this.setRawValue(newValue);
11894 this.selectText(selStart, newValue.length);
11900 onSelect : function(record, index){
11902 if(this.fireEvent('beforeselect', this, record, index) !== false){
11904 this.setFromData(index > -1 ? record.data : false);
11907 this.fireEvent('select', this, record, index);
11912 * Returns the currently selected field value or empty string if no value is set.
11913 * @return {String} value The selected value
11915 getValue : function(){
11918 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11921 if(this.valueField){
11922 return typeof this.value != 'undefined' ? this.value : '';
11924 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11929 * Clears any text/value currently set in the field
11931 clearValue : function(){
11932 if(this.hiddenField){
11933 this.hiddenField.dom.value = '';
11936 this.setRawValue('');
11937 this.lastSelectionText = '';
11938 this.lastData = false;
11943 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11944 * will be displayed in the field. If the value does not match the data value of an existing item,
11945 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11946 * Otherwise the field will be blank (although the value will still be set).
11947 * @param {String} value The value to match
11949 setValue : function(v){
11956 if(this.valueField){
11957 var r = this.findRecord(this.valueField, v);
11959 text = r.data[this.displayField];
11960 }else if(this.valueNotFoundText !== undefined){
11961 text = this.valueNotFoundText;
11964 this.lastSelectionText = text;
11965 if(this.hiddenField){
11966 this.hiddenField.dom.value = v;
11968 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11972 * @property {Object} the last set data for the element
11977 * Sets the value of the field based on a object which is related to the record format for the store.
11978 * @param {Object} value the value to set as. or false on reset?
11980 setFromData : function(o){
11987 var dv = ''; // display value
11988 var vv = ''; // value value..
11990 if (this.displayField) {
11991 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11993 // this is an error condition!!!
11994 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11997 if(this.valueField){
11998 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12001 if(this.hiddenField){
12002 this.hiddenField.dom.value = vv;
12004 this.lastSelectionText = dv;
12005 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12009 // no hidden field.. - we store the value in 'value', but still display
12010 // display field!!!!
12011 this.lastSelectionText = dv;
12012 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12018 reset : function(){
12019 // overridden so that last data is reset..
12026 this.setValue(this.originalValue);
12027 this.clearInvalid();
12028 this.lastData = false;
12030 this.view.clearSelections();
12034 findRecord : function(prop, value){
12036 if(this.store.getCount() > 0){
12037 this.store.each(function(r){
12038 if(r.data[prop] == value){
12048 getName: function()
12050 // returns hidden if it's set..
12051 if (!this.rendered) {return ''};
12052 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12056 onViewMove : function(e, t){
12057 this.inKeyMode = false;
12061 onViewOver : function(e, t){
12062 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12065 var item = this.view.findItemFromChild(t);
12068 var index = this.view.indexOf(item);
12069 this.select(index, false);
12074 onViewClick : function(view, doFocus, el, e)
12076 var index = this.view.getSelectedIndexes()[0];
12078 var r = this.store.getAt(index);
12082 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12089 Roo.each(this.tickItems, function(v,k){
12091 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12092 _this.tickItems.splice(k, 1);
12094 if(typeof(e) == 'undefined' && view == false){
12095 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12107 this.tickItems.push(r.data);
12109 if(typeof(e) == 'undefined' && view == false){
12110 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12117 this.onSelect(r, index);
12119 if(doFocus !== false && !this.blockFocus){
12120 this.inputEl().focus();
12125 restrictHeight : function(){
12126 //this.innerList.dom.style.height = '';
12127 //var inner = this.innerList.dom;
12128 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12129 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12130 //this.list.beginUpdate();
12131 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12132 this.list.alignTo(this.inputEl(), this.listAlign);
12133 this.list.alignTo(this.inputEl(), this.listAlign);
12134 //this.list.endUpdate();
12138 onEmptyResults : function(){
12140 if(this.tickable && this.editable){
12141 this.restrictHeight();
12149 * Returns true if the dropdown list is expanded, else false.
12151 isExpanded : function(){
12152 return this.list.isVisible();
12156 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12157 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12158 * @param {String} value The data value of the item to select
12159 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12160 * selected item if it is not currently in view (defaults to true)
12161 * @return {Boolean} True if the value matched an item in the list, else false
12163 selectByValue : function(v, scrollIntoView){
12164 if(v !== undefined && v !== null){
12165 var r = this.findRecord(this.valueField || this.displayField, v);
12167 this.select(this.store.indexOf(r), scrollIntoView);
12175 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12176 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12177 * @param {Number} index The zero-based index of the list item to select
12178 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12179 * selected item if it is not currently in view (defaults to true)
12181 select : function(index, scrollIntoView){
12182 this.selectedIndex = index;
12183 this.view.select(index);
12184 if(scrollIntoView !== false){
12185 var el = this.view.getNode(index);
12187 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12190 this.list.scrollChildIntoView(el, false);
12196 selectNext : function(){
12197 var ct = this.store.getCount();
12199 if(this.selectedIndex == -1){
12201 }else if(this.selectedIndex < ct-1){
12202 this.select(this.selectedIndex+1);
12208 selectPrev : function(){
12209 var ct = this.store.getCount();
12211 if(this.selectedIndex == -1){
12213 }else if(this.selectedIndex != 0){
12214 this.select(this.selectedIndex-1);
12220 onKeyUp : function(e){
12221 if(this.editable !== false && !e.isSpecialKey()){
12222 this.lastKey = e.getKey();
12223 this.dqTask.delay(this.queryDelay);
12228 validateBlur : function(){
12229 return !this.list || !this.list.isVisible();
12233 initQuery : function(){
12235 var v = this.getRawValue();
12237 if(this.tickable && this.editable){
12238 v = this.tickableInputEl().getValue();
12245 doForce : function(){
12246 if(this.inputEl().dom.value.length > 0){
12247 this.inputEl().dom.value =
12248 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12254 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12255 * query allowing the query action to be canceled if needed.
12256 * @param {String} query The SQL query to execute
12257 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12258 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12259 * saved in the current store (defaults to false)
12261 doQuery : function(q, forceAll){
12263 if(q === undefined || q === null){
12268 forceAll: forceAll,
12272 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12277 forceAll = qe.forceAll;
12278 if(forceAll === true || (q.length >= this.minChars)){
12280 this.hasQuery = true;
12282 if(this.lastQuery != q || this.alwaysQuery){
12283 this.lastQuery = q;
12284 if(this.mode == 'local'){
12285 this.selectedIndex = -1;
12287 this.store.clearFilter();
12290 if(this.specialFilter){
12291 this.fireEvent('specialfilter', this);
12296 this.store.filter(this.displayField, q);
12299 this.store.fireEvent("datachanged", this.store);
12306 this.store.baseParams[this.queryParam] = q;
12308 var options = {params : this.getParams(q)};
12311 options.add = true;
12312 options.params.start = this.page * this.pageSize;
12315 this.store.load(options);
12318 * this code will make the page width larger, at the beginning, the list not align correctly,
12319 * we should expand the list on onLoad
12320 * so command out it
12325 this.selectedIndex = -1;
12330 this.loadNext = false;
12334 getParams : function(q){
12336 //p[this.queryParam] = q;
12340 p.limit = this.pageSize;
12346 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12348 collapse : function(){
12349 if(!this.isExpanded()){
12356 this.hasFocus = false;
12358 this.cancelBtn.hide();
12359 this.trigger.show();
12362 this.tickableInputEl().dom.value = '';
12363 this.tickableInputEl().blur();
12368 Roo.get(document).un('mousedown', this.collapseIf, this);
12369 Roo.get(document).un('mousewheel', this.collapseIf, this);
12370 if (!this.editable) {
12371 Roo.get(document).un('keydown', this.listKeyPress, this);
12373 this.fireEvent('collapse', this);
12377 collapseIf : function(e){
12378 var in_combo = e.within(this.el);
12379 var in_list = e.within(this.list);
12380 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12382 if (in_combo || in_list || is_list) {
12383 //e.stopPropagation();
12388 this.onTickableFooterButtonClick(e, false, false);
12396 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12398 expand : function(){
12400 if(this.isExpanded() || !this.hasFocus){
12404 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12405 this.list.setWidth(lw);
12412 this.restrictHeight();
12416 this.tickItems = Roo.apply([], this.item);
12419 this.cancelBtn.show();
12420 this.trigger.hide();
12423 this.tickableInputEl().focus();
12428 Roo.get(document).on('mousedown', this.collapseIf, this);
12429 Roo.get(document).on('mousewheel', this.collapseIf, this);
12430 if (!this.editable) {
12431 Roo.get(document).on('keydown', this.listKeyPress, this);
12434 this.fireEvent('expand', this);
12438 // Implements the default empty TriggerField.onTriggerClick function
12439 onTriggerClick : function(e)
12441 Roo.log('trigger click');
12443 if(this.disabled || !this.triggerList){
12448 this.loadNext = false;
12450 if(this.isExpanded()){
12452 if (!this.blockFocus) {
12453 this.inputEl().focus();
12457 this.hasFocus = true;
12458 if(this.triggerAction == 'all') {
12459 this.doQuery(this.allQuery, true);
12461 this.doQuery(this.getRawValue());
12463 if (!this.blockFocus) {
12464 this.inputEl().focus();
12469 onTickableTriggerClick : function(e)
12476 this.loadNext = false;
12477 this.hasFocus = true;
12479 if(this.triggerAction == 'all') {
12480 this.doQuery(this.allQuery, true);
12482 this.doQuery(this.getRawValue());
12486 onSearchFieldClick : function(e)
12488 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12489 this.onTickableFooterButtonClick(e, false, false);
12493 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12498 this.loadNext = false;
12499 this.hasFocus = true;
12501 if(this.triggerAction == 'all') {
12502 this.doQuery(this.allQuery, true);
12504 this.doQuery(this.getRawValue());
12508 listKeyPress : function(e)
12510 //Roo.log('listkeypress');
12511 // scroll to first matching element based on key pres..
12512 if (e.isSpecialKey()) {
12515 var k = String.fromCharCode(e.getKey()).toUpperCase();
12518 var csel = this.view.getSelectedNodes();
12519 var cselitem = false;
12521 var ix = this.view.indexOf(csel[0]);
12522 cselitem = this.store.getAt(ix);
12523 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12529 this.store.each(function(v) {
12531 // start at existing selection.
12532 if (cselitem.id == v.id) {
12538 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12539 match = this.store.indexOf(v);
12545 if (match === false) {
12546 return true; // no more action?
12549 this.view.select(match);
12550 var sn = Roo.get(this.view.getSelectedNodes()[0])
12551 sn.scrollIntoView(sn.dom.parentNode, false);
12554 onViewScroll : function(e, t){
12556 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){
12560 this.hasQuery = true;
12562 this.loading = this.list.select('.loading', true).first();
12564 if(this.loading === null){
12565 this.list.createChild({
12567 cls: 'loading select2-more-results select2-active',
12568 html: 'Loading more results...'
12571 this.loading = this.list.select('.loading', true).first();
12573 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12575 this.loading.hide();
12578 this.loading.show();
12583 this.loadNext = true;
12585 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12590 addItem : function(o)
12592 var dv = ''; // display value
12594 if (this.displayField) {
12595 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12597 // this is an error condition!!!
12598 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12605 var choice = this.choices.createChild({
12607 cls: 'select2-search-choice',
12616 cls: 'select2-search-choice-close',
12621 }, this.searchField);
12623 var close = choice.select('a.select2-search-choice-close', true).first()
12625 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12633 this.inputEl().dom.value = '';
12638 onRemoveItem : function(e, _self, o)
12640 e.preventDefault();
12642 this.lastItem = Roo.apply([], this.item);
12644 var index = this.item.indexOf(o.data) * 1;
12647 Roo.log('not this item?!');
12651 this.item.splice(index, 1);
12656 this.fireEvent('remove', this, e);
12662 syncValue : function()
12664 if(!this.item.length){
12671 Roo.each(this.item, function(i){
12672 if(_this.valueField){
12673 value.push(i[_this.valueField]);
12680 this.value = value.join(',');
12682 if(this.hiddenField){
12683 this.hiddenField.dom.value = this.value;
12686 this.store.fireEvent("datachanged", this.store);
12689 clearItem : function()
12691 if(!this.multiple){
12697 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12706 inputEl: function ()
12709 return this.searchField;
12711 return this.el.select('input.form-control',true).first();
12715 onTickableFooterButtonClick : function(e, btn, el)
12717 e.preventDefault();
12719 this.lastItem = Roo.apply([], this.item);
12721 if(btn && btn.name == 'cancel'){
12722 this.tickItems = Roo.apply([], this.item);
12731 Roo.each(this.tickItems, function(o){
12739 validate : function()
12741 var v = this.getRawValue();
12744 v = this.getValue();
12747 if(this.disabled || this.allowBlank || v.length){
12752 this.markInvalid();
12756 tickableInputEl : function()
12758 if(!this.tickable || !this.editable){
12759 return this.inputEl();
12762 return this.inputEl().select('.select2-search-field-input', true).first();
12768 * @cfg {Boolean} grow
12772 * @cfg {Number} growMin
12776 * @cfg {Number} growMax
12786 * Ext JS Library 1.1.1
12787 * Copyright(c) 2006-2007, Ext JS, LLC.
12789 * Originally Released Under LGPL - original licence link has changed is not relivant.
12792 * <script type="text/javascript">
12797 * @extends Roo.util.Observable
12798 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12799 * This class also supports single and multi selection modes. <br>
12800 * Create a data model bound view:
12802 var store = new Roo.data.Store(...);
12804 var view = new Roo.View({
12806 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12808 singleSelect: true,
12809 selectedClass: "ydataview-selected",
12813 // listen for node click?
12814 view.on("click", function(vw, index, node, e){
12815 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12819 dataModel.load("foobar.xml");
12821 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12823 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12824 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12826 * Note: old style constructor is still suported (container, template, config)
12829 * Create a new View
12830 * @param {Object} config The config object
12833 Roo.View = function(config, depreciated_tpl, depreciated_config){
12835 this.parent = false;
12837 if (typeof(depreciated_tpl) == 'undefined') {
12838 // new way.. - universal constructor.
12839 Roo.apply(this, config);
12840 this.el = Roo.get(this.el);
12843 this.el = Roo.get(config);
12844 this.tpl = depreciated_tpl;
12845 Roo.apply(this, depreciated_config);
12847 this.wrapEl = this.el.wrap().wrap();
12848 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12851 if(typeof(this.tpl) == "string"){
12852 this.tpl = new Roo.Template(this.tpl);
12854 // support xtype ctors..
12855 this.tpl = new Roo.factory(this.tpl, Roo);
12859 this.tpl.compile();
12864 * @event beforeclick
12865 * Fires before a click is processed. Returns false to cancel the default action.
12866 * @param {Roo.View} this
12867 * @param {Number} index The index of the target node
12868 * @param {HTMLElement} node The target node
12869 * @param {Roo.EventObject} e The raw event object
12871 "beforeclick" : true,
12874 * Fires when a template node is clicked.
12875 * @param {Roo.View} this
12876 * @param {Number} index The index of the target node
12877 * @param {HTMLElement} node The target node
12878 * @param {Roo.EventObject} e The raw event object
12883 * Fires when a template node is double clicked.
12884 * @param {Roo.View} this
12885 * @param {Number} index The index of the target node
12886 * @param {HTMLElement} node The target node
12887 * @param {Roo.EventObject} e The raw event object
12891 * @event contextmenu
12892 * Fires when a template node is right clicked.
12893 * @param {Roo.View} this
12894 * @param {Number} index The index of the target node
12895 * @param {HTMLElement} node The target node
12896 * @param {Roo.EventObject} e The raw event object
12898 "contextmenu" : true,
12900 * @event selectionchange
12901 * Fires when the selected nodes change.
12902 * @param {Roo.View} this
12903 * @param {Array} selections Array of the selected nodes
12905 "selectionchange" : true,
12908 * @event beforeselect
12909 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12910 * @param {Roo.View} this
12911 * @param {HTMLElement} node The node to be selected
12912 * @param {Array} selections Array of currently selected nodes
12914 "beforeselect" : true,
12916 * @event preparedata
12917 * Fires on every row to render, to allow you to change the data.
12918 * @param {Roo.View} this
12919 * @param {Object} data to be rendered (change this)
12921 "preparedata" : true
12929 "click": this.onClick,
12930 "dblclick": this.onDblClick,
12931 "contextmenu": this.onContextMenu,
12935 this.selections = [];
12937 this.cmp = new Roo.CompositeElementLite([]);
12939 this.store = Roo.factory(this.store, Roo.data);
12940 this.setStore(this.store, true);
12943 if ( this.footer && this.footer.xtype) {
12945 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12947 this.footer.dataSource = this.store
12948 this.footer.container = fctr;
12949 this.footer = Roo.factory(this.footer, Roo);
12950 fctr.insertFirst(this.el);
12952 // this is a bit insane - as the paging toolbar seems to detach the el..
12953 // dom.parentNode.parentNode.parentNode
12954 // they get detached?
12958 Roo.View.superclass.constructor.call(this);
12963 Roo.extend(Roo.View, Roo.util.Observable, {
12966 * @cfg {Roo.data.Store} store Data store to load data from.
12971 * @cfg {String|Roo.Element} el The container element.
12976 * @cfg {String|Roo.Template} tpl The template used by this View
12980 * @cfg {String} dataName the named area of the template to use as the data area
12981 * Works with domtemplates roo-name="name"
12985 * @cfg {String} selectedClass The css class to add to selected nodes
12987 selectedClass : "x-view-selected",
12989 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12994 * @cfg {String} text to display on mask (default Loading)
12998 * @cfg {Boolean} multiSelect Allow multiple selection
13000 multiSelect : false,
13002 * @cfg {Boolean} singleSelect Allow single selection
13004 singleSelect: false,
13007 * @cfg {Boolean} toggleSelect - selecting
13009 toggleSelect : false,
13012 * @cfg {Boolean} tickable - selecting
13017 * Returns the element this view is bound to.
13018 * @return {Roo.Element}
13020 getEl : function(){
13021 return this.wrapEl;
13027 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13029 refresh : function(){
13030 //Roo.log('refresh');
13033 // if we are using something like 'domtemplate', then
13034 // the what gets used is:
13035 // t.applySubtemplate(NAME, data, wrapping data..)
13036 // the outer template then get' applied with
13037 // the store 'extra data'
13038 // and the body get's added to the
13039 // roo-name="data" node?
13040 // <span class='roo-tpl-{name}'></span> ?????
13044 this.clearSelections();
13045 this.el.update("");
13047 var records = this.store.getRange();
13048 if(records.length < 1) {
13050 // is this valid?? = should it render a template??
13052 this.el.update(this.emptyText);
13056 if (this.dataName) {
13057 this.el.update(t.apply(this.store.meta)); //????
13058 el = this.el.child('.roo-tpl-' + this.dataName);
13061 for(var i = 0, len = records.length; i < len; i++){
13062 var data = this.prepareData(records[i].data, i, records[i]);
13063 this.fireEvent("preparedata", this, data, i, records[i]);
13065 var d = Roo.apply({}, data);
13068 Roo.apply(d, {'roo-id' : Roo.id()});
13072 Roo.each(this.parent.item, function(item){
13073 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13076 Roo.apply(d, {'roo-data-checked' : 'checked'});
13080 html[html.length] = Roo.util.Format.trim(
13082 t.applySubtemplate(this.dataName, d, this.store.meta) :
13089 el.update(html.join(""));
13090 this.nodes = el.dom.childNodes;
13091 this.updateIndexes(0);
13096 * Function to override to reformat the data that is sent to
13097 * the template for each node.
13098 * DEPRICATED - use the preparedata event handler.
13099 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13100 * a JSON object for an UpdateManager bound view).
13102 prepareData : function(data, index, record)
13104 this.fireEvent("preparedata", this, data, index, record);
13108 onUpdate : function(ds, record){
13109 // Roo.log('on update');
13110 this.clearSelections();
13111 var index = this.store.indexOf(record);
13112 var n = this.nodes[index];
13113 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13114 n.parentNode.removeChild(n);
13115 this.updateIndexes(index, index);
13121 onAdd : function(ds, records, index)
13123 //Roo.log(['on Add', ds, records, index] );
13124 this.clearSelections();
13125 if(this.nodes.length == 0){
13129 var n = this.nodes[index];
13130 for(var i = 0, len = records.length; i < len; i++){
13131 var d = this.prepareData(records[i].data, i, records[i]);
13133 this.tpl.insertBefore(n, d);
13136 this.tpl.append(this.el, d);
13139 this.updateIndexes(index);
13142 onRemove : function(ds, record, index){
13143 // Roo.log('onRemove');
13144 this.clearSelections();
13145 var el = this.dataName ?
13146 this.el.child('.roo-tpl-' + this.dataName) :
13149 el.dom.removeChild(this.nodes[index]);
13150 this.updateIndexes(index);
13154 * Refresh an individual node.
13155 * @param {Number} index
13157 refreshNode : function(index){
13158 this.onUpdate(this.store, this.store.getAt(index));
13161 updateIndexes : function(startIndex, endIndex){
13162 var ns = this.nodes;
13163 startIndex = startIndex || 0;
13164 endIndex = endIndex || ns.length - 1;
13165 for(var i = startIndex; i <= endIndex; i++){
13166 ns[i].nodeIndex = i;
13171 * Changes the data store this view uses and refresh the view.
13172 * @param {Store} store
13174 setStore : function(store, initial){
13175 if(!initial && this.store){
13176 this.store.un("datachanged", this.refresh);
13177 this.store.un("add", this.onAdd);
13178 this.store.un("remove", this.onRemove);
13179 this.store.un("update", this.onUpdate);
13180 this.store.un("clear", this.refresh);
13181 this.store.un("beforeload", this.onBeforeLoad);
13182 this.store.un("load", this.onLoad);
13183 this.store.un("loadexception", this.onLoad);
13187 store.on("datachanged", this.refresh, this);
13188 store.on("add", this.onAdd, this);
13189 store.on("remove", this.onRemove, this);
13190 store.on("update", this.onUpdate, this);
13191 store.on("clear", this.refresh, this);
13192 store.on("beforeload", this.onBeforeLoad, this);
13193 store.on("load", this.onLoad, this);
13194 store.on("loadexception", this.onLoad, this);
13202 * onbeforeLoad - masks the loading area.
13205 onBeforeLoad : function(store,opts)
13207 //Roo.log('onBeforeLoad');
13209 this.el.update("");
13211 this.el.mask(this.mask ? this.mask : "Loading" );
13213 onLoad : function ()
13220 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13221 * @param {HTMLElement} node
13222 * @return {HTMLElement} The template node
13224 findItemFromChild : function(node){
13225 var el = this.dataName ?
13226 this.el.child('.roo-tpl-' + this.dataName,true) :
13229 if(!node || node.parentNode == el){
13232 var p = node.parentNode;
13233 while(p && p != el){
13234 if(p.parentNode == el){
13243 onClick : function(e){
13244 var item = this.findItemFromChild(e.getTarget());
13246 var index = this.indexOf(item);
13247 if(this.onItemClick(item, index, e) !== false){
13248 this.fireEvent("click", this, index, item, e);
13251 this.clearSelections();
13256 onContextMenu : function(e){
13257 var item = this.findItemFromChild(e.getTarget());
13259 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13264 onDblClick : function(e){
13265 var item = this.findItemFromChild(e.getTarget());
13267 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13271 onItemClick : function(item, index, e)
13273 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13276 if (this.toggleSelect) {
13277 var m = this.isSelected(item) ? 'unselect' : 'select';
13280 _t[m](item, true, false);
13283 if(this.multiSelect || this.singleSelect){
13284 if(this.multiSelect && e.shiftKey && this.lastSelection){
13285 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13287 this.select(item, this.multiSelect && e.ctrlKey);
13288 this.lastSelection = item;
13291 if(!this.tickable){
13292 e.preventDefault();
13300 * Get the number of selected nodes.
13303 getSelectionCount : function(){
13304 return this.selections.length;
13308 * Get the currently selected nodes.
13309 * @return {Array} An array of HTMLElements
13311 getSelectedNodes : function(){
13312 return this.selections;
13316 * Get the indexes of the selected nodes.
13319 getSelectedIndexes : function(){
13320 var indexes = [], s = this.selections;
13321 for(var i = 0, len = s.length; i < len; i++){
13322 indexes.push(s[i].nodeIndex);
13328 * Clear all selections
13329 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13331 clearSelections : function(suppressEvent){
13332 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13333 this.cmp.elements = this.selections;
13334 this.cmp.removeClass(this.selectedClass);
13335 this.selections = [];
13336 if(!suppressEvent){
13337 this.fireEvent("selectionchange", this, this.selections);
13343 * Returns true if the passed node is selected
13344 * @param {HTMLElement/Number} node The node or node index
13345 * @return {Boolean}
13347 isSelected : function(node){
13348 var s = this.selections;
13352 node = this.getNode(node);
13353 return s.indexOf(node) !== -1;
13358 * @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
13359 * @param {Boolean} keepExisting (optional) true to keep existing selections
13360 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13362 select : function(nodeInfo, keepExisting, suppressEvent){
13363 if(nodeInfo instanceof Array){
13365 this.clearSelections(true);
13367 for(var i = 0, len = nodeInfo.length; i < len; i++){
13368 this.select(nodeInfo[i], true, true);
13372 var node = this.getNode(nodeInfo);
13373 if(!node || this.isSelected(node)){
13374 return; // already selected.
13377 this.clearSelections(true);
13380 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13381 Roo.fly(node).addClass(this.selectedClass);
13382 this.selections.push(node);
13383 if(!suppressEvent){
13384 this.fireEvent("selectionchange", this, this.selections);
13392 * @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
13393 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13394 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13396 unselect : function(nodeInfo, keepExisting, suppressEvent)
13398 if(nodeInfo instanceof Array){
13399 Roo.each(this.selections, function(s) {
13400 this.unselect(s, nodeInfo);
13404 var node = this.getNode(nodeInfo);
13405 if(!node || !this.isSelected(node)){
13406 //Roo.log("not selected");
13407 return; // not selected.
13411 Roo.each(this.selections, function(s) {
13413 Roo.fly(node).removeClass(this.selectedClass);
13420 this.selections= ns;
13421 this.fireEvent("selectionchange", this, this.selections);
13425 * Gets a template node.
13426 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13427 * @return {HTMLElement} The node or null if it wasn't found
13429 getNode : function(nodeInfo){
13430 if(typeof nodeInfo == "string"){
13431 return document.getElementById(nodeInfo);
13432 }else if(typeof nodeInfo == "number"){
13433 return this.nodes[nodeInfo];
13439 * Gets a range template nodes.
13440 * @param {Number} startIndex
13441 * @param {Number} endIndex
13442 * @return {Array} An array of nodes
13444 getNodes : function(start, end){
13445 var ns = this.nodes;
13446 start = start || 0;
13447 end = typeof end == "undefined" ? ns.length - 1 : end;
13450 for(var i = start; i <= end; i++){
13454 for(var i = start; i >= end; i--){
13462 * Finds the index of the passed node
13463 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13464 * @return {Number} The index of the node or -1
13466 indexOf : function(node){
13467 node = this.getNode(node);
13468 if(typeof node.nodeIndex == "number"){
13469 return node.nodeIndex;
13471 var ns = this.nodes;
13472 for(var i = 0, len = ns.length; i < len; i++){
13483 * based on jquery fullcalendar
13487 Roo.bootstrap = Roo.bootstrap || {};
13489 * @class Roo.bootstrap.Calendar
13490 * @extends Roo.bootstrap.Component
13491 * Bootstrap Calendar class
13492 * @cfg {Boolean} loadMask (true|false) default false
13493 * @cfg {Object} header generate the user specific header of the calendar, default false
13496 * Create a new Container
13497 * @param {Object} config The config object
13502 Roo.bootstrap.Calendar = function(config){
13503 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13507 * Fires when a date is selected
13508 * @param {DatePicker} this
13509 * @param {Date} date The selected date
13513 * @event monthchange
13514 * Fires when the displayed month changes
13515 * @param {DatePicker} this
13516 * @param {Date} date The selected month
13518 'monthchange': true,
13520 * @event evententer
13521 * Fires when mouse over an event
13522 * @param {Calendar} this
13523 * @param {event} Event
13525 'evententer': true,
13527 * @event eventleave
13528 * Fires when the mouse leaves an
13529 * @param {Calendar} this
13532 'eventleave': true,
13534 * @event eventclick
13535 * Fires when the mouse click an
13536 * @param {Calendar} this
13545 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13548 * @cfg {Number} startDay
13549 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13557 getAutoCreate : function(){
13560 var fc_button = function(name, corner, style, content ) {
13561 return Roo.apply({},{
13563 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13565 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13568 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13579 style : 'width:100%',
13586 cls : 'fc-header-left',
13588 fc_button('prev', 'left', 'arrow', '‹' ),
13589 fc_button('next', 'right', 'arrow', '›' ),
13590 { tag: 'span', cls: 'fc-header-space' },
13591 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13599 cls : 'fc-header-center',
13603 cls: 'fc-header-title',
13606 html : 'month / year'
13614 cls : 'fc-header-right',
13616 /* fc_button('month', 'left', '', 'month' ),
13617 fc_button('week', '', '', 'week' ),
13618 fc_button('day', 'right', '', 'day' )
13630 header = this.header;
13633 var cal_heads = function() {
13635 // fixme - handle this.
13637 for (var i =0; i < Date.dayNames.length; i++) {
13638 var d = Date.dayNames[i];
13641 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13642 html : d.substring(0,3)
13646 ret[0].cls += ' fc-first';
13647 ret[6].cls += ' fc-last';
13650 var cal_cell = function(n) {
13653 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13658 cls: 'fc-day-number',
13662 cls: 'fc-day-content',
13666 style: 'position: relative;' // height: 17px;
13678 var cal_rows = function() {
13681 for (var r = 0; r < 6; r++) {
13688 for (var i =0; i < Date.dayNames.length; i++) {
13689 var d = Date.dayNames[i];
13690 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13693 row.cn[0].cls+=' fc-first';
13694 row.cn[0].cn[0].style = 'min-height:90px';
13695 row.cn[6].cls+=' fc-last';
13699 ret[0].cls += ' fc-first';
13700 ret[4].cls += ' fc-prev-last';
13701 ret[5].cls += ' fc-last';
13708 cls: 'fc-border-separate',
13709 style : 'width:100%',
13717 cls : 'fc-first fc-last',
13735 cls : 'fc-content',
13736 style : "position: relative;",
13739 cls : 'fc-view fc-view-month fc-grid',
13740 style : 'position: relative',
13741 unselectable : 'on',
13744 cls : 'fc-event-container',
13745 style : 'position:absolute;z-index:8;top:0;left:0;'
13763 initEvents : function()
13766 throw "can not find store for calendar";
13772 style: "text-align:center",
13776 style: "background-color:white;width:50%;margin:250 auto",
13780 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13791 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13793 var size = this.el.select('.fc-content', true).first().getSize();
13794 this.maskEl.setSize(size.width, size.height);
13795 this.maskEl.enableDisplayMode("block");
13796 if(!this.loadMask){
13797 this.maskEl.hide();
13800 this.store = Roo.factory(this.store, Roo.data);
13801 this.store.on('load', this.onLoad, this);
13802 this.store.on('beforeload', this.onBeforeLoad, this);
13806 this.cells = this.el.select('.fc-day',true);
13807 //Roo.log(this.cells);
13808 this.textNodes = this.el.query('.fc-day-number');
13809 this.cells.addClassOnOver('fc-state-hover');
13811 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13812 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13813 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13814 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13816 this.on('monthchange', this.onMonthChange, this);
13818 this.update(new Date().clearTime());
13821 resize : function() {
13822 var sz = this.el.getSize();
13824 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13825 this.el.select('.fc-day-content div',true).setHeight(34);
13830 showPrevMonth : function(e){
13831 this.update(this.activeDate.add("mo", -1));
13833 showToday : function(e){
13834 this.update(new Date().clearTime());
13837 showNextMonth : function(e){
13838 this.update(this.activeDate.add("mo", 1));
13842 showPrevYear : function(){
13843 this.update(this.activeDate.add("y", -1));
13847 showNextYear : function(){
13848 this.update(this.activeDate.add("y", 1));
13853 update : function(date)
13855 var vd = this.activeDate;
13856 this.activeDate = date;
13857 // if(vd && this.el){
13858 // var t = date.getTime();
13859 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13860 // Roo.log('using add remove');
13862 // this.fireEvent('monthchange', this, date);
13864 // this.cells.removeClass("fc-state-highlight");
13865 // this.cells.each(function(c){
13866 // if(c.dateValue == t){
13867 // c.addClass("fc-state-highlight");
13868 // setTimeout(function(){
13869 // try{c.dom.firstChild.focus();}catch(e){}
13879 var days = date.getDaysInMonth();
13881 var firstOfMonth = date.getFirstDateOfMonth();
13882 var startingPos = firstOfMonth.getDay()-this.startDay;
13884 if(startingPos < this.startDay){
13888 var pm = date.add(Date.MONTH, -1);
13889 var prevStart = pm.getDaysInMonth()-startingPos;
13891 this.cells = this.el.select('.fc-day',true);
13892 this.textNodes = this.el.query('.fc-day-number');
13893 this.cells.addClassOnOver('fc-state-hover');
13895 var cells = this.cells.elements;
13896 var textEls = this.textNodes;
13898 Roo.each(cells, function(cell){
13899 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13902 days += startingPos;
13904 // convert everything to numbers so it's fast
13905 var day = 86400000;
13906 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13909 //Roo.log(prevStart);
13911 var today = new Date().clearTime().getTime();
13912 var sel = date.clearTime().getTime();
13913 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13914 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13915 var ddMatch = this.disabledDatesRE;
13916 var ddText = this.disabledDatesText;
13917 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13918 var ddaysText = this.disabledDaysText;
13919 var format = this.format;
13921 var setCellClass = function(cal, cell){
13925 //Roo.log('set Cell Class');
13927 var t = d.getTime();
13931 cell.dateValue = t;
13933 cell.className += " fc-today";
13934 cell.className += " fc-state-highlight";
13935 cell.title = cal.todayText;
13938 // disable highlight in other month..
13939 //cell.className += " fc-state-highlight";
13944 cell.className = " fc-state-disabled";
13945 cell.title = cal.minText;
13949 cell.className = " fc-state-disabled";
13950 cell.title = cal.maxText;
13954 if(ddays.indexOf(d.getDay()) != -1){
13955 cell.title = ddaysText;
13956 cell.className = " fc-state-disabled";
13959 if(ddMatch && format){
13960 var fvalue = d.dateFormat(format);
13961 if(ddMatch.test(fvalue)){
13962 cell.title = ddText.replace("%0", fvalue);
13963 cell.className = " fc-state-disabled";
13967 if (!cell.initialClassName) {
13968 cell.initialClassName = cell.dom.className;
13971 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13976 for(; i < startingPos; i++) {
13977 textEls[i].innerHTML = (++prevStart);
13978 d.setDate(d.getDate()+1);
13980 cells[i].className = "fc-past fc-other-month";
13981 setCellClass(this, cells[i]);
13986 for(; i < days; i++){
13987 intDay = i - startingPos + 1;
13988 textEls[i].innerHTML = (intDay);
13989 d.setDate(d.getDate()+1);
13991 cells[i].className = ''; // "x-date-active";
13992 setCellClass(this, cells[i]);
13996 for(; i < 42; i++) {
13997 textEls[i].innerHTML = (++extraDays);
13998 d.setDate(d.getDate()+1);
14000 cells[i].className = "fc-future fc-other-month";
14001 setCellClass(this, cells[i]);
14004 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14006 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14008 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14009 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14011 if(totalRows != 6){
14012 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14013 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14016 this.fireEvent('monthchange', this, date);
14020 if(!this.internalRender){
14021 var main = this.el.dom.firstChild;
14022 var w = main.offsetWidth;
14023 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14024 Roo.fly(main).setWidth(w);
14025 this.internalRender = true;
14026 // opera does not respect the auto grow header center column
14027 // then, after it gets a width opera refuses to recalculate
14028 // without a second pass
14029 if(Roo.isOpera && !this.secondPass){
14030 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14031 this.secondPass = true;
14032 this.update.defer(10, this, [date]);
14039 findCell : function(dt) {
14040 dt = dt.clearTime().getTime();
14042 this.cells.each(function(c){
14043 //Roo.log("check " +c.dateValue + '?=' + dt);
14044 if(c.dateValue == dt){
14054 findCells : function(ev) {
14055 var s = ev.start.clone().clearTime().getTime();
14057 var e= ev.end.clone().clearTime().getTime();
14060 this.cells.each(function(c){
14061 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14063 if(c.dateValue > e){
14066 if(c.dateValue < s){
14075 // findBestRow: function(cells)
14079 // for (var i =0 ; i < cells.length;i++) {
14080 // ret = Math.max(cells[i].rows || 0,ret);
14087 addItem : function(ev)
14089 // look for vertical location slot in
14090 var cells = this.findCells(ev);
14092 // ev.row = this.findBestRow(cells);
14094 // work out the location.
14098 for(var i =0; i < cells.length; i++) {
14100 cells[i].row = cells[0].row;
14103 cells[i].row = cells[i].row + 1;
14113 if (crow.start.getY() == cells[i].getY()) {
14115 crow.end = cells[i];
14132 cells[0].events.push(ev);
14134 this.calevents.push(ev);
14137 clearEvents: function() {
14139 if(!this.calevents){
14143 Roo.each(this.cells.elements, function(c){
14149 Roo.each(this.calevents, function(e) {
14150 Roo.each(e.els, function(el) {
14151 el.un('mouseenter' ,this.onEventEnter, this);
14152 el.un('mouseleave' ,this.onEventLeave, this);
14157 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14163 renderEvents: function()
14167 this.cells.each(function(c) {
14176 if(c.row != c.events.length){
14177 r = 4 - (4 - (c.row - c.events.length));
14180 c.events = ev.slice(0, r);
14181 c.more = ev.slice(r);
14183 if(c.more.length && c.more.length == 1){
14184 c.events.push(c.more.pop());
14187 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14191 this.cells.each(function(c) {
14193 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14196 for (var e = 0; e < c.events.length; e++){
14197 var ev = c.events[e];
14198 var rows = ev.rows;
14200 for(var i = 0; i < rows.length; i++) {
14202 // how many rows should it span..
14205 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14206 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14208 unselectable : "on",
14211 cls: 'fc-event-inner',
14215 // cls: 'fc-event-time',
14216 // html : cells.length > 1 ? '' : ev.time
14220 cls: 'fc-event-title',
14221 html : String.format('{0}', ev.title)
14228 cls: 'ui-resizable-handle ui-resizable-e',
14229 html : '  '
14236 cfg.cls += ' fc-event-start';
14238 if ((i+1) == rows.length) {
14239 cfg.cls += ' fc-event-end';
14242 var ctr = _this.el.select('.fc-event-container',true).first();
14243 var cg = ctr.createChild(cfg);
14245 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14246 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14248 var r = (c.more.length) ? 1 : 0;
14249 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14250 cg.setWidth(ebox.right - sbox.x -2);
14252 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14253 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14254 cg.on('click', _this.onEventClick, _this, ev);
14265 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14266 style : 'position: absolute',
14267 unselectable : "on",
14270 cls: 'fc-event-inner',
14274 cls: 'fc-event-title',
14282 cls: 'ui-resizable-handle ui-resizable-e',
14283 html : '  '
14289 var ctr = _this.el.select('.fc-event-container',true).first();
14290 var cg = ctr.createChild(cfg);
14292 var sbox = c.select('.fc-day-content',true).first().getBox();
14293 var ebox = c.select('.fc-day-content',true).first().getBox();
14295 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14296 cg.setWidth(ebox.right - sbox.x -2);
14298 cg.on('click', _this.onMoreEventClick, _this, c.more);
14308 onEventEnter: function (e, el,event,d) {
14309 this.fireEvent('evententer', this, el, event);
14312 onEventLeave: function (e, el,event,d) {
14313 this.fireEvent('eventleave', this, el, event);
14316 onEventClick: function (e, el,event,d) {
14317 this.fireEvent('eventclick', this, el, event);
14320 onMonthChange: function () {
14324 onMoreEventClick: function(e, el, more)
14328 this.calpopover.placement = 'right';
14329 this.calpopover.setTitle('More');
14331 this.calpopover.setContent('');
14333 var ctr = this.calpopover.el.select('.popover-content', true).first();
14335 Roo.each(more, function(m){
14337 cls : 'fc-event-hori fc-event-draggable',
14340 var cg = ctr.createChild(cfg);
14342 cg.on('click', _this.onEventClick, _this, m);
14345 this.calpopover.show(el);
14350 onLoad: function ()
14352 this.calevents = [];
14355 if(this.store.getCount() > 0){
14356 this.store.data.each(function(d){
14359 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14360 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14361 time : d.data.start_time,
14362 title : d.data.title,
14363 description : d.data.description,
14364 venue : d.data.venue
14369 this.renderEvents();
14371 if(this.calevents.length && this.loadMask){
14372 this.maskEl.hide();
14376 onBeforeLoad: function()
14378 this.clearEvents();
14380 this.maskEl.show();
14394 * @class Roo.bootstrap.Popover
14395 * @extends Roo.bootstrap.Component
14396 * Bootstrap Popover class
14397 * @cfg {String} html contents of the popover (or false to use children..)
14398 * @cfg {String} title of popover (or false to hide)
14399 * @cfg {String} placement how it is placed
14400 * @cfg {String} trigger click || hover (or false to trigger manually)
14401 * @cfg {String} over what (parent or false to trigger manually.)
14402 * @cfg {Number} delay - delay before showing
14405 * Create a new Popover
14406 * @param {Object} config The config object
14409 Roo.bootstrap.Popover = function(config){
14410 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14413 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14415 title: 'Fill in a title',
14418 placement : 'right',
14419 trigger : 'hover', // hover
14425 can_build_overlaid : false,
14427 getChildContainer : function()
14429 return this.el.select('.popover-content',true).first();
14432 getAutoCreate : function(){
14433 Roo.log('make popover?');
14435 cls : 'popover roo-dynamic',
14436 style: 'display:block',
14442 cls : 'popover-inner',
14446 cls: 'popover-title',
14450 cls : 'popover-content',
14461 setTitle: function(str)
14463 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14465 setContent: function(str)
14467 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14469 // as it get's added to the bottom of the page.
14470 onRender : function(ct, position)
14472 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14474 var cfg = Roo.apply({}, this.getAutoCreate());
14478 cfg.cls += ' ' + this.cls;
14481 cfg.style = this.style;
14483 Roo.log("adding to ")
14484 this.el = Roo.get(document.body).createChild(cfg, position);
14490 initEvents : function()
14492 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14493 this.el.enableDisplayMode('block');
14495 if (this.over === false) {
14498 if (this.triggers === false) {
14501 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14502 var triggers = this.trigger ? this.trigger.split(' ') : [];
14503 Roo.each(triggers, function(trigger) {
14505 if (trigger == 'click') {
14506 on_el.on('click', this.toggle, this);
14507 } else if (trigger != 'manual') {
14508 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14509 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14511 on_el.on(eventIn ,this.enter, this);
14512 on_el.on(eventOut, this.leave, this);
14523 toggle : function () {
14524 this.hoverState == 'in' ? this.leave() : this.enter();
14527 enter : function () {
14530 clearTimeout(this.timeout);
14532 this.hoverState = 'in';
14534 if (!this.delay || !this.delay.show) {
14539 this.timeout = setTimeout(function () {
14540 if (_t.hoverState == 'in') {
14543 }, this.delay.show)
14545 leave : function() {
14546 clearTimeout(this.timeout);
14548 this.hoverState = 'out';
14550 if (!this.delay || !this.delay.hide) {
14555 this.timeout = setTimeout(function () {
14556 if (_t.hoverState == 'out') {
14559 }, this.delay.hide)
14562 show : function (on_el)
14565 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14568 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14569 if (this.html !== false) {
14570 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14572 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14573 if (!this.title.length) {
14574 this.el.select('.popover-title',true).hide();
14577 var placement = typeof this.placement == 'function' ?
14578 this.placement.call(this, this.el, on_el) :
14581 var autoToken = /\s?auto?\s?/i;
14582 var autoPlace = autoToken.test(placement);
14584 placement = placement.replace(autoToken, '') || 'top';
14588 //this.el.setXY([0,0]);
14590 this.el.dom.style.display='block';
14591 this.el.addClass(placement);
14593 //this.el.appendTo(on_el);
14595 var p = this.getPosition();
14596 var box = this.el.getBox();
14601 var align = Roo.bootstrap.Popover.alignment[placement];
14602 this.el.alignTo(on_el, align[0],align[1]);
14603 //var arrow = this.el.select('.arrow',true).first();
14604 //arrow.set(align[2],
14606 this.el.addClass('in');
14607 this.hoverState = null;
14609 if (this.el.hasClass('fade')) {
14616 this.el.setXY([0,0]);
14617 this.el.removeClass('in');
14624 Roo.bootstrap.Popover.alignment = {
14625 'left' : ['r-l', [-10,0], 'right'],
14626 'right' : ['l-r', [10,0], 'left'],
14627 'bottom' : ['t-b', [0,10], 'top'],
14628 'top' : [ 'b-t', [0,-10], 'bottom']
14639 * @class Roo.bootstrap.Progress
14640 * @extends Roo.bootstrap.Component
14641 * Bootstrap Progress class
14642 * @cfg {Boolean} striped striped of the progress bar
14643 * @cfg {Boolean} active animated of the progress bar
14647 * Create a new Progress
14648 * @param {Object} config The config object
14651 Roo.bootstrap.Progress = function(config){
14652 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14655 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14660 getAutoCreate : function(){
14668 cfg.cls += ' progress-striped';
14672 cfg.cls += ' active';
14691 * @class Roo.bootstrap.ProgressBar
14692 * @extends Roo.bootstrap.Component
14693 * Bootstrap ProgressBar class
14694 * @cfg {Number} aria_valuenow aria-value now
14695 * @cfg {Number} aria_valuemin aria-value min
14696 * @cfg {Number} aria_valuemax aria-value max
14697 * @cfg {String} label label for the progress bar
14698 * @cfg {String} panel (success | info | warning | danger )
14699 * @cfg {String} role role of the progress bar
14700 * @cfg {String} sr_only text
14704 * Create a new ProgressBar
14705 * @param {Object} config The config object
14708 Roo.bootstrap.ProgressBar = function(config){
14709 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14712 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14716 aria_valuemax : 100,
14722 getAutoCreate : function()
14727 cls: 'progress-bar',
14728 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14740 cfg.role = this.role;
14743 if(this.aria_valuenow){
14744 cfg['aria-valuenow'] = this.aria_valuenow;
14747 if(this.aria_valuemin){
14748 cfg['aria-valuemin'] = this.aria_valuemin;
14751 if(this.aria_valuemax){
14752 cfg['aria-valuemax'] = this.aria_valuemax;
14755 if(this.label && !this.sr_only){
14756 cfg.html = this.label;
14760 cfg.cls += ' progress-bar-' + this.panel;
14766 update : function(aria_valuenow)
14768 this.aria_valuenow = aria_valuenow;
14770 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14785 * @class Roo.bootstrap.TabGroup
14786 * @extends Roo.bootstrap.Column
14787 * Bootstrap Column class
14788 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14789 * @cfg {Boolean} carousel true to make the group behave like a carousel
14790 * @cfg {Number} bullets show the panel pointer.. default 0
14791 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14792 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14793 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14796 * Create a new TabGroup
14797 * @param {Object} config The config object
14800 Roo.bootstrap.TabGroup = function(config){
14801 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14803 this.navId = Roo.id();
14806 Roo.bootstrap.TabGroup.register(this);
14810 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14813 transition : false,
14818 slideOnTouch : false,
14820 getAutoCreate : function()
14822 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14824 cfg.cls += ' tab-content';
14826 Roo.log('get auto create...............');
14828 if (this.carousel) {
14829 cfg.cls += ' carousel slide';
14832 cls : 'carousel-inner'
14835 if(this.bullets > 0 && !Roo.isTouch){
14838 cls : 'carousel-bullets',
14842 if(this.bullets_cls){
14843 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14846 for (var i = 0; i < this.bullets; i++){
14848 cls : 'bullet bullet-' + i
14856 cfg.cn[0].cn = bullets;
14863 initEvents: function()
14865 Roo.log('-------- init events on tab group ---------');
14867 if(this.bullets > 0 && !Roo.isTouch){
14873 if(Roo.isTouch && this.slideOnTouch){
14874 this.el.on("touchstart", this.onTouchStart, this);
14877 if(this.autoslide){
14880 this.slideFn = window.setInterval(function() {
14881 _this.showPanelNext();
14887 onTouchStart : function(e, el, o)
14889 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14893 this.showPanelNext();
14896 getChildContainer : function()
14898 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14902 * register a Navigation item
14903 * @param {Roo.bootstrap.NavItem} the navitem to add
14905 register : function(item)
14907 this.tabs.push( item);
14908 item.navId = this.navId; // not really needed..
14912 getActivePanel : function()
14915 Roo.each(this.tabs, function(t) {
14925 getPanelByName : function(n)
14928 Roo.each(this.tabs, function(t) {
14929 if (t.tabId == n) {
14937 indexOfPanel : function(p)
14940 Roo.each(this.tabs, function(t,i) {
14941 if (t.tabId == p.tabId) {
14950 * show a specific panel
14951 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14952 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14954 showPanel : function (pan)
14956 if(this.transition){
14957 Roo.log("waiting for the transitionend");
14961 if (typeof(pan) == 'number') {
14962 pan = this.tabs[pan];
14964 if (typeof(pan) == 'string') {
14965 pan = this.getPanelByName(pan);
14967 if (pan.tabId == this.getActivePanel().tabId) {
14970 var cur = this.getActivePanel();
14972 if (false === cur.fireEvent('beforedeactivate')) {
14976 if(this.bullets > 0 && !Roo.isTouch){
14977 this.setActiveBullet(this.indexOfPanel(pan));
14980 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14982 this.transition = true;
14983 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14984 var lr = dir == 'next' ? 'left' : 'right';
14985 pan.el.addClass(dir); // or prev
14986 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14987 cur.el.addClass(lr); // or right
14988 pan.el.addClass(lr);
14991 cur.el.on('transitionend', function() {
14992 Roo.log("trans end?");
14994 pan.el.removeClass([lr,dir]);
14995 pan.setActive(true);
14997 cur.el.removeClass([lr]);
14998 cur.setActive(false);
15000 _this.transition = false;
15002 }, this, { single: true } );
15007 cur.setActive(false);
15008 pan.setActive(true);
15013 showPanelNext : function()
15015 var i = this.indexOfPanel(this.getActivePanel());
15017 if (i >= this.tabs.length - 1 && !this.autoslide) {
15021 if (i >= this.tabs.length - 1 && this.autoslide) {
15025 this.showPanel(this.tabs[i+1]);
15028 showPanelPrev : function()
15030 var i = this.indexOfPanel(this.getActivePanel());
15032 if (i < 1 && !this.autoslide) {
15036 if (i < 1 && this.autoslide) {
15037 i = this.tabs.length;
15040 this.showPanel(this.tabs[i-1]);
15043 initBullet : function()
15051 for (var i = 0; i < this.bullets; i++){
15052 var bullet = this.el.select('.bullet-' + i, true).first();
15058 bullet.on('click', (function(e, el, o, ii, t){
15060 e.preventDefault();
15062 _this.showPanel(ii);
15064 if(_this.autoslide && _this.slideFn){
15065 clearInterval(_this.slideFn);
15066 _this.slideFn = window.setInterval(function() {
15067 _this.showPanelNext();
15071 }).createDelegate(this, [i, bullet], true));
15075 setActiveBullet : function(i)
15081 Roo.each(this.el.select('.bullet', true).elements, function(el){
15082 el.removeClass('selected');
15085 var bullet = this.el.select('.bullet-' + i, true).first();
15091 bullet.addClass('selected');
15102 Roo.apply(Roo.bootstrap.TabGroup, {
15106 * register a Navigation Group
15107 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15109 register : function(navgrp)
15111 this.groups[navgrp.navId] = navgrp;
15115 * fetch a Navigation Group based on the navigation ID
15116 * if one does not exist , it will get created.
15117 * @param {string} the navgroup to add
15118 * @returns {Roo.bootstrap.NavGroup} the navgroup
15120 get: function(navId) {
15121 if (typeof(this.groups[navId]) == 'undefined') {
15122 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15124 return this.groups[navId] ;
15139 * @class Roo.bootstrap.TabPanel
15140 * @extends Roo.bootstrap.Component
15141 * Bootstrap TabPanel class
15142 * @cfg {Boolean} active panel active
15143 * @cfg {String} html panel content
15144 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15145 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15149 * Create a new TabPanel
15150 * @param {Object} config The config object
15153 Roo.bootstrap.TabPanel = function(config){
15154 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15158 * Fires when the active status changes
15159 * @param {Roo.bootstrap.TabPanel} this
15160 * @param {Boolean} state the new state
15165 * @event beforedeactivate
15166 * Fires before a tab is de-activated - can be used to do validation on a form.
15167 * @param {Roo.bootstrap.TabPanel} this
15168 * @return {Boolean} false if there is an error
15171 'beforedeactivate': true
15174 this.tabId = this.tabId || Roo.id();
15178 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15185 getAutoCreate : function(){
15188 // item is needed for carousel - not sure if it has any effect otherwise
15189 cls: 'tab-pane item',
15190 html: this.html || ''
15194 cfg.cls += ' active';
15198 cfg.tabId = this.tabId;
15205 initEvents: function()
15207 Roo.log('-------- init events on tab panel ---------');
15209 var p = this.parent();
15210 this.navId = this.navId || p.navId;
15212 if (typeof(this.navId) != 'undefined') {
15213 // not really needed.. but just in case.. parent should be a NavGroup.
15214 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15215 Roo.log(['register', tg, this]);
15218 var i = tg.tabs.length - 1;
15220 if(this.active && tg.bullets > 0 && i < tg.bullets){
15221 tg.setActiveBullet(i);
15228 onRender : function(ct, position)
15230 // Roo.log("Call onRender: " + this.xtype);
15232 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15240 setActive: function(state)
15242 Roo.log("panel - set active " + this.tabId + "=" + state);
15244 this.active = state;
15246 this.el.removeClass('active');
15248 } else if (!this.el.hasClass('active')) {
15249 this.el.addClass('active');
15252 this.fireEvent('changed', this, state);
15269 * @class Roo.bootstrap.DateField
15270 * @extends Roo.bootstrap.Input
15271 * Bootstrap DateField class
15272 * @cfg {Number} weekStart default 0
15273 * @cfg {String} viewMode default empty, (months|years)
15274 * @cfg {String} minViewMode default empty, (months|years)
15275 * @cfg {Number} startDate default -Infinity
15276 * @cfg {Number} endDate default Infinity
15277 * @cfg {Boolean} todayHighlight default false
15278 * @cfg {Boolean} todayBtn default false
15279 * @cfg {Boolean} calendarWeeks default false
15280 * @cfg {Object} daysOfWeekDisabled default empty
15281 * @cfg {Boolean} singleMode default false (true | false)
15283 * @cfg {Boolean} keyboardNavigation default true
15284 * @cfg {String} language default en
15287 * Create a new DateField
15288 * @param {Object} config The config object
15291 Roo.bootstrap.DateField = function(config){
15292 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15296 * Fires when this field show.
15297 * @param {Roo.bootstrap.DateField} this
15298 * @param {Mixed} date The date value
15303 * Fires when this field hide.
15304 * @param {Roo.bootstrap.DateField} this
15305 * @param {Mixed} date The date value
15310 * Fires when select a date.
15311 * @param {Roo.bootstrap.DateField} this
15312 * @param {Mixed} date The date value
15318 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15321 * @cfg {String} format
15322 * The default date format string which can be overriden for localization support. The format must be
15323 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15327 * @cfg {String} altFormats
15328 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15329 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15331 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15339 todayHighlight : false,
15345 keyboardNavigation: true,
15347 calendarWeeks: false,
15349 startDate: -Infinity,
15353 daysOfWeekDisabled: [],
15357 singleMode : false,
15359 UTCDate: function()
15361 return new Date(Date.UTC.apply(Date, arguments));
15364 UTCToday: function()
15366 var today = new Date();
15367 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15370 getDate: function() {
15371 var d = this.getUTCDate();
15372 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15375 getUTCDate: function() {
15379 setDate: function(d) {
15380 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15383 setUTCDate: function(d) {
15385 this.setValue(this.formatDate(this.date));
15388 onRender: function(ct, position)
15391 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15393 this.language = this.language || 'en';
15394 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15395 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15397 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15398 this.format = this.format || 'm/d/y';
15399 this.isInline = false;
15400 this.isInput = true;
15401 this.component = this.el.select('.add-on', true).first() || false;
15402 this.component = (this.component && this.component.length === 0) ? false : this.component;
15403 this.hasInput = this.component && this.inputEL().length;
15405 if (typeof(this.minViewMode === 'string')) {
15406 switch (this.minViewMode) {
15408 this.minViewMode = 1;
15411 this.minViewMode = 2;
15414 this.minViewMode = 0;
15419 if (typeof(this.viewMode === 'string')) {
15420 switch (this.viewMode) {
15433 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15435 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15437 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15439 this.picker().on('mousedown', this.onMousedown, this);
15440 this.picker().on('click', this.onClick, this);
15442 this.picker().addClass('datepicker-dropdown');
15444 this.startViewMode = this.viewMode;
15446 if(this.singleMode){
15447 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15448 v.setVisibilityMode(Roo.Element.DISPLAY)
15452 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15453 v.setStyle('width', '189px');
15457 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15458 if(!this.calendarWeeks){
15463 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15464 v.attr('colspan', function(i, val){
15465 return parseInt(val) + 1;
15470 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15472 this.setStartDate(this.startDate);
15473 this.setEndDate(this.endDate);
15475 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15482 if(this.isInline) {
15487 picker : function()
15489 return this.pickerEl;
15490 // return this.el.select('.datepicker', true).first();
15493 fillDow: function()
15495 var dowCnt = this.weekStart;
15504 if(this.calendarWeeks){
15512 while (dowCnt < this.weekStart + 7) {
15516 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15520 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15523 fillMonths: function()
15526 var months = this.picker().select('>.datepicker-months td', true).first();
15528 months.dom.innerHTML = '';
15534 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15537 months.createChild(month);
15544 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;
15546 if (this.date < this.startDate) {
15547 this.viewDate = new Date(this.startDate);
15548 } else if (this.date > this.endDate) {
15549 this.viewDate = new Date(this.endDate);
15551 this.viewDate = new Date(this.date);
15559 var d = new Date(this.viewDate),
15560 year = d.getUTCFullYear(),
15561 month = d.getUTCMonth(),
15562 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15563 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15564 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15565 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15566 currentDate = this.date && this.date.valueOf(),
15567 today = this.UTCToday();
15569 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15571 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15573 // this.picker.select('>tfoot th.today').
15574 // .text(dates[this.language].today)
15575 // .toggle(this.todayBtn !== false);
15577 this.updateNavArrows();
15580 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15582 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15584 prevMonth.setUTCDate(day);
15586 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15588 var nextMonth = new Date(prevMonth);
15590 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15592 nextMonth = nextMonth.valueOf();
15594 var fillMonths = false;
15596 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15598 while(prevMonth.valueOf() < nextMonth) {
15601 if (prevMonth.getUTCDay() === this.weekStart) {
15603 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15611 if(this.calendarWeeks){
15612 // ISO 8601: First week contains first thursday.
15613 // ISO also states week starts on Monday, but we can be more abstract here.
15615 // Start of current week: based on weekstart/current date
15616 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15617 // Thursday of this week
15618 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15619 // First Thursday of year, year from thursday
15620 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15621 // Calendar week: ms between thursdays, div ms per day, div 7 days
15622 calWeek = (th - yth) / 864e5 / 7 + 1;
15624 fillMonths.cn.push({
15632 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15634 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15637 if (this.todayHighlight &&
15638 prevMonth.getUTCFullYear() == today.getFullYear() &&
15639 prevMonth.getUTCMonth() == today.getMonth() &&
15640 prevMonth.getUTCDate() == today.getDate()) {
15641 clsName += ' today';
15644 if (currentDate && prevMonth.valueOf() === currentDate) {
15645 clsName += ' active';
15648 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15649 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15650 clsName += ' disabled';
15653 fillMonths.cn.push({
15655 cls: 'day ' + clsName,
15656 html: prevMonth.getDate()
15659 prevMonth.setDate(prevMonth.getDate()+1);
15662 var currentYear = this.date && this.date.getUTCFullYear();
15663 var currentMonth = this.date && this.date.getUTCMonth();
15665 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15667 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15668 v.removeClass('active');
15670 if(currentYear === year && k === currentMonth){
15671 v.addClass('active');
15674 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15675 v.addClass('disabled');
15681 year = parseInt(year/10, 10) * 10;
15683 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15685 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15688 for (var i = -1; i < 11; i++) {
15689 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15691 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15699 showMode: function(dir)
15702 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15705 Roo.each(this.picker().select('>div',true).elements, function(v){
15706 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15709 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15714 if(this.isInline) return;
15716 this.picker().removeClass(['bottom', 'top']);
15718 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15720 * place to the top of element!
15724 this.picker().addClass('top');
15725 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15730 this.picker().addClass('bottom');
15732 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15735 parseDate : function(value)
15737 if(!value || value instanceof Date){
15740 var v = Date.parseDate(value, this.format);
15741 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15742 v = Date.parseDate(value, 'Y-m-d');
15744 if(!v && this.altFormats){
15745 if(!this.altFormatsArray){
15746 this.altFormatsArray = this.altFormats.split("|");
15748 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15749 v = Date.parseDate(value, this.altFormatsArray[i]);
15755 formatDate : function(date, fmt)
15757 return (!date || !(date instanceof Date)) ?
15758 date : date.dateFormat(fmt || this.format);
15761 onFocus : function()
15763 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15767 onBlur : function()
15769 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15771 var d = this.inputEl().getValue();
15780 this.picker().show();
15784 this.fireEvent('show', this, this.date);
15789 if(this.isInline) return;
15790 this.picker().hide();
15791 this.viewMode = this.startViewMode;
15794 this.fireEvent('hide', this, this.date);
15798 onMousedown: function(e)
15800 e.stopPropagation();
15801 e.preventDefault();
15806 Roo.bootstrap.DateField.superclass.keyup.call(this);
15810 setValue: function(v)
15813 // v can be a string or a date..
15816 var d = new Date(this.parseDate(v) ).clearTime();
15818 if(isNaN(d.getTime())){
15819 this.date = this.viewDate = '';
15820 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15824 v = this.formatDate(d);
15826 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15828 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15832 this.fireEvent('select', this, this.date);
15836 getValue: function()
15838 return this.formatDate(this.date);
15841 fireKey: function(e)
15843 if (!this.picker().isVisible()){
15844 if (e.keyCode == 27) // allow escape to hide and re-show picker
15849 var dateChanged = false,
15851 newDate, newViewDate;
15856 e.preventDefault();
15860 if (!this.keyboardNavigation) break;
15861 dir = e.keyCode == 37 ? -1 : 1;
15864 newDate = this.moveYear(this.date, dir);
15865 newViewDate = this.moveYear(this.viewDate, dir);
15866 } else if (e.shiftKey){
15867 newDate = this.moveMonth(this.date, dir);
15868 newViewDate = this.moveMonth(this.viewDate, dir);
15870 newDate = new Date(this.date);
15871 newDate.setUTCDate(this.date.getUTCDate() + dir);
15872 newViewDate = new Date(this.viewDate);
15873 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15875 if (this.dateWithinRange(newDate)){
15876 this.date = newDate;
15877 this.viewDate = newViewDate;
15878 this.setValue(this.formatDate(this.date));
15880 e.preventDefault();
15881 dateChanged = true;
15886 if (!this.keyboardNavigation) break;
15887 dir = e.keyCode == 38 ? -1 : 1;
15889 newDate = this.moveYear(this.date, dir);
15890 newViewDate = this.moveYear(this.viewDate, dir);
15891 } else if (e.shiftKey){
15892 newDate = this.moveMonth(this.date, dir);
15893 newViewDate = this.moveMonth(this.viewDate, dir);
15895 newDate = new Date(this.date);
15896 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15897 newViewDate = new Date(this.viewDate);
15898 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15900 if (this.dateWithinRange(newDate)){
15901 this.date = newDate;
15902 this.viewDate = newViewDate;
15903 this.setValue(this.formatDate(this.date));
15905 e.preventDefault();
15906 dateChanged = true;
15910 this.setValue(this.formatDate(this.date));
15912 e.preventDefault();
15915 this.setValue(this.formatDate(this.date));
15929 onClick: function(e)
15931 e.stopPropagation();
15932 e.preventDefault();
15934 var target = e.getTarget();
15936 if(target.nodeName.toLowerCase() === 'i'){
15937 target = Roo.get(target).dom.parentNode;
15940 var nodeName = target.nodeName;
15941 var className = target.className;
15942 var html = target.innerHTML;
15943 //Roo.log(nodeName);
15945 switch(nodeName.toLowerCase()) {
15947 switch(className) {
15953 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15954 switch(this.viewMode){
15956 this.viewDate = this.moveMonth(this.viewDate, dir);
15960 this.viewDate = this.moveYear(this.viewDate, dir);
15966 var date = new Date();
15967 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15969 this.setValue(this.formatDate(this.date));
15976 if (className.indexOf('disabled') < 0) {
15977 this.viewDate.setUTCDate(1);
15978 if (className.indexOf('month') > -1) {
15979 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15981 var year = parseInt(html, 10) || 0;
15982 this.viewDate.setUTCFullYear(year);
15986 if(this.singleMode){
15987 this.setValue(this.formatDate(this.viewDate));
15998 //Roo.log(className);
15999 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16000 var day = parseInt(html, 10) || 1;
16001 var year = this.viewDate.getUTCFullYear(),
16002 month = this.viewDate.getUTCMonth();
16004 if (className.indexOf('old') > -1) {
16011 } else if (className.indexOf('new') > -1) {
16019 //Roo.log([year,month,day]);
16020 this.date = this.UTCDate(year, month, day,0,0,0,0);
16021 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16023 //Roo.log(this.formatDate(this.date));
16024 this.setValue(this.formatDate(this.date));
16031 setStartDate: function(startDate)
16033 this.startDate = startDate || -Infinity;
16034 if (this.startDate !== -Infinity) {
16035 this.startDate = this.parseDate(this.startDate);
16038 this.updateNavArrows();
16041 setEndDate: function(endDate)
16043 this.endDate = endDate || Infinity;
16044 if (this.endDate !== Infinity) {
16045 this.endDate = this.parseDate(this.endDate);
16048 this.updateNavArrows();
16051 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16053 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16054 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16055 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16057 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16058 return parseInt(d, 10);
16061 this.updateNavArrows();
16064 updateNavArrows: function()
16066 if(this.singleMode){
16070 var d = new Date(this.viewDate),
16071 year = d.getUTCFullYear(),
16072 month = d.getUTCMonth();
16074 Roo.each(this.picker().select('.prev', true).elements, function(v){
16076 switch (this.viewMode) {
16079 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16085 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16092 Roo.each(this.picker().select('.next', true).elements, function(v){
16094 switch (this.viewMode) {
16097 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16103 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16111 moveMonth: function(date, dir)
16113 if (!dir) return date;
16114 var new_date = new Date(date.valueOf()),
16115 day = new_date.getUTCDate(),
16116 month = new_date.getUTCMonth(),
16117 mag = Math.abs(dir),
16119 dir = dir > 0 ? 1 : -1;
16122 // If going back one month, make sure month is not current month
16123 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16125 return new_date.getUTCMonth() == month;
16127 // If going forward one month, make sure month is as expected
16128 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16130 return new_date.getUTCMonth() != new_month;
16132 new_month = month + dir;
16133 new_date.setUTCMonth(new_month);
16134 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16135 if (new_month < 0 || new_month > 11)
16136 new_month = (new_month + 12) % 12;
16138 // For magnitudes >1, move one month at a time...
16139 for (var i=0; i<mag; i++)
16140 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16141 new_date = this.moveMonth(new_date, dir);
16142 // ...then reset the day, keeping it in the new month
16143 new_month = new_date.getUTCMonth();
16144 new_date.setUTCDate(day);
16146 return new_month != new_date.getUTCMonth();
16149 // Common date-resetting loop -- if date is beyond end of month, make it
16152 new_date.setUTCDate(--day);
16153 new_date.setUTCMonth(new_month);
16158 moveYear: function(date, dir)
16160 return this.moveMonth(date, dir*12);
16163 dateWithinRange: function(date)
16165 return date >= this.startDate && date <= this.endDate;
16171 this.picker().remove();
16176 Roo.apply(Roo.bootstrap.DateField, {
16187 html: '<i class="fa fa-arrow-left"/>'
16197 html: '<i class="fa fa-arrow-right"/>'
16239 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16240 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16241 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16242 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16243 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16256 navFnc: 'FullYear',
16261 navFnc: 'FullYear',
16266 Roo.apply(Roo.bootstrap.DateField, {
16270 cls: 'datepicker dropdown-menu roo-dynamic',
16274 cls: 'datepicker-days',
16278 cls: 'table-condensed',
16280 Roo.bootstrap.DateField.head,
16284 Roo.bootstrap.DateField.footer
16291 cls: 'datepicker-months',
16295 cls: 'table-condensed',
16297 Roo.bootstrap.DateField.head,
16298 Roo.bootstrap.DateField.content,
16299 Roo.bootstrap.DateField.footer
16306 cls: 'datepicker-years',
16310 cls: 'table-condensed',
16312 Roo.bootstrap.DateField.head,
16313 Roo.bootstrap.DateField.content,
16314 Roo.bootstrap.DateField.footer
16333 * @class Roo.bootstrap.TimeField
16334 * @extends Roo.bootstrap.Input
16335 * Bootstrap DateField class
16339 * Create a new TimeField
16340 * @param {Object} config The config object
16343 Roo.bootstrap.TimeField = function(config){
16344 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16348 * Fires when this field show.
16349 * @param {Roo.bootstrap.DateField} thisthis
16350 * @param {Mixed} date The date value
16355 * Fires when this field hide.
16356 * @param {Roo.bootstrap.DateField} this
16357 * @param {Mixed} date The date value
16362 * Fires when select a date.
16363 * @param {Roo.bootstrap.DateField} this
16364 * @param {Mixed} date The date value
16370 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16373 * @cfg {String} format
16374 * The default time format string which can be overriden for localization support. The format must be
16375 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16379 onRender: function(ct, position)
16382 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16384 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16386 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16388 this.pop = this.picker().select('>.datepicker-time',true).first();
16389 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16391 this.picker().on('mousedown', this.onMousedown, this);
16392 this.picker().on('click', this.onClick, this);
16394 this.picker().addClass('datepicker-dropdown');
16399 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16400 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16401 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16402 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16403 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16404 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16408 fireKey: function(e){
16409 if (!this.picker().isVisible()){
16410 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16416 e.preventDefault();
16424 this.onTogglePeriod();
16427 this.onIncrementMinutes();
16430 this.onDecrementMinutes();
16439 onClick: function(e) {
16440 e.stopPropagation();
16441 e.preventDefault();
16444 picker : function()
16446 return this.el.select('.datepicker', true).first();
16449 fillTime: function()
16451 var time = this.pop.select('tbody', true).first();
16453 time.dom.innerHTML = '';
16468 cls: 'hours-up glyphicon glyphicon-chevron-up'
16488 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16509 cls: 'timepicker-hour',
16524 cls: 'timepicker-minute',
16539 cls: 'btn btn-primary period',
16561 cls: 'hours-down glyphicon glyphicon-chevron-down'
16581 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16599 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16606 var hours = this.time.getHours();
16607 var minutes = this.time.getMinutes();
16620 hours = hours - 12;
16624 hours = '0' + hours;
16628 minutes = '0' + minutes;
16631 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16632 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16633 this.pop.select('button', true).first().dom.innerHTML = period;
16639 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16641 var cls = ['bottom'];
16643 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16650 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16655 this.picker().addClass(cls.join('-'));
16659 Roo.each(cls, function(c){
16661 _this.picker().setTop(_this.inputEl().getHeight());
16665 _this.picker().setTop(0 - _this.picker().getHeight());
16670 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16674 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16681 onFocus : function()
16683 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16687 onBlur : function()
16689 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16695 this.picker().show();
16700 this.fireEvent('show', this, this.date);
16705 this.picker().hide();
16708 this.fireEvent('hide', this, this.date);
16711 setTime : function()
16714 this.setValue(this.time.format(this.format));
16716 this.fireEvent('select', this, this.date);
16721 onMousedown: function(e){
16722 e.stopPropagation();
16723 e.preventDefault();
16726 onIncrementHours: function()
16728 Roo.log('onIncrementHours');
16729 this.time = this.time.add(Date.HOUR, 1);
16734 onDecrementHours: function()
16736 Roo.log('onDecrementHours');
16737 this.time = this.time.add(Date.HOUR, -1);
16741 onIncrementMinutes: function()
16743 Roo.log('onIncrementMinutes');
16744 this.time = this.time.add(Date.MINUTE, 1);
16748 onDecrementMinutes: function()
16750 Roo.log('onDecrementMinutes');
16751 this.time = this.time.add(Date.MINUTE, -1);
16755 onTogglePeriod: function()
16757 Roo.log('onTogglePeriod');
16758 this.time = this.time.add(Date.HOUR, 12);
16765 Roo.apply(Roo.bootstrap.TimeField, {
16795 cls: 'btn btn-info ok',
16807 Roo.apply(Roo.bootstrap.TimeField, {
16811 cls: 'datepicker dropdown-menu',
16815 cls: 'datepicker-time',
16819 cls: 'table-condensed',
16821 Roo.bootstrap.TimeField.content,
16822 Roo.bootstrap.TimeField.footer
16841 * @class Roo.bootstrap.MonthField
16842 * @extends Roo.bootstrap.Input
16843 * Bootstrap MonthField class
16845 * @cfg {String} language default en
16848 * Create a new MonthField
16849 * @param {Object} config The config object
16852 Roo.bootstrap.MonthField = function(config){
16853 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16858 * Fires when this field show.
16859 * @param {Roo.bootstrap.MonthField} this
16860 * @param {Mixed} date The date value
16865 * Fires when this field hide.
16866 * @param {Roo.bootstrap.MonthField} this
16867 * @param {Mixed} date The date value
16872 * Fires when select a date.
16873 * @param {Roo.bootstrap.MonthField} this
16874 * @param {String} oldvalue The old value
16875 * @param {String} newvalue The new value
16881 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16883 onRender: function(ct, position)
16886 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16888 this.language = this.language || 'en';
16889 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16890 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16892 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16893 this.isInline = false;
16894 this.isInput = true;
16895 this.component = this.el.select('.add-on', true).first() || false;
16896 this.component = (this.component && this.component.length === 0) ? false : this.component;
16897 this.hasInput = this.component && this.inputEL().length;
16899 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16901 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16903 this.picker().on('mousedown', this.onMousedown, this);
16904 this.picker().on('click', this.onClick, this);
16906 this.picker().addClass('datepicker-dropdown');
16908 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16909 v.setStyle('width', '189px');
16916 if(this.isInline) {
16922 setValue: function(v, suppressEvent)
16924 var o = this.getValue();
16926 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16930 if(suppressEvent !== true){
16931 this.fireEvent('select', this, o, v);
16936 getValue: function()
16941 onClick: function(e)
16943 e.stopPropagation();
16944 e.preventDefault();
16946 var target = e.getTarget();
16948 if(target.nodeName.toLowerCase() === 'i'){
16949 target = Roo.get(target).dom.parentNode;
16952 var nodeName = target.nodeName;
16953 var className = target.className;
16954 var html = target.innerHTML;
16956 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16960 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16962 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16968 picker : function()
16970 return this.pickerEl;
16973 fillMonths: function()
16976 var months = this.picker().select('>.datepicker-months td', true).first();
16978 months.dom.innerHTML = '';
16984 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16987 months.createChild(month);
16996 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16997 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17000 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17001 e.removeClass('active');
17003 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17004 e.addClass('active');
17011 if(this.isInline) return;
17013 this.picker().removeClass(['bottom', 'top']);
17015 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17017 * place to the top of element!
17021 this.picker().addClass('top');
17022 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17027 this.picker().addClass('bottom');
17029 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17032 onFocus : function()
17034 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17038 onBlur : function()
17040 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17042 var d = this.inputEl().getValue();
17051 this.picker().show();
17052 this.picker().select('>.datepicker-months', true).first().show();
17056 this.fireEvent('show', this, this.date);
17061 if(this.isInline) return;
17062 this.picker().hide();
17063 this.fireEvent('hide', this, this.date);
17067 onMousedown: function(e)
17069 e.stopPropagation();
17070 e.preventDefault();
17075 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17079 fireKey: function(e)
17081 if (!this.picker().isVisible()){
17082 if (e.keyCode == 27) // allow escape to hide and re-show picker
17092 e.preventDefault();
17096 dir = e.keyCode == 37 ? -1 : 1;
17098 this.vIndex = this.vIndex + dir;
17100 if(this.vIndex < 0){
17104 if(this.vIndex > 11){
17108 if(isNaN(this.vIndex)){
17112 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17118 dir = e.keyCode == 38 ? -1 : 1;
17120 this.vIndex = this.vIndex + dir * 4;
17122 if(this.vIndex < 0){
17126 if(this.vIndex > 11){
17130 if(isNaN(this.vIndex)){
17134 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17139 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17140 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17144 e.preventDefault();
17147 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17148 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17164 this.picker().remove();
17169 Roo.apply(Roo.bootstrap.MonthField, {
17188 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17189 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17194 Roo.apply(Roo.bootstrap.MonthField, {
17198 cls: 'datepicker dropdown-menu roo-dynamic',
17202 cls: 'datepicker-months',
17206 cls: 'table-condensed',
17208 Roo.bootstrap.DateField.content
17228 * @class Roo.bootstrap.CheckBox
17229 * @extends Roo.bootstrap.Input
17230 * Bootstrap CheckBox class
17232 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17233 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17234 * @cfg {String} boxLabel The text that appears beside the checkbox
17235 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17236 * @cfg {Boolean} checked initnal the element
17237 * @cfg {Boolean} inline inline the element (default false)
17238 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17241 * Create a new CheckBox
17242 * @param {Object} config The config object
17245 Roo.bootstrap.CheckBox = function(config){
17246 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17251 * Fires when the element is checked or unchecked.
17252 * @param {Roo.bootstrap.CheckBox} this This input
17253 * @param {Boolean} checked The new checked value
17260 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17262 inputType: 'checkbox',
17270 getAutoCreate : function()
17272 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17278 cfg.cls = 'form-group ' + this.inputType; //input-group
17281 cfg.cls += ' ' + this.inputType + '-inline';
17287 type : this.inputType,
17288 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17289 cls : 'roo-' + this.inputType, //'form-box',
17290 placeholder : this.placeholder || ''
17294 if (this.weight) { // Validity check?
17295 cfg.cls += " " + this.inputType + "-" + this.weight;
17298 if (this.disabled) {
17299 input.disabled=true;
17303 input.checked = this.checked;
17307 input.name = this.name;
17311 input.cls += ' input-' + this.size;
17316 ['xs','sm','md','lg'].map(function(size){
17317 if (settings[size]) {
17318 cfg.cls += ' col-' + size + '-' + settings[size];
17322 var inputblock = input;
17324 if (this.before || this.after) {
17327 cls : 'input-group',
17332 inputblock.cn.push({
17334 cls : 'input-group-addon',
17339 inputblock.cn.push(input);
17342 inputblock.cn.push({
17344 cls : 'input-group-addon',
17351 if (align ==='left' && this.fieldLabel.length) {
17352 Roo.log("left and has label");
17358 cls : 'control-label col-md-' + this.labelWidth,
17359 html : this.fieldLabel
17363 cls : "col-md-" + (12 - this.labelWidth),
17370 } else if ( this.fieldLabel.length) {
17375 tag: this.boxLabel ? 'span' : 'label',
17377 cls: 'control-label box-input-label',
17378 //cls : 'input-group-addon',
17379 html : this.fieldLabel
17389 Roo.log(" no label && no align");
17390 cfg.cn = [ inputblock ] ;
17395 var boxLabelCfg = {
17397 //'for': id, // box label is handled by onclick - so no for...
17399 html: this.boxLabel
17403 boxLabelCfg.tooltip = this.tooltip;
17406 cfg.cn.push(boxLabelCfg);
17416 * return the real input element.
17418 inputEl: function ()
17420 return this.el.select('input.roo-' + this.inputType,true).first();
17423 labelEl: function()
17425 return this.el.select('label.control-label',true).first();
17427 /* depricated... */
17431 return this.labelEl();
17434 initEvents : function()
17436 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17438 this.inputEl().on('click', this.onClick, this);
17440 if (this.boxLabel) {
17441 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17444 this.startValue = this.getValue();
17447 Roo.bootstrap.CheckBox.register(this);
17451 onClick : function()
17453 this.setChecked(!this.checked);
17456 setChecked : function(state,suppressEvent)
17458 this.startValue = this.getValue();
17460 if(this.inputType == 'radio'){
17462 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17463 e.dom.checked = false;
17466 this.inputEl().dom.checked = true;
17468 this.inputEl().dom.value = this.inputValue;
17470 if(suppressEvent !== true){
17471 this.fireEvent('check', this, true);
17479 this.checked = state;
17481 this.inputEl().dom.checked = state;
17483 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17485 if(suppressEvent !== true){
17486 this.fireEvent('check', this, state);
17492 getValue : function()
17494 if(this.inputType == 'radio'){
17495 return this.getGroupValue();
17498 return this.inputEl().getValue();
17502 getGroupValue : function()
17504 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17508 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17511 setValue : function(v,suppressEvent)
17513 if(this.inputType == 'radio'){
17514 this.setGroupValue(v, suppressEvent);
17518 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17523 setGroupValue : function(v, suppressEvent)
17525 this.startValue = this.getValue();
17527 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17528 e.dom.checked = false;
17530 if(e.dom.value == v){
17531 e.dom.checked = true;
17535 if(suppressEvent !== true){
17536 this.fireEvent('check', this, true);
17544 validate : function()
17548 (this.inputType == 'radio' && this.validateRadio()) ||
17549 (this.inputType == 'checkbox' && this.validateCheckbox())
17555 this.markInvalid();
17559 validateRadio : function()
17563 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17564 if(!e.dom.checked){
17576 validateCheckbox : function()
17579 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17582 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17590 for(var i in group){
17595 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17602 * Mark this field as valid
17604 markValid : function()
17606 if(this.allowBlank){
17612 this.fireEvent('valid', this);
17614 if(this.inputType == 'radio'){
17615 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17616 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17617 e.findParent('.form-group', false, true).addClass(_this.validClass);
17624 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17625 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17629 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17635 for(var i in group){
17636 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17637 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17642 * Mark this field as invalid
17643 * @param {String} msg The validation message
17645 markInvalid : function(msg)
17647 if(this.allowBlank){
17653 this.fireEvent('invalid', this, msg);
17655 if(this.inputType == 'radio'){
17656 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17657 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17658 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17665 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17666 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17670 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17676 for(var i in group){
17677 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17678 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17685 Roo.apply(Roo.bootstrap.CheckBox, {
17690 * register a CheckBox Group
17691 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17693 register : function(checkbox)
17695 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17696 this.groups[checkbox.groupId] = {};
17699 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17703 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17707 * fetch a CheckBox Group based on the group ID
17708 * @param {string} the group ID
17709 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17711 get: function(groupId) {
17712 if (typeof(this.groups[groupId]) == 'undefined') {
17716 return this.groups[groupId] ;
17728 *<div class="radio">
17730 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17731 Option one is this and that—be sure to include why it's great
17738 *<label class="radio-inline">fieldLabel</label>
17739 *<label class="radio-inline">
17740 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17748 * @class Roo.bootstrap.Radio
17749 * @extends Roo.bootstrap.CheckBox
17750 * Bootstrap Radio class
17753 * Create a new Radio
17754 * @param {Object} config The config object
17757 Roo.bootstrap.Radio = function(config){
17758 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17762 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17764 inputType: 'radio',
17768 getAutoCreate : function()
17770 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17771 align = align || 'left'; // default...
17778 tag : this.inline ? 'span' : 'div',
17783 var inline = this.inline ? ' radio-inline' : '';
17787 // does not need for, as we wrap the input with it..
17789 cls : 'control-label box-label' + inline,
17792 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17796 //cls : 'control-label' + inline,
17797 html : this.fieldLabel,
17798 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17807 type : this.inputType,
17808 //value : (!this.checked) ? this.valueOff : this.inputValue,
17809 value : this.inputValue,
17811 placeholder : this.placeholder || '' // ?? needed????
17814 if (this.weight) { // Validity check?
17815 input.cls += " radio-" + this.weight;
17817 if (this.disabled) {
17818 input.disabled=true;
17822 input.checked = this.checked;
17826 input.name = this.name;
17830 input.cls += ' input-' + this.size;
17833 //?? can span's inline have a width??
17836 ['xs','sm','md','lg'].map(function(size){
17837 if (settings[size]) {
17838 cfg.cls += ' col-' + size + '-' + settings[size];
17842 var inputblock = input;
17844 if (this.before || this.after) {
17847 cls : 'input-group',
17852 inputblock.cn.push({
17854 cls : 'input-group-addon',
17858 inputblock.cn.push(input);
17860 inputblock.cn.push({
17862 cls : 'input-group-addon',
17870 if (this.fieldLabel && this.fieldLabel.length) {
17871 cfg.cn.push(fieldLabel);
17874 // normal bootstrap puts the input inside the label.
17875 // however with our styled version - it has to go after the input.
17877 //lbl.cn.push(inputblock);
17881 cls: 'radio' + inline,
17888 cfg.cn.push( lblwrap);
17893 html: this.boxLabel
17902 initEvents : function()
17904 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17906 this.inputEl().on('click', this.onClick, this);
17907 if (this.boxLabel) {
17908 Roo.log('find label')
17909 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17914 inputEl: function ()
17916 return this.el.select('input.roo-radio',true).first();
17918 onClick : function()
17921 this.setChecked(true);
17924 setChecked : function(state,suppressEvent)
17927 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17928 v.dom.checked = false;
17931 Roo.log(this.inputEl().dom);
17932 this.checked = state;
17933 this.inputEl().dom.checked = state;
17935 if(suppressEvent !== true){
17936 this.fireEvent('check', this, state);
17939 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17943 getGroupValue : function()
17946 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17947 if(v.dom.checked == true){
17948 value = v.dom.value;
17956 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17957 * @return {Mixed} value The field value
17959 getValue : function(){
17960 return this.getGroupValue();
17966 //<script type="text/javascript">
17969 * Based Ext JS Library 1.1.1
17970 * Copyright(c) 2006-2007, Ext JS, LLC.
17976 * @class Roo.HtmlEditorCore
17977 * @extends Roo.Component
17978 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17980 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17983 Roo.HtmlEditorCore = function(config){
17986 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17991 * @event initialize
17992 * Fires when the editor is fully initialized (including the iframe)
17993 * @param {Roo.HtmlEditorCore} this
17998 * Fires when the editor is first receives the focus. Any insertion must wait
17999 * until after this event.
18000 * @param {Roo.HtmlEditorCore} this
18004 * @event beforesync
18005 * Fires before the textarea is updated with content from the editor iframe. Return false
18006 * to cancel the sync.
18007 * @param {Roo.HtmlEditorCore} this
18008 * @param {String} html
18012 * @event beforepush
18013 * Fires before the iframe editor is updated with content from the textarea. Return false
18014 * to cancel the push.
18015 * @param {Roo.HtmlEditorCore} this
18016 * @param {String} html
18021 * Fires when the textarea is updated with content from the editor iframe.
18022 * @param {Roo.HtmlEditorCore} this
18023 * @param {String} html
18028 * Fires when the iframe editor is updated with content from the textarea.
18029 * @param {Roo.HtmlEditorCore} this
18030 * @param {String} html
18035 * @event editorevent
18036 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18037 * @param {Roo.HtmlEditorCore} this
18043 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18045 // defaults : white / black...
18046 this.applyBlacklists();
18053 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18057 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18063 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18068 * @cfg {Number} height (in pixels)
18072 * @cfg {Number} width (in pixels)
18077 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18080 stylesheets: false,
18085 // private properties
18086 validationEvent : false,
18088 initialized : false,
18090 sourceEditMode : false,
18091 onFocus : Roo.emptyFn,
18093 hideMode:'offsets',
18097 // blacklist + whitelisted elements..
18104 * Protected method that will not generally be called directly. It
18105 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18106 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18108 getDocMarkup : function(){
18112 // inherit styels from page...??
18113 if (this.stylesheets === false) {
18115 Roo.get(document.head).select('style').each(function(node) {
18116 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18119 Roo.get(document.head).select('link').each(function(node) {
18120 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18123 } else if (!this.stylesheets.length) {
18125 st = '<style type="text/css">' +
18126 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18132 st += '<style type="text/css">' +
18133 'IMG { cursor: pointer } ' +
18137 return '<html><head>' + st +
18138 //<style type="text/css">' +
18139 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18141 ' </head><body class="roo-htmleditor-body"></body></html>';
18145 onRender : function(ct, position)
18148 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18149 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18152 this.el.dom.style.border = '0 none';
18153 this.el.dom.setAttribute('tabIndex', -1);
18154 this.el.addClass('x-hidden hide');
18158 if(Roo.isIE){ // fix IE 1px bogus margin
18159 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18163 this.frameId = Roo.id();
18167 var iframe = this.owner.wrap.createChild({
18169 cls: 'form-control', // bootstrap..
18171 name: this.frameId,
18172 frameBorder : 'no',
18173 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18178 this.iframe = iframe.dom;
18180 this.assignDocWin();
18182 this.doc.designMode = 'on';
18185 this.doc.write(this.getDocMarkup());
18189 var task = { // must defer to wait for browser to be ready
18191 //console.log("run task?" + this.doc.readyState);
18192 this.assignDocWin();
18193 if(this.doc.body || this.doc.readyState == 'complete'){
18195 this.doc.designMode="on";
18199 Roo.TaskMgr.stop(task);
18200 this.initEditor.defer(10, this);
18207 Roo.TaskMgr.start(task);
18212 onResize : function(w, h)
18214 Roo.log('resize: ' +w + ',' + h );
18215 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18219 if(typeof w == 'number'){
18221 this.iframe.style.width = w + 'px';
18223 if(typeof h == 'number'){
18225 this.iframe.style.height = h + 'px';
18227 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18234 * Toggles the editor between standard and source edit mode.
18235 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18237 toggleSourceEdit : function(sourceEditMode){
18239 this.sourceEditMode = sourceEditMode === true;
18241 if(this.sourceEditMode){
18243 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18246 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18247 //this.iframe.className = '';
18250 //this.setSize(this.owner.wrap.getSize());
18251 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18258 * Protected method that will not generally be called directly. If you need/want
18259 * custom HTML cleanup, this is the method you should override.
18260 * @param {String} html The HTML to be cleaned
18261 * return {String} The cleaned HTML
18263 cleanHtml : function(html){
18264 html = String(html);
18265 if(html.length > 5){
18266 if(Roo.isSafari){ // strip safari nonsense
18267 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18270 if(html == ' '){
18277 * HTML Editor -> Textarea
18278 * Protected method that will not generally be called directly. Syncs the contents
18279 * of the editor iframe with the textarea.
18281 syncValue : function(){
18282 if(this.initialized){
18283 var bd = (this.doc.body || this.doc.documentElement);
18284 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18285 var html = bd.innerHTML;
18287 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18288 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18290 html = '<div style="'+m[0]+'">' + html + '</div>';
18293 html = this.cleanHtml(html);
18294 // fix up the special chars.. normaly like back quotes in word...
18295 // however we do not want to do this with chinese..
18296 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18297 var cc = b.charCodeAt();
18299 (cc >= 0x4E00 && cc < 0xA000 ) ||
18300 (cc >= 0x3400 && cc < 0x4E00 ) ||
18301 (cc >= 0xf900 && cc < 0xfb00 )
18307 if(this.owner.fireEvent('beforesync', this, html) !== false){
18308 this.el.dom.value = html;
18309 this.owner.fireEvent('sync', this, html);
18315 * Protected method that will not generally be called directly. Pushes the value of the textarea
18316 * into the iframe editor.
18318 pushValue : function(){
18319 if(this.initialized){
18320 var v = this.el.dom.value.trim();
18322 // if(v.length < 1){
18326 if(this.owner.fireEvent('beforepush', this, v) !== false){
18327 var d = (this.doc.body || this.doc.documentElement);
18329 this.cleanUpPaste();
18330 this.el.dom.value = d.innerHTML;
18331 this.owner.fireEvent('push', this, v);
18337 deferFocus : function(){
18338 this.focus.defer(10, this);
18342 focus : function(){
18343 if(this.win && !this.sourceEditMode){
18350 assignDocWin: function()
18352 var iframe = this.iframe;
18355 this.doc = iframe.contentWindow.document;
18356 this.win = iframe.contentWindow;
18358 // if (!Roo.get(this.frameId)) {
18361 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18362 // this.win = Roo.get(this.frameId).dom.contentWindow;
18364 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18368 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18369 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18374 initEditor : function(){
18375 //console.log("INIT EDITOR");
18376 this.assignDocWin();
18380 this.doc.designMode="on";
18382 this.doc.write(this.getDocMarkup());
18385 var dbody = (this.doc.body || this.doc.documentElement);
18386 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18387 // this copies styles from the containing element into thsi one..
18388 // not sure why we need all of this..
18389 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18391 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18392 //ss['background-attachment'] = 'fixed'; // w3c
18393 dbody.bgProperties = 'fixed'; // ie
18394 //Roo.DomHelper.applyStyles(dbody, ss);
18395 Roo.EventManager.on(this.doc, {
18396 //'mousedown': this.onEditorEvent,
18397 'mouseup': this.onEditorEvent,
18398 'dblclick': this.onEditorEvent,
18399 'click': this.onEditorEvent,
18400 'keyup': this.onEditorEvent,
18405 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18407 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18408 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18410 this.initialized = true;
18412 this.owner.fireEvent('initialize', this);
18417 onDestroy : function(){
18423 //for (var i =0; i < this.toolbars.length;i++) {
18424 // // fixme - ask toolbars for heights?
18425 // this.toolbars[i].onDestroy();
18428 //this.wrap.dom.innerHTML = '';
18429 //this.wrap.remove();
18434 onFirstFocus : function(){
18436 this.assignDocWin();
18439 this.activated = true;
18442 if(Roo.isGecko){ // prevent silly gecko errors
18444 var s = this.win.getSelection();
18445 if(!s.focusNode || s.focusNode.nodeType != 3){
18446 var r = s.getRangeAt(0);
18447 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18452 this.execCmd('useCSS', true);
18453 this.execCmd('styleWithCSS', false);
18456 this.owner.fireEvent('activate', this);
18460 adjustFont: function(btn){
18461 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18462 //if(Roo.isSafari){ // safari
18465 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18466 if(Roo.isSafari){ // safari
18467 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18468 v = (v < 10) ? 10 : v;
18469 v = (v > 48) ? 48 : v;
18470 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18475 v = Math.max(1, v+adjust);
18477 this.execCmd('FontSize', v );
18480 onEditorEvent : function(e)
18482 this.owner.fireEvent('editorevent', this, e);
18483 // this.updateToolbar();
18484 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18487 insertTag : function(tg)
18489 // could be a bit smarter... -> wrap the current selected tRoo..
18490 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18492 range = this.createRange(this.getSelection());
18493 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18494 wrappingNode.appendChild(range.extractContents());
18495 range.insertNode(wrappingNode);
18502 this.execCmd("formatblock", tg);
18506 insertText : function(txt)
18510 var range = this.createRange();
18511 range.deleteContents();
18512 //alert(Sender.getAttribute('label'));
18514 range.insertNode(this.doc.createTextNode(txt));
18520 * Executes a Midas editor command on the editor document and performs necessary focus and
18521 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18522 * @param {String} cmd The Midas command
18523 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18525 relayCmd : function(cmd, value){
18527 this.execCmd(cmd, value);
18528 this.owner.fireEvent('editorevent', this);
18529 //this.updateToolbar();
18530 this.owner.deferFocus();
18534 * Executes a Midas editor command directly on the editor document.
18535 * For visual commands, you should use {@link #relayCmd} instead.
18536 * <b>This should only be called after the editor is initialized.</b>
18537 * @param {String} cmd The Midas command
18538 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18540 execCmd : function(cmd, value){
18541 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18548 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18550 * @param {String} text | dom node..
18552 insertAtCursor : function(text)
18557 if(!this.activated){
18563 var r = this.doc.selection.createRange();
18574 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18578 // from jquery ui (MIT licenced)
18580 var win = this.win;
18582 if (win.getSelection && win.getSelection().getRangeAt) {
18583 range = win.getSelection().getRangeAt(0);
18584 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18585 range.insertNode(node);
18586 } else if (win.document.selection && win.document.selection.createRange) {
18587 // no firefox support
18588 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18589 win.document.selection.createRange().pasteHTML(txt);
18591 // no firefox support
18592 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18593 this.execCmd('InsertHTML', txt);
18602 mozKeyPress : function(e){
18604 var c = e.getCharCode(), cmd;
18607 c = String.fromCharCode(c).toLowerCase();
18621 this.cleanUpPaste.defer(100, this);
18629 e.preventDefault();
18637 fixKeys : function(){ // load time branching for fastest keydown performance
18639 return function(e){
18640 var k = e.getKey(), r;
18643 r = this.doc.selection.createRange();
18646 r.pasteHTML('    ');
18653 r = this.doc.selection.createRange();
18655 var target = r.parentElement();
18656 if(!target || target.tagName.toLowerCase() != 'li'){
18658 r.pasteHTML('<br />');
18664 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18665 this.cleanUpPaste.defer(100, this);
18671 }else if(Roo.isOpera){
18672 return function(e){
18673 var k = e.getKey();
18677 this.execCmd('InsertHTML','    ');
18680 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18681 this.cleanUpPaste.defer(100, this);
18686 }else if(Roo.isSafari){
18687 return function(e){
18688 var k = e.getKey();
18692 this.execCmd('InsertText','\t');
18696 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18697 this.cleanUpPaste.defer(100, this);
18705 getAllAncestors: function()
18707 var p = this.getSelectedNode();
18710 a.push(p); // push blank onto stack..
18711 p = this.getParentElement();
18715 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18719 a.push(this.doc.body);
18723 lastSelNode : false,
18726 getSelection : function()
18728 this.assignDocWin();
18729 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18732 getSelectedNode: function()
18734 // this may only work on Gecko!!!
18736 // should we cache this!!!!
18741 var range = this.createRange(this.getSelection()).cloneRange();
18744 var parent = range.parentElement();
18746 var testRange = range.duplicate();
18747 testRange.moveToElementText(parent);
18748 if (testRange.inRange(range)) {
18751 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18754 parent = parent.parentElement;
18759 // is ancestor a text element.
18760 var ac = range.commonAncestorContainer;
18761 if (ac.nodeType == 3) {
18762 ac = ac.parentNode;
18765 var ar = ac.childNodes;
18768 var other_nodes = [];
18769 var has_other_nodes = false;
18770 for (var i=0;i<ar.length;i++) {
18771 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18774 // fullly contained node.
18776 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18781 // probably selected..
18782 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18783 other_nodes.push(ar[i]);
18787 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18792 has_other_nodes = true;
18794 if (!nodes.length && other_nodes.length) {
18795 nodes= other_nodes;
18797 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18803 createRange: function(sel)
18805 // this has strange effects when using with
18806 // top toolbar - not sure if it's a great idea.
18807 //this.editor.contentWindow.focus();
18808 if (typeof sel != "undefined") {
18810 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18812 return this.doc.createRange();
18815 return this.doc.createRange();
18818 getParentElement: function()
18821 this.assignDocWin();
18822 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18824 var range = this.createRange(sel);
18827 var p = range.commonAncestorContainer;
18828 while (p.nodeType == 3) { // text node
18839 * Range intersection.. the hard stuff...
18843 * [ -- selected range --- ]
18847 * if end is before start or hits it. fail.
18848 * if start is after end or hits it fail.
18850 * if either hits (but other is outside. - then it's not
18856 // @see http://www.thismuchiknow.co.uk/?p=64.
18857 rangeIntersectsNode : function(range, node)
18859 var nodeRange = node.ownerDocument.createRange();
18861 nodeRange.selectNode(node);
18863 nodeRange.selectNodeContents(node);
18866 var rangeStartRange = range.cloneRange();
18867 rangeStartRange.collapse(true);
18869 var rangeEndRange = range.cloneRange();
18870 rangeEndRange.collapse(false);
18872 var nodeStartRange = nodeRange.cloneRange();
18873 nodeStartRange.collapse(true);
18875 var nodeEndRange = nodeRange.cloneRange();
18876 nodeEndRange.collapse(false);
18878 return rangeStartRange.compareBoundaryPoints(
18879 Range.START_TO_START, nodeEndRange) == -1 &&
18880 rangeEndRange.compareBoundaryPoints(
18881 Range.START_TO_START, nodeStartRange) == 1;
18885 rangeCompareNode : function(range, node)
18887 var nodeRange = node.ownerDocument.createRange();
18889 nodeRange.selectNode(node);
18891 nodeRange.selectNodeContents(node);
18895 range.collapse(true);
18897 nodeRange.collapse(true);
18899 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18900 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18902 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18904 var nodeIsBefore = ss == 1;
18905 var nodeIsAfter = ee == -1;
18907 if (nodeIsBefore && nodeIsAfter)
18909 if (!nodeIsBefore && nodeIsAfter)
18910 return 1; //right trailed.
18912 if (nodeIsBefore && !nodeIsAfter)
18913 return 2; // left trailed.
18918 // private? - in a new class?
18919 cleanUpPaste : function()
18921 // cleans up the whole document..
18922 Roo.log('cleanuppaste');
18924 this.cleanUpChildren(this.doc.body);
18925 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18926 if (clean != this.doc.body.innerHTML) {
18927 this.doc.body.innerHTML = clean;
18932 cleanWordChars : function(input) {// change the chars to hex code
18933 var he = Roo.HtmlEditorCore;
18935 var output = input;
18936 Roo.each(he.swapCodes, function(sw) {
18937 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18939 output = output.replace(swapper, sw[1]);
18946 cleanUpChildren : function (n)
18948 if (!n.childNodes.length) {
18951 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18952 this.cleanUpChild(n.childNodes[i]);
18959 cleanUpChild : function (node)
18962 //console.log(node);
18963 if (node.nodeName == "#text") {
18964 // clean up silly Windows -- stuff?
18967 if (node.nodeName == "#comment") {
18968 node.parentNode.removeChild(node);
18969 // clean up silly Windows -- stuff?
18972 var lcname = node.tagName.toLowerCase();
18973 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18974 // whitelist of tags..
18976 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18978 node.parentNode.removeChild(node);
18983 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18985 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18986 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18988 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18989 // remove_keep_children = true;
18992 if (remove_keep_children) {
18993 this.cleanUpChildren(node);
18994 // inserts everything just before this node...
18995 while (node.childNodes.length) {
18996 var cn = node.childNodes[0];
18997 node.removeChild(cn);
18998 node.parentNode.insertBefore(cn, node);
19000 node.parentNode.removeChild(node);
19004 if (!node.attributes || !node.attributes.length) {
19005 this.cleanUpChildren(node);
19009 function cleanAttr(n,v)
19012 if (v.match(/^\./) || v.match(/^\//)) {
19015 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19018 if (v.match(/^#/)) {
19021 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19022 node.removeAttribute(n);
19026 var cwhite = this.cwhite;
19027 var cblack = this.cblack;
19029 function cleanStyle(n,v)
19031 if (v.match(/expression/)) { //XSS?? should we even bother..
19032 node.removeAttribute(n);
19036 var parts = v.split(/;/);
19039 Roo.each(parts, function(p) {
19040 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19044 var l = p.split(':').shift().replace(/\s+/g,'');
19045 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19047 if ( cwhite.length && cblack.indexOf(l) > -1) {
19048 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19049 //node.removeAttribute(n);
19053 // only allow 'c whitelisted system attributes'
19054 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19055 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19056 //node.removeAttribute(n);
19066 if (clean.length) {
19067 node.setAttribute(n, clean.join(';'));
19069 node.removeAttribute(n);
19075 for (var i = node.attributes.length-1; i > -1 ; i--) {
19076 var a = node.attributes[i];
19079 if (a.name.toLowerCase().substr(0,2)=='on') {
19080 node.removeAttribute(a.name);
19083 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19084 node.removeAttribute(a.name);
19087 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19088 cleanAttr(a.name,a.value); // fixme..
19091 if (a.name == 'style') {
19092 cleanStyle(a.name,a.value);
19095 /// clean up MS crap..
19096 // tecnically this should be a list of valid class'es..
19099 if (a.name == 'class') {
19100 if (a.value.match(/^Mso/)) {
19101 node.className = '';
19104 if (a.value.match(/body/)) {
19105 node.className = '';
19116 this.cleanUpChildren(node);
19121 * Clean up MS wordisms...
19123 cleanWord : function(node)
19126 var cleanWordChildren = function()
19128 if (!node.childNodes.length) {
19131 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19132 _t.cleanWord(node.childNodes[i]);
19138 this.cleanWord(this.doc.body);
19141 if (node.nodeName == "#text") {
19142 // clean up silly Windows -- stuff?
19145 if (node.nodeName == "#comment") {
19146 node.parentNode.removeChild(node);
19147 // clean up silly Windows -- stuff?
19151 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19152 node.parentNode.removeChild(node);
19156 // remove - but keep children..
19157 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19158 while (node.childNodes.length) {
19159 var cn = node.childNodes[0];
19160 node.removeChild(cn);
19161 node.parentNode.insertBefore(cn, node);
19163 node.parentNode.removeChild(node);
19164 cleanWordChildren();
19168 if (node.className.length) {
19170 var cn = node.className.split(/\W+/);
19172 Roo.each(cn, function(cls) {
19173 if (cls.match(/Mso[a-zA-Z]+/)) {
19178 node.className = cna.length ? cna.join(' ') : '';
19180 node.removeAttribute("class");
19184 if (node.hasAttribute("lang")) {
19185 node.removeAttribute("lang");
19188 if (node.hasAttribute("style")) {
19190 var styles = node.getAttribute("style").split(";");
19192 Roo.each(styles, function(s) {
19193 if (!s.match(/:/)) {
19196 var kv = s.split(":");
19197 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19200 // what ever is left... we allow.
19203 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19204 if (!nstyle.length) {
19205 node.removeAttribute('style');
19209 cleanWordChildren();
19213 domToHTML : function(currentElement, depth, nopadtext) {
19215 depth = depth || 0;
19216 nopadtext = nopadtext || false;
19218 if (!currentElement) {
19219 return this.domToHTML(this.doc.body);
19222 //Roo.log(currentElement);
19224 var allText = false;
19225 var nodeName = currentElement.nodeName;
19226 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19228 if (nodeName == '#text') {
19230 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19235 if (nodeName != 'BODY') {
19238 // Prints the node tagName, such as <A>, <IMG>, etc
19241 for(i = 0; i < currentElement.attributes.length;i++) {
19243 var aname = currentElement.attributes.item(i).name;
19244 if (!currentElement.attributes.item(i).value.length) {
19247 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19250 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19259 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19262 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19267 // Traverse the tree
19269 var currentElementChild = currentElement.childNodes.item(i);
19270 var allText = true;
19271 var innerHTML = '';
19273 while (currentElementChild) {
19274 // Formatting code (indent the tree so it looks nice on the screen)
19275 var nopad = nopadtext;
19276 if (lastnode == 'SPAN') {
19280 if (currentElementChild.nodeName == '#text') {
19281 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19282 toadd = nopadtext ? toadd : toadd.trim();
19283 if (!nopad && toadd.length > 80) {
19284 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19286 innerHTML += toadd;
19289 currentElementChild = currentElement.childNodes.item(i);
19295 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19297 // Recursively traverse the tree structure of the child node
19298 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19299 lastnode = currentElementChild.nodeName;
19301 currentElementChild=currentElement.childNodes.item(i);
19307 // The remaining code is mostly for formatting the tree
19308 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19313 ret+= "</"+tagName+">";
19319 applyBlacklists : function()
19321 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19322 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19326 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19327 if (b.indexOf(tag) > -1) {
19330 this.white.push(tag);
19334 Roo.each(w, function(tag) {
19335 if (b.indexOf(tag) > -1) {
19338 if (this.white.indexOf(tag) > -1) {
19341 this.white.push(tag);
19346 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19347 if (w.indexOf(tag) > -1) {
19350 this.black.push(tag);
19354 Roo.each(b, function(tag) {
19355 if (w.indexOf(tag) > -1) {
19358 if (this.black.indexOf(tag) > -1) {
19361 this.black.push(tag);
19366 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19367 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19371 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19372 if (b.indexOf(tag) > -1) {
19375 this.cwhite.push(tag);
19379 Roo.each(w, function(tag) {
19380 if (b.indexOf(tag) > -1) {
19383 if (this.cwhite.indexOf(tag) > -1) {
19386 this.cwhite.push(tag);
19391 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19392 if (w.indexOf(tag) > -1) {
19395 this.cblack.push(tag);
19399 Roo.each(b, function(tag) {
19400 if (w.indexOf(tag) > -1) {
19403 if (this.cblack.indexOf(tag) > -1) {
19406 this.cblack.push(tag);
19411 setStylesheets : function(stylesheets)
19413 if(typeof(stylesheets) == 'string'){
19414 Roo.get(this.iframe.contentDocument.head).createChild({
19416 rel : 'stylesheet',
19425 Roo.each(stylesheets, function(s) {
19430 Roo.get(_this.iframe.contentDocument.head).createChild({
19432 rel : 'stylesheet',
19441 removeStylesheets : function()
19445 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19450 // hide stuff that is not compatible
19464 * @event specialkey
19468 * @cfg {String} fieldClass @hide
19471 * @cfg {String} focusClass @hide
19474 * @cfg {String} autoCreate @hide
19477 * @cfg {String} inputType @hide
19480 * @cfg {String} invalidClass @hide
19483 * @cfg {String} invalidText @hide
19486 * @cfg {String} msgFx @hide
19489 * @cfg {String} validateOnBlur @hide
19493 Roo.HtmlEditorCore.white = [
19494 'area', 'br', 'img', 'input', 'hr', 'wbr',
19496 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19497 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19498 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19499 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19500 'table', 'ul', 'xmp',
19502 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19505 'dir', 'menu', 'ol', 'ul', 'dl',
19511 Roo.HtmlEditorCore.black = [
19512 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19514 'base', 'basefont', 'bgsound', 'blink', 'body',
19515 'frame', 'frameset', 'head', 'html', 'ilayer',
19516 'iframe', 'layer', 'link', 'meta', 'object',
19517 'script', 'style' ,'title', 'xml' // clean later..
19519 Roo.HtmlEditorCore.clean = [
19520 'script', 'style', 'title', 'xml'
19522 Roo.HtmlEditorCore.remove = [
19527 Roo.HtmlEditorCore.ablack = [
19531 Roo.HtmlEditorCore.aclean = [
19532 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19536 Roo.HtmlEditorCore.pwhite= [
19537 'http', 'https', 'mailto'
19540 // white listed style attributes.
19541 Roo.HtmlEditorCore.cwhite= [
19542 // 'text-align', /// default is to allow most things..
19548 // black listed style attributes.
19549 Roo.HtmlEditorCore.cblack= [
19550 // 'font-size' -- this can be set by the project
19554 Roo.HtmlEditorCore.swapCodes =[
19573 * @class Roo.bootstrap.HtmlEditor
19574 * @extends Roo.bootstrap.TextArea
19575 * Bootstrap HtmlEditor class
19578 * Create a new HtmlEditor
19579 * @param {Object} config The config object
19582 Roo.bootstrap.HtmlEditor = function(config){
19583 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19584 if (!this.toolbars) {
19585 this.toolbars = [];
19587 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19590 * @event initialize
19591 * Fires when the editor is fully initialized (including the iframe)
19592 * @param {HtmlEditor} this
19597 * Fires when the editor is first receives the focus. Any insertion must wait
19598 * until after this event.
19599 * @param {HtmlEditor} this
19603 * @event beforesync
19604 * Fires before the textarea is updated with content from the editor iframe. Return false
19605 * to cancel the sync.
19606 * @param {HtmlEditor} this
19607 * @param {String} html
19611 * @event beforepush
19612 * Fires before the iframe editor is updated with content from the textarea. Return false
19613 * to cancel the push.
19614 * @param {HtmlEditor} this
19615 * @param {String} html
19620 * Fires when the textarea is updated with content from the editor iframe.
19621 * @param {HtmlEditor} this
19622 * @param {String} html
19627 * Fires when the iframe editor is updated with content from the textarea.
19628 * @param {HtmlEditor} this
19629 * @param {String} html
19633 * @event editmodechange
19634 * Fires when the editor switches edit modes
19635 * @param {HtmlEditor} this
19636 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19638 editmodechange: true,
19640 * @event editorevent
19641 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19642 * @param {HtmlEditor} this
19646 * @event firstfocus
19647 * Fires when on first focus - needed by toolbars..
19648 * @param {HtmlEditor} this
19653 * Auto save the htmlEditor value as a file into Events
19654 * @param {HtmlEditor} this
19658 * @event savedpreview
19659 * preview the saved version of htmlEditor
19660 * @param {HtmlEditor} this
19667 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19671 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19676 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19681 * @cfg {Number} height (in pixels)
19685 * @cfg {Number} width (in pixels)
19690 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19693 stylesheets: false,
19698 // private properties
19699 validationEvent : false,
19701 initialized : false,
19704 onFocus : Roo.emptyFn,
19706 hideMode:'offsets',
19709 tbContainer : false,
19711 toolbarContainer :function() {
19712 return this.wrap.select('.x-html-editor-tb',true).first();
19716 * Protected method that will not generally be called directly. It
19717 * is called when the editor creates its toolbar. Override this method if you need to
19718 * add custom toolbar buttons.
19719 * @param {HtmlEditor} editor
19721 createToolbar : function(){
19723 Roo.log("create toolbars");
19725 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19726 this.toolbars[0].render(this.toolbarContainer());
19730 // if (!editor.toolbars || !editor.toolbars.length) {
19731 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19734 // for (var i =0 ; i < editor.toolbars.length;i++) {
19735 // editor.toolbars[i] = Roo.factory(
19736 // typeof(editor.toolbars[i]) == 'string' ?
19737 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19738 // Roo.bootstrap.HtmlEditor);
19739 // editor.toolbars[i].init(editor);
19745 onRender : function(ct, position)
19747 // Roo.log("Call onRender: " + this.xtype);
19749 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19751 this.wrap = this.inputEl().wrap({
19752 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19755 this.editorcore.onRender(ct, position);
19757 if (this.resizable) {
19758 this.resizeEl = new Roo.Resizable(this.wrap, {
19762 minHeight : this.height,
19763 height: this.height,
19764 handles : this.resizable,
19767 resize : function(r, w, h) {
19768 _t.onResize(w,h); // -something
19774 this.createToolbar(this);
19777 if(!this.width && this.resizable){
19778 this.setSize(this.wrap.getSize());
19780 if (this.resizeEl) {
19781 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19782 // should trigger onReize..
19788 onResize : function(w, h)
19790 Roo.log('resize: ' +w + ',' + h );
19791 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19795 if(this.inputEl() ){
19796 if(typeof w == 'number'){
19797 var aw = w - this.wrap.getFrameWidth('lr');
19798 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19801 if(typeof h == 'number'){
19802 var tbh = -11; // fixme it needs to tool bar size!
19803 for (var i =0; i < this.toolbars.length;i++) {
19804 // fixme - ask toolbars for heights?
19805 tbh += this.toolbars[i].el.getHeight();
19806 //if (this.toolbars[i].footer) {
19807 // tbh += this.toolbars[i].footer.el.getHeight();
19815 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19816 ah -= 5; // knock a few pixes off for look..
19817 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19821 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19822 this.editorcore.onResize(ew,eh);
19827 * Toggles the editor between standard and source edit mode.
19828 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19830 toggleSourceEdit : function(sourceEditMode)
19832 this.editorcore.toggleSourceEdit(sourceEditMode);
19834 if(this.editorcore.sourceEditMode){
19835 Roo.log('editor - showing textarea');
19838 // Roo.log(this.syncValue());
19840 this.inputEl().removeClass(['hide', 'x-hidden']);
19841 this.inputEl().dom.removeAttribute('tabIndex');
19842 this.inputEl().focus();
19844 Roo.log('editor - hiding textarea');
19846 // Roo.log(this.pushValue());
19849 this.inputEl().addClass(['hide', 'x-hidden']);
19850 this.inputEl().dom.setAttribute('tabIndex', -1);
19851 //this.deferFocus();
19854 if(this.resizable){
19855 this.setSize(this.wrap.getSize());
19858 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19861 // private (for BoxComponent)
19862 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19864 // private (for BoxComponent)
19865 getResizeEl : function(){
19869 // private (for BoxComponent)
19870 getPositionEl : function(){
19875 initEvents : function(){
19876 this.originalValue = this.getValue();
19880 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19883 // markInvalid : Roo.emptyFn,
19885 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19888 // clearInvalid : Roo.emptyFn,
19890 setValue : function(v){
19891 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19892 this.editorcore.pushValue();
19897 deferFocus : function(){
19898 this.focus.defer(10, this);
19902 focus : function(){
19903 this.editorcore.focus();
19909 onDestroy : function(){
19915 for (var i =0; i < this.toolbars.length;i++) {
19916 // fixme - ask toolbars for heights?
19917 this.toolbars[i].onDestroy();
19920 this.wrap.dom.innerHTML = '';
19921 this.wrap.remove();
19926 onFirstFocus : function(){
19927 //Roo.log("onFirstFocus");
19928 this.editorcore.onFirstFocus();
19929 for (var i =0; i < this.toolbars.length;i++) {
19930 this.toolbars[i].onFirstFocus();
19936 syncValue : function()
19938 this.editorcore.syncValue();
19941 pushValue : function()
19943 this.editorcore.pushValue();
19947 // hide stuff that is not compatible
19961 * @event specialkey
19965 * @cfg {String} fieldClass @hide
19968 * @cfg {String} focusClass @hide
19971 * @cfg {String} autoCreate @hide
19974 * @cfg {String} inputType @hide
19977 * @cfg {String} invalidClass @hide
19980 * @cfg {String} invalidText @hide
19983 * @cfg {String} msgFx @hide
19986 * @cfg {String} validateOnBlur @hide
19995 Roo.namespace('Roo.bootstrap.htmleditor');
19997 * @class Roo.bootstrap.HtmlEditorToolbar1
20002 new Roo.bootstrap.HtmlEditor({
20005 new Roo.bootstrap.HtmlEditorToolbar1({
20006 disable : { fonts: 1 , format: 1, ..., ... , ...],
20012 * @cfg {Object} disable List of elements to disable..
20013 * @cfg {Array} btns List of additional buttons.
20017 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20020 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20023 Roo.apply(this, config);
20025 // default disabled, based on 'good practice'..
20026 this.disable = this.disable || {};
20027 Roo.applyIf(this.disable, {
20030 specialElements : true
20032 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20034 this.editor = config.editor;
20035 this.editorcore = config.editor.editorcore;
20037 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20039 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20040 // dont call parent... till later.
20042 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20047 editorcore : false,
20052 "h1","h2","h3","h4","h5","h6",
20054 "abbr", "acronym", "address", "cite", "samp", "var",
20058 onRender : function(ct, position)
20060 // Roo.log("Call onRender: " + this.xtype);
20062 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20064 this.el.dom.style.marginBottom = '0';
20066 var editorcore = this.editorcore;
20067 var editor= this.editor;
20070 var btn = function(id,cmd , toggle, handler){
20072 var event = toggle ? 'toggle' : 'click';
20077 xns: Roo.bootstrap,
20080 enableToggle:toggle !== false,
20082 pressed : toggle ? false : null,
20085 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20086 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20095 xns: Roo.bootstrap,
20096 glyphicon : 'font',
20100 xns: Roo.bootstrap,
20104 Roo.each(this.formats, function(f) {
20105 style.menu.items.push({
20107 xns: Roo.bootstrap,
20108 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20113 editorcore.insertTag(this.tagname);
20120 children.push(style);
20123 btn('bold',false,true);
20124 btn('italic',false,true);
20125 btn('align-left', 'justifyleft',true);
20126 btn('align-center', 'justifycenter',true);
20127 btn('align-right' , 'justifyright',true);
20128 btn('link', false, false, function(btn) {
20129 //Roo.log("create link?");
20130 var url = prompt(this.createLinkText, this.defaultLinkValue);
20131 if(url && url != 'http:/'+'/'){
20132 this.editorcore.relayCmd('createlink', url);
20135 btn('list','insertunorderedlist',true);
20136 btn('pencil', false,true, function(btn){
20139 this.toggleSourceEdit(btn.pressed);
20145 xns: Roo.bootstrap,
20150 xns: Roo.bootstrap,
20155 cog.menu.items.push({
20157 xns: Roo.bootstrap,
20158 html : Clean styles,
20163 editorcore.insertTag(this.tagname);
20172 this.xtype = 'NavSimplebar';
20174 for(var i=0;i< children.length;i++) {
20176 this.buttons.add(this.addxtypeChild(children[i]));
20180 editor.on('editorevent', this.updateToolbar, this);
20182 onBtnClick : function(id)
20184 this.editorcore.relayCmd(id);
20185 this.editorcore.focus();
20189 * Protected method that will not generally be called directly. It triggers
20190 * a toolbar update by reading the markup state of the current selection in the editor.
20192 updateToolbar: function(){
20194 if(!this.editorcore.activated){
20195 this.editor.onFirstFocus(); // is this neeed?
20199 var btns = this.buttons;
20200 var doc = this.editorcore.doc;
20201 btns.get('bold').setActive(doc.queryCommandState('bold'));
20202 btns.get('italic').setActive(doc.queryCommandState('italic'));
20203 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20205 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20206 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20207 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20209 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20210 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20213 var ans = this.editorcore.getAllAncestors();
20214 if (this.formatCombo) {
20217 var store = this.formatCombo.store;
20218 this.formatCombo.setValue("");
20219 for (var i =0; i < ans.length;i++) {
20220 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20222 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20230 // hides menus... - so this cant be on a menu...
20231 Roo.bootstrap.MenuMgr.hideAll();
20233 Roo.bootstrap.MenuMgr.hideAll();
20234 //this.editorsyncValue();
20236 onFirstFocus: function() {
20237 this.buttons.each(function(item){
20241 toggleSourceEdit : function(sourceEditMode){
20244 if(sourceEditMode){
20245 Roo.log("disabling buttons");
20246 this.buttons.each( function(item){
20247 if(item.cmd != 'pencil'){
20253 Roo.log("enabling buttons");
20254 if(this.editorcore.initialized){
20255 this.buttons.each( function(item){
20261 Roo.log("calling toggole on editor");
20262 // tell the editor that it's been pressed..
20263 this.editor.toggleSourceEdit(sourceEditMode);
20273 * @class Roo.bootstrap.Table.AbstractSelectionModel
20274 * @extends Roo.util.Observable
20275 * Abstract base class for grid SelectionModels. It provides the interface that should be
20276 * implemented by descendant classes. This class should not be directly instantiated.
20279 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20280 this.locked = false;
20281 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20285 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20286 /** @ignore Called by the grid automatically. Do not call directly. */
20287 init : function(grid){
20293 * Locks the selections.
20296 this.locked = true;
20300 * Unlocks the selections.
20302 unlock : function(){
20303 this.locked = false;
20307 * Returns true if the selections are locked.
20308 * @return {Boolean}
20310 isLocked : function(){
20311 return this.locked;
20315 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20316 * @class Roo.bootstrap.Table.RowSelectionModel
20317 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20318 * It supports multiple selections and keyboard selection/navigation.
20320 * @param {Object} config
20323 Roo.bootstrap.Table.RowSelectionModel = function(config){
20324 Roo.apply(this, config);
20325 this.selections = new Roo.util.MixedCollection(false, function(o){
20330 this.lastActive = false;
20334 * @event selectionchange
20335 * Fires when the selection changes
20336 * @param {SelectionModel} this
20338 "selectionchange" : true,
20340 * @event afterselectionchange
20341 * Fires after the selection changes (eg. by key press or clicking)
20342 * @param {SelectionModel} this
20344 "afterselectionchange" : true,
20346 * @event beforerowselect
20347 * Fires when a row is selected being selected, return false to cancel.
20348 * @param {SelectionModel} this
20349 * @param {Number} rowIndex The selected index
20350 * @param {Boolean} keepExisting False if other selections will be cleared
20352 "beforerowselect" : true,
20355 * Fires when a row is selected.
20356 * @param {SelectionModel} this
20357 * @param {Number} rowIndex The selected index
20358 * @param {Roo.data.Record} r The record
20360 "rowselect" : true,
20362 * @event rowdeselect
20363 * Fires when a row is deselected.
20364 * @param {SelectionModel} this
20365 * @param {Number} rowIndex The selected index
20367 "rowdeselect" : true
20369 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20370 this.locked = false;
20373 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20375 * @cfg {Boolean} singleSelect
20376 * True to allow selection of only one row at a time (defaults to false)
20378 singleSelect : false,
20381 initEvents : function(){
20383 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20384 this.grid.on("mousedown", this.handleMouseDown, this);
20385 }else{ // allow click to work like normal
20386 this.grid.on("rowclick", this.handleDragableRowClick, this);
20389 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20390 "up" : function(e){
20392 this.selectPrevious(e.shiftKey);
20393 }else if(this.last !== false && this.lastActive !== false){
20394 var last = this.last;
20395 this.selectRange(this.last, this.lastActive-1);
20396 this.grid.getView().focusRow(this.lastActive);
20397 if(last !== false){
20401 this.selectFirstRow();
20403 this.fireEvent("afterselectionchange", this);
20405 "down" : function(e){
20407 this.selectNext(e.shiftKey);
20408 }else if(this.last !== false && this.lastActive !== false){
20409 var last = this.last;
20410 this.selectRange(this.last, this.lastActive+1);
20411 this.grid.getView().focusRow(this.lastActive);
20412 if(last !== false){
20416 this.selectFirstRow();
20418 this.fireEvent("afterselectionchange", this);
20423 var view = this.grid.view;
20424 view.on("refresh", this.onRefresh, this);
20425 view.on("rowupdated", this.onRowUpdated, this);
20426 view.on("rowremoved", this.onRemove, this);
20430 onRefresh : function(){
20431 var ds = this.grid.dataSource, i, v = this.grid.view;
20432 var s = this.selections;
20433 s.each(function(r){
20434 if((i = ds.indexOfId(r.id)) != -1){
20443 onRemove : function(v, index, r){
20444 this.selections.remove(r);
20448 onRowUpdated : function(v, index, r){
20449 if(this.isSelected(r)){
20450 v.onRowSelect(index);
20456 * @param {Array} records The records to select
20457 * @param {Boolean} keepExisting (optional) True to keep existing selections
20459 selectRecords : function(records, keepExisting){
20461 this.clearSelections();
20463 var ds = this.grid.dataSource;
20464 for(var i = 0, len = records.length; i < len; i++){
20465 this.selectRow(ds.indexOf(records[i]), true);
20470 * Gets the number of selected rows.
20473 getCount : function(){
20474 return this.selections.length;
20478 * Selects the first row in the grid.
20480 selectFirstRow : function(){
20485 * Select the last row.
20486 * @param {Boolean} keepExisting (optional) True to keep existing selections
20488 selectLastRow : function(keepExisting){
20489 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20493 * Selects the row immediately following the last selected row.
20494 * @param {Boolean} keepExisting (optional) True to keep existing selections
20496 selectNext : function(keepExisting){
20497 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20498 this.selectRow(this.last+1, keepExisting);
20499 this.grid.getView().focusRow(this.last);
20504 * Selects the row that precedes the last selected row.
20505 * @param {Boolean} keepExisting (optional) True to keep existing selections
20507 selectPrevious : function(keepExisting){
20509 this.selectRow(this.last-1, keepExisting);
20510 this.grid.getView().focusRow(this.last);
20515 * Returns the selected records
20516 * @return {Array} Array of selected records
20518 getSelections : function(){
20519 return [].concat(this.selections.items);
20523 * Returns the first selected record.
20526 getSelected : function(){
20527 return this.selections.itemAt(0);
20532 * Clears all selections.
20534 clearSelections : function(fast){
20535 if(this.locked) return;
20537 var ds = this.grid.dataSource;
20538 var s = this.selections;
20539 s.each(function(r){
20540 this.deselectRow(ds.indexOfId(r.id));
20544 this.selections.clear();
20551 * Selects all rows.
20553 selectAll : function(){
20554 if(this.locked) return;
20555 this.selections.clear();
20556 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20557 this.selectRow(i, true);
20562 * Returns True if there is a selection.
20563 * @return {Boolean}
20565 hasSelection : function(){
20566 return this.selections.length > 0;
20570 * Returns True if the specified row is selected.
20571 * @param {Number/Record} record The record or index of the record to check
20572 * @return {Boolean}
20574 isSelected : function(index){
20575 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20576 return (r && this.selections.key(r.id) ? true : false);
20580 * Returns True if the specified record id is selected.
20581 * @param {String} id The id of record to check
20582 * @return {Boolean}
20584 isIdSelected : function(id){
20585 return (this.selections.key(id) ? true : false);
20589 handleMouseDown : function(e, t){
20590 var view = this.grid.getView(), rowIndex;
20591 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20594 if(e.shiftKey && this.last !== false){
20595 var last = this.last;
20596 this.selectRange(last, rowIndex, e.ctrlKey);
20597 this.last = last; // reset the last
20598 view.focusRow(rowIndex);
20600 var isSelected = this.isSelected(rowIndex);
20601 if(e.button !== 0 && isSelected){
20602 view.focusRow(rowIndex);
20603 }else if(e.ctrlKey && isSelected){
20604 this.deselectRow(rowIndex);
20605 }else if(!isSelected){
20606 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20607 view.focusRow(rowIndex);
20610 this.fireEvent("afterselectionchange", this);
20613 handleDragableRowClick : function(grid, rowIndex, e)
20615 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20616 this.selectRow(rowIndex, false);
20617 grid.view.focusRow(rowIndex);
20618 this.fireEvent("afterselectionchange", this);
20623 * Selects multiple rows.
20624 * @param {Array} rows Array of the indexes of the row to select
20625 * @param {Boolean} keepExisting (optional) True to keep existing selections
20627 selectRows : function(rows, keepExisting){
20629 this.clearSelections();
20631 for(var i = 0, len = rows.length; i < len; i++){
20632 this.selectRow(rows[i], true);
20637 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20638 * @param {Number} startRow The index of the first row in the range
20639 * @param {Number} endRow The index of the last row in the range
20640 * @param {Boolean} keepExisting (optional) True to retain existing selections
20642 selectRange : function(startRow, endRow, keepExisting){
20643 if(this.locked) return;
20645 this.clearSelections();
20647 if(startRow <= endRow){
20648 for(var i = startRow; i <= endRow; i++){
20649 this.selectRow(i, true);
20652 for(var i = startRow; i >= endRow; i--){
20653 this.selectRow(i, true);
20659 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20660 * @param {Number} startRow The index of the first row in the range
20661 * @param {Number} endRow The index of the last row in the range
20663 deselectRange : function(startRow, endRow, preventViewNotify){
20664 if(this.locked) return;
20665 for(var i = startRow; i <= endRow; i++){
20666 this.deselectRow(i, preventViewNotify);
20672 * @param {Number} row The index of the row to select
20673 * @param {Boolean} keepExisting (optional) True to keep existing selections
20675 selectRow : function(index, keepExisting, preventViewNotify){
20676 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20677 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20678 if(!keepExisting || this.singleSelect){
20679 this.clearSelections();
20681 var r = this.grid.dataSource.getAt(index);
20682 this.selections.add(r);
20683 this.last = this.lastActive = index;
20684 if(!preventViewNotify){
20685 this.grid.getView().onRowSelect(index);
20687 this.fireEvent("rowselect", this, index, r);
20688 this.fireEvent("selectionchange", this);
20694 * @param {Number} row The index of the row to deselect
20696 deselectRow : function(index, preventViewNotify){
20697 if(this.locked) return;
20698 if(this.last == index){
20701 if(this.lastActive == index){
20702 this.lastActive = false;
20704 var r = this.grid.dataSource.getAt(index);
20705 this.selections.remove(r);
20706 if(!preventViewNotify){
20707 this.grid.getView().onRowDeselect(index);
20709 this.fireEvent("rowdeselect", this, index);
20710 this.fireEvent("selectionchange", this);
20714 restoreLast : function(){
20716 this.last = this._last;
20721 acceptsNav : function(row, col, cm){
20722 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20726 onEditorKey : function(field, e){
20727 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20732 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20734 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20736 }else if(k == e.ENTER && !e.ctrlKey){
20740 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20742 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20744 }else if(k == e.ESC){
20748 g.startEditing(newCell[0], newCell[1]);
20753 * Ext JS Library 1.1.1
20754 * Copyright(c) 2006-2007, Ext JS, LLC.
20756 * Originally Released Under LGPL - original licence link has changed is not relivant.
20759 * <script type="text/javascript">
20763 * @class Roo.bootstrap.PagingToolbar
20765 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20767 * Create a new PagingToolbar
20768 * @param {Object} config The config object
20770 Roo.bootstrap.PagingToolbar = function(config)
20772 // old args format still supported... - xtype is prefered..
20773 // created from xtype...
20774 var ds = config.dataSource;
20775 this.toolbarItems = [];
20776 if (config.items) {
20777 this.toolbarItems = config.items;
20778 // config.items = [];
20781 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20788 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20792 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20794 * @cfg {Roo.data.Store} dataSource
20795 * The underlying data store providing the paged data
20798 * @cfg {String/HTMLElement/Element} container
20799 * container The id or element that will contain the toolbar
20802 * @cfg {Boolean} displayInfo
20803 * True to display the displayMsg (defaults to false)
20806 * @cfg {Number} pageSize
20807 * The number of records to display per page (defaults to 20)
20811 * @cfg {String} displayMsg
20812 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20814 displayMsg : 'Displaying {0} - {1} of {2}',
20816 * @cfg {String} emptyMsg
20817 * The message to display when no records are found (defaults to "No data to display")
20819 emptyMsg : 'No data to display',
20821 * Customizable piece of the default paging text (defaults to "Page")
20824 beforePageText : "Page",
20826 * Customizable piece of the default paging text (defaults to "of %0")
20829 afterPageText : "of {0}",
20831 * Customizable piece of the default paging text (defaults to "First Page")
20834 firstText : "First Page",
20836 * Customizable piece of the default paging text (defaults to "Previous Page")
20839 prevText : "Previous Page",
20841 * Customizable piece of the default paging text (defaults to "Next Page")
20844 nextText : "Next Page",
20846 * Customizable piece of the default paging text (defaults to "Last Page")
20849 lastText : "Last Page",
20851 * Customizable piece of the default paging text (defaults to "Refresh")
20854 refreshText : "Refresh",
20858 onRender : function(ct, position)
20860 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20861 this.navgroup.parentId = this.id;
20862 this.navgroup.onRender(this.el, null);
20863 // add the buttons to the navgroup
20865 if(this.displayInfo){
20866 Roo.log(this.el.select('ul.navbar-nav',true).first());
20867 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20868 this.displayEl = this.el.select('.x-paging-info', true).first();
20869 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20870 // this.displayEl = navel.el.select('span',true).first();
20876 Roo.each(_this.buttons, function(e){
20877 Roo.factory(e).onRender(_this.el, null);
20881 Roo.each(_this.toolbarItems, function(e) {
20882 _this.navgroup.addItem(e);
20886 this.first = this.navgroup.addItem({
20887 tooltip: this.firstText,
20889 icon : 'fa fa-backward',
20891 preventDefault: true,
20892 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20895 this.prev = this.navgroup.addItem({
20896 tooltip: this.prevText,
20898 icon : 'fa fa-step-backward',
20900 preventDefault: true,
20901 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20903 //this.addSeparator();
20906 var field = this.navgroup.addItem( {
20908 cls : 'x-paging-position',
20910 html : this.beforePageText +
20911 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20912 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20915 this.field = field.el.select('input', true).first();
20916 this.field.on("keydown", this.onPagingKeydown, this);
20917 this.field.on("focus", function(){this.dom.select();});
20920 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20921 //this.field.setHeight(18);
20922 //this.addSeparator();
20923 this.next = this.navgroup.addItem({
20924 tooltip: this.nextText,
20926 html : ' <i class="fa fa-step-forward">',
20928 preventDefault: true,
20929 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20931 this.last = this.navgroup.addItem({
20932 tooltip: this.lastText,
20933 icon : 'fa fa-forward',
20936 preventDefault: true,
20937 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20939 //this.addSeparator();
20940 this.loading = this.navgroup.addItem({
20941 tooltip: this.refreshText,
20942 icon: 'fa fa-refresh',
20943 preventDefault: true,
20944 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20950 updateInfo : function(){
20951 if(this.displayEl){
20952 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20953 var msg = count == 0 ?
20957 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20959 this.displayEl.update(msg);
20964 onLoad : function(ds, r, o){
20965 this.cursor = o.params ? o.params.start : 0;
20966 var d = this.getPageData(),
20970 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20971 this.field.dom.value = ap;
20972 this.first.setDisabled(ap == 1);
20973 this.prev.setDisabled(ap == 1);
20974 this.next.setDisabled(ap == ps);
20975 this.last.setDisabled(ap == ps);
20976 this.loading.enable();
20981 getPageData : function(){
20982 var total = this.ds.getTotalCount();
20985 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20986 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20991 onLoadError : function(){
20992 this.loading.enable();
20996 onPagingKeydown : function(e){
20997 var k = e.getKey();
20998 var d = this.getPageData();
21000 var v = this.field.dom.value, pageNum;
21001 if(!v || isNaN(pageNum = parseInt(v, 10))){
21002 this.field.dom.value = d.activePage;
21005 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21006 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21009 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))
21011 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21012 this.field.dom.value = pageNum;
21013 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21016 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21018 var v = this.field.dom.value, pageNum;
21019 var increment = (e.shiftKey) ? 10 : 1;
21020 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21022 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21023 this.field.dom.value = d.activePage;
21026 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21028 this.field.dom.value = parseInt(v, 10) + increment;
21029 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21030 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21037 beforeLoad : function(){
21039 this.loading.disable();
21044 onClick : function(which){
21053 ds.load({params:{start: 0, limit: this.pageSize}});
21056 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21059 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21062 var total = ds.getTotalCount();
21063 var extra = total % this.pageSize;
21064 var lastStart = extra ? (total - extra) : total-this.pageSize;
21065 ds.load({params:{start: lastStart, limit: this.pageSize}});
21068 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21074 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21075 * @param {Roo.data.Store} store The data store to unbind
21077 unbind : function(ds){
21078 ds.un("beforeload", this.beforeLoad, this);
21079 ds.un("load", this.onLoad, this);
21080 ds.un("loadexception", this.onLoadError, this);
21081 ds.un("remove", this.updateInfo, this);
21082 ds.un("add", this.updateInfo, this);
21083 this.ds = undefined;
21087 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21088 * @param {Roo.data.Store} store The data store to bind
21090 bind : function(ds){
21091 ds.on("beforeload", this.beforeLoad, this);
21092 ds.on("load", this.onLoad, this);
21093 ds.on("loadexception", this.onLoadError, this);
21094 ds.on("remove", this.updateInfo, this);
21095 ds.on("add", this.updateInfo, this);
21106 * @class Roo.bootstrap.MessageBar
21107 * @extends Roo.bootstrap.Component
21108 * Bootstrap MessageBar class
21109 * @cfg {String} html contents of the MessageBar
21110 * @cfg {String} weight (info | success | warning | danger) default info
21111 * @cfg {String} beforeClass insert the bar before the given class
21112 * @cfg {Boolean} closable (true | false) default false
21113 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21116 * Create a new Element
21117 * @param {Object} config The config object
21120 Roo.bootstrap.MessageBar = function(config){
21121 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21124 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21130 beforeClass: 'bootstrap-sticky-wrap',
21132 getAutoCreate : function(){
21136 cls: 'alert alert-dismissable alert-' + this.weight,
21141 html: this.html || ''
21147 cfg.cls += ' alert-messages-fixed';
21161 onRender : function(ct, position)
21163 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21166 var cfg = Roo.apply({}, this.getAutoCreate());
21170 cfg.cls += ' ' + this.cls;
21173 cfg.style = this.style;
21175 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21177 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21180 this.el.select('>button.close').on('click', this.hide, this);
21186 if (!this.rendered) {
21192 this.fireEvent('show', this);
21198 if (!this.rendered) {
21204 this.fireEvent('hide', this);
21207 update : function()
21209 // var e = this.el.dom.firstChild;
21211 // if(this.closable){
21212 // e = e.nextSibling;
21215 // e.data = this.html || '';
21217 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21233 * @class Roo.bootstrap.Graph
21234 * @extends Roo.bootstrap.Component
21235 * Bootstrap Graph class
21239 @cfg {String} graphtype bar | vbar | pie
21240 @cfg {number} g_x coodinator | centre x (pie)
21241 @cfg {number} g_y coodinator | centre y (pie)
21242 @cfg {number} g_r radius (pie)
21243 @cfg {number} g_height height of the chart (respected by all elements in the set)
21244 @cfg {number} g_width width of the chart (respected by all elements in the set)
21245 @cfg {Object} title The title of the chart
21248 -opts (object) options for the chart
21250 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21251 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21253 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.
21254 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21256 o stretch (boolean)
21258 -opts (object) options for the pie
21261 o startAngle (number)
21262 o endAngle (number)
21266 * Create a new Input
21267 * @param {Object} config The config object
21270 Roo.bootstrap.Graph = function(config){
21271 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21277 * The img click event for the img.
21278 * @param {Roo.EventObject} e
21284 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21295 //g_colors: this.colors,
21302 getAutoCreate : function(){
21313 onRender : function(ct,position){
21314 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21315 this.raphael = Raphael(this.el.dom);
21317 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21318 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21319 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21320 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21322 r.text(160, 10, "Single Series Chart").attr(txtattr);
21323 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21324 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21325 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21327 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21328 r.barchart(330, 10, 300, 220, data1);
21329 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21330 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21333 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21334 // r.barchart(30, 30, 560, 250, xdata, {
21335 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21336 // axis : "0 0 1 1",
21337 // axisxlabels : xdata
21338 // //yvalues : cols,
21341 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21343 // this.load(null,xdata,{
21344 // axis : "0 0 1 1",
21345 // axisxlabels : xdata
21350 load : function(graphtype,xdata,opts){
21351 this.raphael.clear();
21353 graphtype = this.graphtype;
21358 var r = this.raphael,
21359 fin = function () {
21360 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21362 fout = function () {
21363 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21365 pfin = function() {
21366 this.sector.stop();
21367 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21370 this.label[0].stop();
21371 this.label[0].attr({ r: 7.5 });
21372 this.label[1].attr({ "font-weight": 800 });
21375 pfout = function() {
21376 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21379 this.label[0].animate({ r: 5 }, 500, "bounce");
21380 this.label[1].attr({ "font-weight": 400 });
21386 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21389 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21392 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21393 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21395 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21402 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21407 setTitle: function(o)
21412 initEvents: function() {
21415 this.el.on('click', this.onClick, this);
21419 onClick : function(e)
21421 Roo.log('img onclick');
21422 this.fireEvent('click', this, e);
21434 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21437 * @class Roo.bootstrap.dash.NumberBox
21438 * @extends Roo.bootstrap.Component
21439 * Bootstrap NumberBox class
21440 * @cfg {String} headline Box headline
21441 * @cfg {String} content Box content
21442 * @cfg {String} icon Box icon
21443 * @cfg {String} footer Footer text
21444 * @cfg {String} fhref Footer href
21447 * Create a new NumberBox
21448 * @param {Object} config The config object
21452 Roo.bootstrap.dash.NumberBox = function(config){
21453 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21457 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21466 getAutoCreate : function(){
21470 cls : 'small-box ',
21478 cls : 'roo-headline',
21479 html : this.headline
21483 cls : 'roo-content',
21484 html : this.content
21498 cls : 'ion ' + this.icon
21507 cls : 'small-box-footer',
21508 href : this.fhref || '#',
21512 cfg.cn.push(footer);
21519 onRender : function(ct,position){
21520 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21527 setHeadline: function (value)
21529 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21532 setFooter: function (value, href)
21534 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21537 this.el.select('a.small-box-footer',true).first().attr('href', href);
21542 setContent: function (value)
21544 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21547 initEvents: function()
21561 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21564 * @class Roo.bootstrap.dash.TabBox
21565 * @extends Roo.bootstrap.Component
21566 * Bootstrap TabBox class
21567 * @cfg {String} title Title of the TabBox
21568 * @cfg {String} icon Icon of the TabBox
21569 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21570 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21573 * Create a new TabBox
21574 * @param {Object} config The config object
21578 Roo.bootstrap.dash.TabBox = function(config){
21579 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21584 * When a pane is added
21585 * @param {Roo.bootstrap.dash.TabPane} pane
21589 * @event activatepane
21590 * When a pane is activated
21591 * @param {Roo.bootstrap.dash.TabPane} pane
21593 "activatepane" : true
21601 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21606 tabScrollable : false,
21608 getChildContainer : function()
21610 return this.el.select('.tab-content', true).first();
21613 getAutoCreate : function(){
21617 cls: 'pull-left header',
21625 cls: 'fa ' + this.icon
21631 cls: 'nav nav-tabs pull-right',
21637 if(this.tabScrollable){
21644 cls: 'nav nav-tabs pull-right',
21655 cls: 'nav-tabs-custom',
21660 cls: 'tab-content no-padding',
21668 initEvents : function()
21670 //Roo.log('add add pane handler');
21671 this.on('addpane', this.onAddPane, this);
21674 * Updates the box title
21675 * @param {String} html to set the title to.
21677 setTitle : function(value)
21679 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21681 onAddPane : function(pane)
21683 this.panes.push(pane);
21684 //Roo.log('addpane');
21686 // tabs are rendere left to right..
21687 if(!this.showtabs){
21691 var ctr = this.el.select('.nav-tabs', true).first();
21694 var existing = ctr.select('.nav-tab',true);
21695 var qty = existing.getCount();;
21698 var tab = ctr.createChild({
21700 cls : 'nav-tab' + (qty ? '' : ' active'),
21708 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21711 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21713 pane.el.addClass('active');
21718 onTabClick : function(ev,un,ob,pane)
21720 //Roo.log('tab - prev default');
21721 ev.preventDefault();
21724 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21725 pane.tab.addClass('active');
21726 //Roo.log(pane.title);
21727 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21728 // technically we should have a deactivate event.. but maybe add later.
21729 // and it should not de-activate the selected tab...
21730 this.fireEvent('activatepane', pane);
21731 pane.el.addClass('active');
21732 pane.fireEvent('activate');
21737 getActivePane : function()
21740 Roo.each(this.panes, function(p) {
21741 if(p.el.hasClass('active')){
21762 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21764 * @class Roo.bootstrap.TabPane
21765 * @extends Roo.bootstrap.Component
21766 * Bootstrap TabPane class
21767 * @cfg {Boolean} active (false | true) Default false
21768 * @cfg {String} title title of panel
21772 * Create a new TabPane
21773 * @param {Object} config The config object
21776 Roo.bootstrap.dash.TabPane = function(config){
21777 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21783 * When a pane is activated
21784 * @param {Roo.bootstrap.dash.TabPane} pane
21791 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21796 // the tabBox that this is attached to.
21799 getAutoCreate : function()
21807 cfg.cls += ' active';
21812 initEvents : function()
21814 //Roo.log('trigger add pane handler');
21815 this.parent().fireEvent('addpane', this)
21819 * Updates the tab title
21820 * @param {String} html to set the title to.
21822 setTitle: function(str)
21828 this.tab.select('a', true).first().dom.innerHTML = str;
21845 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21848 * @class Roo.bootstrap.menu.Menu
21849 * @extends Roo.bootstrap.Component
21850 * Bootstrap Menu class - container for Menu
21851 * @cfg {String} html Text of the menu
21852 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21853 * @cfg {String} icon Font awesome icon
21854 * @cfg {String} pos Menu align to (top | bottom) default bottom
21858 * Create a new Menu
21859 * @param {Object} config The config object
21863 Roo.bootstrap.menu.Menu = function(config){
21864 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21868 * @event beforeshow
21869 * Fires before this menu is displayed
21870 * @param {Roo.bootstrap.menu.Menu} this
21874 * @event beforehide
21875 * Fires before this menu is hidden
21876 * @param {Roo.bootstrap.menu.Menu} this
21881 * Fires after this menu is displayed
21882 * @param {Roo.bootstrap.menu.Menu} this
21887 * Fires after this menu is hidden
21888 * @param {Roo.bootstrap.menu.Menu} this
21893 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21894 * @param {Roo.bootstrap.menu.Menu} this
21895 * @param {Roo.EventObject} e
21902 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21906 weight : 'default',
21911 getChildContainer : function() {
21912 if(this.isSubMenu){
21916 return this.el.select('ul.dropdown-menu', true).first();
21919 getAutoCreate : function()
21924 cls : 'roo-menu-text',
21932 cls : 'fa ' + this.icon
21943 cls : 'dropdown-button btn btn-' + this.weight,
21948 cls : 'dropdown-toggle btn btn-' + this.weight,
21958 cls : 'dropdown-menu'
21964 if(this.pos == 'top'){
21965 cfg.cls += ' dropup';
21968 if(this.isSubMenu){
21971 cls : 'dropdown-menu'
21978 onRender : function(ct, position)
21980 this.isSubMenu = ct.hasClass('dropdown-submenu');
21982 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21985 initEvents : function()
21987 if(this.isSubMenu){
21991 this.hidden = true;
21993 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21994 this.triggerEl.on('click', this.onTriggerPress, this);
21996 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21997 this.buttonEl.on('click', this.onClick, this);
22003 if(this.isSubMenu){
22007 return this.el.select('ul.dropdown-menu', true).first();
22010 onClick : function(e)
22012 this.fireEvent("click", this, e);
22015 onTriggerPress : function(e)
22017 if (this.isVisible()) {
22024 isVisible : function(){
22025 return !this.hidden;
22030 this.fireEvent("beforeshow", this);
22032 this.hidden = false;
22033 this.el.addClass('open');
22035 Roo.get(document).on("mouseup", this.onMouseUp, this);
22037 this.fireEvent("show", this);
22044 this.fireEvent("beforehide", this);
22046 this.hidden = true;
22047 this.el.removeClass('open');
22049 Roo.get(document).un("mouseup", this.onMouseUp);
22051 this.fireEvent("hide", this);
22054 onMouseUp : function()
22068 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22071 * @class Roo.bootstrap.menu.Item
22072 * @extends Roo.bootstrap.Component
22073 * Bootstrap MenuItem class
22074 * @cfg {Boolean} submenu (true | false) default false
22075 * @cfg {String} html text of the item
22076 * @cfg {String} href the link
22077 * @cfg {Boolean} disable (true | false) default false
22078 * @cfg {Boolean} preventDefault (true | false) default true
22079 * @cfg {String} icon Font awesome icon
22080 * @cfg {String} pos Submenu align to (left | right) default right
22084 * Create a new Item
22085 * @param {Object} config The config object
22089 Roo.bootstrap.menu.Item = function(config){
22090 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22094 * Fires when the mouse is hovering over this menu
22095 * @param {Roo.bootstrap.menu.Item} this
22096 * @param {Roo.EventObject} e
22101 * Fires when the mouse exits this menu
22102 * @param {Roo.bootstrap.menu.Item} this
22103 * @param {Roo.EventObject} e
22109 * The raw click event for the entire grid.
22110 * @param {Roo.EventObject} e
22116 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22121 preventDefault: true,
22126 getAutoCreate : function()
22131 cls : 'roo-menu-item-text',
22139 cls : 'fa ' + this.icon
22148 href : this.href || '#',
22155 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22159 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22161 if(this.pos == 'left'){
22162 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22169 initEvents : function()
22171 this.el.on('mouseover', this.onMouseOver, this);
22172 this.el.on('mouseout', this.onMouseOut, this);
22174 this.el.select('a', true).first().on('click', this.onClick, this);
22178 onClick : function(e)
22180 if(this.preventDefault){
22181 e.preventDefault();
22184 this.fireEvent("click", this, e);
22187 onMouseOver : function(e)
22189 if(this.submenu && this.pos == 'left'){
22190 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22193 this.fireEvent("mouseover", this, e);
22196 onMouseOut : function(e)
22198 this.fireEvent("mouseout", this, e);
22210 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22213 * @class Roo.bootstrap.menu.Separator
22214 * @extends Roo.bootstrap.Component
22215 * Bootstrap Separator class
22218 * Create a new Separator
22219 * @param {Object} config The config object
22223 Roo.bootstrap.menu.Separator = function(config){
22224 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22227 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22229 getAutoCreate : function(){
22250 * @class Roo.bootstrap.Tooltip
22251 * Bootstrap Tooltip class
22252 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22253 * to determine which dom element triggers the tooltip.
22255 * It needs to add support for additional attributes like tooltip-position
22258 * Create a new Toolti
22259 * @param {Object} config The config object
22262 Roo.bootstrap.Tooltip = function(config){
22263 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22266 Roo.apply(Roo.bootstrap.Tooltip, {
22268 * @function init initialize tooltip monitoring.
22272 currentTip : false,
22273 currentRegion : false,
22279 Roo.get(document).on('mouseover', this.enter ,this);
22280 Roo.get(document).on('mouseout', this.leave, this);
22283 this.currentTip = new Roo.bootstrap.Tooltip();
22286 enter : function(ev)
22288 var dom = ev.getTarget();
22290 //Roo.log(['enter',dom]);
22291 var el = Roo.fly(dom);
22292 if (this.currentEl) {
22294 //Roo.log(this.currentEl);
22295 //Roo.log(this.currentEl.contains(dom));
22296 if (this.currentEl == el) {
22299 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22307 if (this.currentTip.el) {
22308 this.currentTip.el.hide(); // force hiding...
22313 // you can not look for children, as if el is the body.. then everythign is the child..
22314 if (!el.attr('tooltip')) { //
22315 if (!el.select("[tooltip]").elements.length) {
22318 // is the mouse over this child...?
22319 bindEl = el.select("[tooltip]").first();
22320 var xy = ev.getXY();
22321 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22322 //Roo.log("not in region.");
22325 //Roo.log("child element over..");
22328 this.currentEl = bindEl;
22329 this.currentTip.bind(bindEl);
22330 this.currentRegion = Roo.lib.Region.getRegion(dom);
22331 this.currentTip.enter();
22334 leave : function(ev)
22336 var dom = ev.getTarget();
22337 //Roo.log(['leave',dom]);
22338 if (!this.currentEl) {
22343 if (dom != this.currentEl.dom) {
22346 var xy = ev.getXY();
22347 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22350 // only activate leave if mouse cursor is outside... bounding box..
22355 if (this.currentTip) {
22356 this.currentTip.leave();
22358 //Roo.log('clear currentEl');
22359 this.currentEl = false;
22364 'left' : ['r-l', [-2,0], 'right'],
22365 'right' : ['l-r', [2,0], 'left'],
22366 'bottom' : ['t-b', [0,2], 'top'],
22367 'top' : [ 'b-t', [0,-2], 'bottom']
22373 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22378 delay : null, // can be { show : 300 , hide: 500}
22382 hoverState : null, //???
22384 placement : 'bottom',
22386 getAutoCreate : function(){
22393 cls : 'tooltip-arrow'
22396 cls : 'tooltip-inner'
22403 bind : function(el)
22409 enter : function () {
22411 if (this.timeout != null) {
22412 clearTimeout(this.timeout);
22415 this.hoverState = 'in';
22416 //Roo.log("enter - show");
22417 if (!this.delay || !this.delay.show) {
22422 this.timeout = setTimeout(function () {
22423 if (_t.hoverState == 'in') {
22426 }, this.delay.show);
22430 clearTimeout(this.timeout);
22432 this.hoverState = 'out';
22433 if (!this.delay || !this.delay.hide) {
22439 this.timeout = setTimeout(function () {
22440 //Roo.log("leave - timeout");
22442 if (_t.hoverState == 'out') {
22444 Roo.bootstrap.Tooltip.currentEl = false;
22452 this.render(document.body);
22455 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22457 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22459 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22461 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22463 var placement = typeof this.placement == 'function' ?
22464 this.placement.call(this, this.el, on_el) :
22467 var autoToken = /\s?auto?\s?/i;
22468 var autoPlace = autoToken.test(placement);
22470 placement = placement.replace(autoToken, '') || 'top';
22474 //this.el.setXY([0,0]);
22476 //this.el.dom.style.display='block';
22477 this.el.addClass(placement);
22479 //this.el.appendTo(on_el);
22481 var p = this.getPosition();
22482 var box = this.el.getBox();
22487 var align = Roo.bootstrap.Tooltip.alignment[placement];
22488 this.el.alignTo(this.bindEl, align[0],align[1]);
22489 //var arrow = this.el.select('.arrow',true).first();
22490 //arrow.set(align[2],
22492 this.el.addClass('in fade');
22493 this.hoverState = null;
22495 if (this.el.hasClass('fade')) {
22506 //this.el.setXY([0,0]);
22507 this.el.removeClass('in');
22523 * @class Roo.bootstrap.LocationPicker
22524 * @extends Roo.bootstrap.Component
22525 * Bootstrap LocationPicker class
22526 * @cfg {Number} latitude Position when init default 0
22527 * @cfg {Number} longitude Position when init default 0
22528 * @cfg {Number} zoom default 15
22529 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22530 * @cfg {Boolean} mapTypeControl default false
22531 * @cfg {Boolean} disableDoubleClickZoom default false
22532 * @cfg {Boolean} scrollwheel default true
22533 * @cfg {Boolean} streetViewControl default false
22534 * @cfg {Number} radius default 0
22535 * @cfg {String} locationName
22536 * @cfg {Boolean} draggable default true
22537 * @cfg {Boolean} enableAutocomplete default false
22538 * @cfg {Boolean} enableReverseGeocode default true
22539 * @cfg {String} markerTitle
22542 * Create a new LocationPicker
22543 * @param {Object} config The config object
22547 Roo.bootstrap.LocationPicker = function(config){
22549 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22554 * Fires when the picker initialized.
22555 * @param {Roo.bootstrap.LocationPicker} this
22556 * @param {Google Location} location
22560 * @event positionchanged
22561 * Fires when the picker position changed.
22562 * @param {Roo.bootstrap.LocationPicker} this
22563 * @param {Google Location} location
22565 positionchanged : true,
22568 * Fires when the map resize.
22569 * @param {Roo.bootstrap.LocationPicker} this
22574 * Fires when the map show.
22575 * @param {Roo.bootstrap.LocationPicker} this
22580 * Fires when the map hide.
22581 * @param {Roo.bootstrap.LocationPicker} this
22586 * Fires when click the map.
22587 * @param {Roo.bootstrap.LocationPicker} this
22588 * @param {Map event} e
22592 * @event mapRightClick
22593 * Fires when right click the map.
22594 * @param {Roo.bootstrap.LocationPicker} this
22595 * @param {Map event} e
22597 mapRightClick : true,
22599 * @event markerClick
22600 * Fires when click the marker.
22601 * @param {Roo.bootstrap.LocationPicker} this
22602 * @param {Map event} e
22604 markerClick : true,
22606 * @event markerRightClick
22607 * Fires when right click the marker.
22608 * @param {Roo.bootstrap.LocationPicker} this
22609 * @param {Map event} e
22611 markerRightClick : true,
22613 * @event OverlayViewDraw
22614 * Fires when OverlayView Draw
22615 * @param {Roo.bootstrap.LocationPicker} this
22617 OverlayViewDraw : true,
22619 * @event OverlayViewOnAdd
22620 * Fires when OverlayView Draw
22621 * @param {Roo.bootstrap.LocationPicker} this
22623 OverlayViewOnAdd : true,
22625 * @event OverlayViewOnRemove
22626 * Fires when OverlayView Draw
22627 * @param {Roo.bootstrap.LocationPicker} this
22629 OverlayViewOnRemove : true,
22631 * @event OverlayViewShow
22632 * Fires when OverlayView Draw
22633 * @param {Roo.bootstrap.LocationPicker} this
22634 * @param {Pixel} cpx
22636 OverlayViewShow : true,
22638 * @event OverlayViewHide
22639 * Fires when OverlayView Draw
22640 * @param {Roo.bootstrap.LocationPicker} this
22642 OverlayViewHide : true
22647 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22649 gMapContext: false,
22655 mapTypeControl: false,
22656 disableDoubleClickZoom: false,
22658 streetViewControl: false,
22662 enableAutocomplete: false,
22663 enableReverseGeocode: true,
22666 getAutoCreate: function()
22671 cls: 'roo-location-picker'
22677 initEvents: function(ct, position)
22679 if(!this.el.getWidth() || this.isApplied()){
22683 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22688 initial: function()
22690 if(!this.mapTypeId){
22691 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22694 this.gMapContext = this.GMapContext();
22696 this.initOverlayView();
22698 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22702 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22703 _this.setPosition(_this.gMapContext.marker.position);
22706 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22707 _this.fireEvent('mapClick', this, event);
22711 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22712 _this.fireEvent('mapRightClick', this, event);
22716 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22717 _this.fireEvent('markerClick', this, event);
22721 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22722 _this.fireEvent('markerRightClick', this, event);
22726 this.setPosition(this.gMapContext.location);
22728 this.fireEvent('initial', this, this.gMapContext.location);
22731 initOverlayView: function()
22735 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22739 _this.fireEvent('OverlayViewDraw', _this);
22744 _this.fireEvent('OverlayViewOnAdd', _this);
22747 onRemove: function()
22749 _this.fireEvent('OverlayViewOnRemove', _this);
22752 show: function(cpx)
22754 _this.fireEvent('OverlayViewShow', _this, cpx);
22759 _this.fireEvent('OverlayViewHide', _this);
22765 fromLatLngToContainerPixel: function(event)
22767 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22770 isApplied: function()
22772 return this.getGmapContext() == false ? false : true;
22775 getGmapContext: function()
22777 return this.gMapContext
22780 GMapContext: function()
22782 var position = new google.maps.LatLng(this.latitude, this.longitude);
22784 var _map = new google.maps.Map(this.el.dom, {
22787 mapTypeId: this.mapTypeId,
22788 mapTypeControl: this.mapTypeControl,
22789 disableDoubleClickZoom: this.disableDoubleClickZoom,
22790 scrollwheel: this.scrollwheel,
22791 streetViewControl: this.streetViewControl,
22792 locationName: this.locationName,
22793 draggable: this.draggable,
22794 enableAutocomplete: this.enableAutocomplete,
22795 enableReverseGeocode: this.enableReverseGeocode
22798 var _marker = new google.maps.Marker({
22799 position: position,
22801 title: this.markerTitle,
22802 draggable: this.draggable
22809 location: position,
22810 radius: this.radius,
22811 locationName: this.locationName,
22812 addressComponents: {
22813 formatted_address: null,
22814 addressLine1: null,
22815 addressLine2: null,
22817 streetNumber: null,
22821 stateOrProvince: null
22824 domContainer: this.el.dom,
22825 geodecoder: new google.maps.Geocoder()
22829 drawCircle: function(center, radius, options)
22831 if (this.gMapContext.circle != null) {
22832 this.gMapContext.circle.setMap(null);
22836 options = Roo.apply({}, options, {
22837 strokeColor: "#0000FF",
22838 strokeOpacity: .35,
22840 fillColor: "#0000FF",
22844 options.map = this.gMapContext.map;
22845 options.radius = radius;
22846 options.center = center;
22847 this.gMapContext.circle = new google.maps.Circle(options);
22848 return this.gMapContext.circle;
22854 setPosition: function(location)
22856 this.gMapContext.location = location;
22857 this.gMapContext.marker.setPosition(location);
22858 this.gMapContext.map.panTo(location);
22859 this.drawCircle(location, this.gMapContext.radius, {});
22863 if (this.gMapContext.settings.enableReverseGeocode) {
22864 this.gMapContext.geodecoder.geocode({
22865 latLng: this.gMapContext.location
22866 }, function(results, status) {
22868 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22869 _this.gMapContext.locationName = results[0].formatted_address;
22870 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22872 _this.fireEvent('positionchanged', this, location);
22879 this.fireEvent('positionchanged', this, location);
22884 google.maps.event.trigger(this.gMapContext.map, "resize");
22886 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22888 this.fireEvent('resize', this);
22891 setPositionByLatLng: function(latitude, longitude)
22893 this.setPosition(new google.maps.LatLng(latitude, longitude));
22896 getCurrentPosition: function()
22899 latitude: this.gMapContext.location.lat(),
22900 longitude: this.gMapContext.location.lng()
22904 getAddressName: function()
22906 return this.gMapContext.locationName;
22909 getAddressComponents: function()
22911 return this.gMapContext.addressComponents;
22914 address_component_from_google_geocode: function(address_components)
22918 for (var i = 0; i < address_components.length; i++) {
22919 var component = address_components[i];
22920 if (component.types.indexOf("postal_code") >= 0) {
22921 result.postalCode = component.short_name;
22922 } else if (component.types.indexOf("street_number") >= 0) {
22923 result.streetNumber = component.short_name;
22924 } else if (component.types.indexOf("route") >= 0) {
22925 result.streetName = component.short_name;
22926 } else if (component.types.indexOf("neighborhood") >= 0) {
22927 result.city = component.short_name;
22928 } else if (component.types.indexOf("locality") >= 0) {
22929 result.city = component.short_name;
22930 } else if (component.types.indexOf("sublocality") >= 0) {
22931 result.district = component.short_name;
22932 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22933 result.stateOrProvince = component.short_name;
22934 } else if (component.types.indexOf("country") >= 0) {
22935 result.country = component.short_name;
22939 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22940 result.addressLine2 = "";
22944 setZoomLevel: function(zoom)
22946 this.gMapContext.map.setZoom(zoom);
22959 this.fireEvent('show', this);
22970 this.fireEvent('hide', this);
22975 Roo.apply(Roo.bootstrap.LocationPicker, {
22977 OverlayView : function(map, options)
22979 options = options || {};
22993 * @class Roo.bootstrap.Alert
22994 * @extends Roo.bootstrap.Component
22995 * Bootstrap Alert class
22996 * @cfg {String} title The title of alert
22997 * @cfg {String} html The content of alert
22998 * @cfg {String} weight ( success | info | warning | danger )
22999 * @cfg {String} faicon font-awesomeicon
23002 * Create a new alert
23003 * @param {Object} config The config object
23007 Roo.bootstrap.Alert = function(config){
23008 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23012 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23019 getAutoCreate : function()
23028 cls : 'roo-alert-icon'
23033 cls : 'roo-alert-title',
23038 cls : 'roo-alert-text',
23045 cfg.cn[0].cls += ' fa ' + this.faicon;
23049 cfg.cls += ' alert-' + this.weight;
23055 initEvents: function()
23057 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23060 setTitle : function(str)
23062 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23065 setText : function(str)
23067 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23070 setWeight : function(weight)
23073 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23076 this.weight = weight;
23078 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23081 setIcon : function(icon)
23084 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23089 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);