2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass('hidden');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
585 * @cfg {String} size ( lg | sm | xs)
586 * @cfg {String} tag ( a | input | submit)
587 * @cfg {String} href empty or href
588 * @cfg {Boolean} disabled default false;
589 * @cfg {Boolean} isClose default false;
590 * @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)
591 * @cfg {String} badge text for badge
592 * @cfg {String} theme (default|glow)
593 * @cfg {Boolean} inverse dark themed version
594 * @cfg {Boolean} toggle is it a slidy toggle button
595 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
596 * @cfg {String} ontext text for on slidy toggle state
597 * @cfg {String} offtext text for off slidy toggle state
598 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
599 * @cfg {Boolean} removeClass remove the standard class..
600 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
603 * Create a new button
604 * @param {Object} config The config object
608 Roo.bootstrap.Button = function(config){
609 Roo.bootstrap.Button.superclass.constructor.call(this, config);
610 this.weightClass = ["btn-default",
622 * When a butotn is pressed
623 * @param {Roo.bootstrap.Button} btn
624 * @param {Roo.EventObject} e
629 * After the button has been toggles
630 * @param {Roo.bootstrap.Button} btn
631 * @param {Roo.EventObject} e
632 * @param {boolean} pressed (also available as button.pressed)
638 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
656 preventDefault: true,
664 getAutoCreate : function(){
672 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
673 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
678 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
680 if (this.toggle == true) {
683 cls: 'slider-frame roo-button',
688 'data-off-text':'OFF',
689 cls: 'slider-button',
695 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
696 cfg.cls += ' '+this.weight;
705 cfg["aria-hidden"] = true;
707 cfg.html = "×";
713 if (this.theme==='default') {
714 cfg.cls = 'btn roo-button';
716 //if (this.parentType != 'Navbar') {
717 this.weight = this.weight.length ? this.weight : 'default';
719 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
721 cfg.cls += ' btn-' + this.weight;
723 } else if (this.theme==='glow') {
726 cfg.cls = 'btn-glow roo-button';
728 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
730 cfg.cls += ' ' + this.weight;
736 this.cls += ' inverse';
740 if (this.active || this.pressed === true) {
741 cfg.cls += ' active';
745 cfg.disabled = 'disabled';
749 Roo.log('changing to ul' );
751 this.glyphicon = 'caret';
754 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
756 //gsRoo.log(this.parentType);
757 if (this.parentType === 'Navbar' && !this.parent().bar) {
758 Roo.log('changing to li?');
767 href : this.href || '#'
770 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
771 cfg.cls += ' dropdown';
778 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
780 if (this.glyphicon) {
781 cfg.html = ' ' + cfg.html;
786 cls: 'glyphicon glyphicon-' + this.glyphicon
796 // cfg.cls='btn roo-button';
800 var value = cfg.html;
805 cls: 'glyphicon glyphicon-' + this.glyphicon,
824 cfg.cls += ' dropdown';
825 cfg.html = typeof(cfg.html) != 'undefined' ?
826 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
829 if (cfg.tag !== 'a' && this.href !== '') {
830 throw "Tag must be a to set href.";
831 } else if (this.href.length > 0) {
832 cfg.href = this.href;
835 if(this.removeClass){
840 cfg.target = this.target;
845 initEvents: function() {
846 // Roo.log('init events?');
847 // Roo.log(this.el.dom);
850 if (typeof (this.menu) != 'undefined') {
851 this.menu.parentType = this.xtype;
852 this.menu.triggerEl = this.el;
853 this.addxtype(Roo.apply({}, this.menu));
857 if (this.el.hasClass('roo-button')) {
858 this.el.on('click', this.onClick, this);
860 this.el.select('.roo-button').on('click', this.onClick, this);
863 if(this.removeClass){
864 this.el.on('click', this.onClick, this);
867 this.el.enableDisplayMode();
870 onClick : function(e)
876 Roo.log('button on click ');
877 if(this.preventDefault){
881 if (this.pressed === true || this.pressed === false) {
882 this.toggleActive(e);
886 this.fireEvent('click', this, e);
890 * Enables this button
894 this.disabled = false;
895 this.el.removeClass('disabled');
899 * Disable this button
903 this.disabled = true;
904 this.el.addClass('disabled');
907 * sets the active state on/off,
908 * @param {Boolean} state (optional) Force a particular state
910 setActive : function(v) {
912 this.el[v ? 'addClass' : 'removeClass']('active');
916 * toggles the current active state
918 toggleActive : function(e)
920 this.setActive(!this.pressed);
921 this.fireEvent('toggle', this, e, !this.pressed);
924 * get the current active state
925 * @return {boolean} true if it's active
927 isActive : function()
929 return this.el.hasClass('active');
932 * set the text of the first selected button
934 setText : function(str)
936 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
939 * get the text of the first selected button
943 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
946 setWeight : function(str)
948 this.el.removeClass(this.weightClass);
949 this.el.addClass('btn-' + str);
963 * @class Roo.bootstrap.Column
964 * @extends Roo.bootstrap.Component
965 * Bootstrap Column class
966 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
967 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
968 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
969 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
970 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
971 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
972 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
973 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
976 * @cfg {Boolean} hidden (true|false) hide the element
977 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
978 * @cfg {String} fa (ban|check|...) font awesome icon
979 * @cfg {Number} fasize (1|2|....) font awsome size
981 * @cfg {String} icon (info-sign|check|...) glyphicon name
983 * @cfg {String} html content of column.
986 * Create a new Column
987 * @param {Object} config The config object
990 Roo.bootstrap.Column = function(config){
991 Roo.bootstrap.Column.superclass.constructor.call(this, config);
994 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1012 getAutoCreate : function(){
1013 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1021 ['xs','sm','md','lg'].map(function(size){
1022 //Roo.log( size + ':' + settings[size]);
1024 if (settings[size+'off'] !== false) {
1025 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1028 if (settings[size] === false) {
1032 if (!settings[size]) { // 0 = hidden
1033 cfg.cls += ' hidden-' + size;
1036 cfg.cls += ' col-' + size + '-' + settings[size];
1041 cfg.cls += ' hidden';
1044 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1045 cfg.cls +=' alert alert-' + this.alert;
1049 if (this.html.length) {
1050 cfg.html = this.html;
1054 if (this.fasize > 1) {
1055 fasize = ' fa-' + this.fasize + 'x';
1057 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1062 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1081 * @class Roo.bootstrap.Container
1082 * @extends Roo.bootstrap.Component
1083 * Bootstrap Container class
1084 * @cfg {Boolean} jumbotron is it a jumbotron element
1085 * @cfg {String} html content of element
1086 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1087 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1088 * @cfg {String} header content of header (for panel)
1089 * @cfg {String} footer content of footer (for panel)
1090 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1091 * @cfg {String} tag (header|aside|section) type of HTML tag.
1092 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1093 * @cfg {String} fa font awesome icon
1094 * @cfg {String} icon (info-sign|check|...) glyphicon name
1095 * @cfg {Boolean} hidden (true|false) hide the element
1096 * @cfg {Boolean} expandable (true|false) default false
1097 * @cfg {Boolean} expanded (true|false) default true
1098 * @cfg {String} rheader contet on the right of header
1099 * @cfg {Boolean} clickable (true|false) default false
1103 * Create a new Container
1104 * @param {Object} config The config object
1107 Roo.bootstrap.Container = function(config){
1108 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1114 * After the panel has been expand
1116 * @param {Roo.bootstrap.Container} this
1121 * After the panel has been collapsed
1123 * @param {Roo.bootstrap.Container} this
1128 * When a element is chick
1129 * @param {Roo.bootstrap.Container} this
1130 * @param {Roo.EventObject} e
1136 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1154 getChildContainer : function() {
1160 if (this.panel.length) {
1161 return this.el.select('.panel-body',true).first();
1168 getAutoCreate : function(){
1171 tag : this.tag || 'div',
1175 if (this.jumbotron) {
1176 cfg.cls = 'jumbotron';
1181 // - this is applied by the parent..
1183 // cfg.cls = this.cls + '';
1186 if (this.sticky.length) {
1188 var bd = Roo.get(document.body);
1189 if (!bd.hasClass('bootstrap-sticky')) {
1190 bd.addClass('bootstrap-sticky');
1191 Roo.select('html',true).setStyle('height', '100%');
1194 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1198 if (this.well.length) {
1199 switch (this.well) {
1202 cfg.cls +=' well well-' +this.well;
1211 cfg.cls += ' hidden';
1215 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1216 cfg.cls +=' alert alert-' + this.alert;
1221 if (this.panel.length) {
1222 cfg.cls += ' panel panel-' + this.panel;
1224 if (this.header.length) {
1228 if(this.expandable){
1230 cfg.cls = cfg.cls + ' expandable';
1234 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1242 cls : 'panel-title',
1243 html : (this.expandable ? ' ' : '') + this.header
1247 cls: 'panel-header-right',
1253 cls : 'panel-heading',
1254 style : this.expandable ? 'cursor: pointer' : '',
1262 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1267 if (this.footer.length) {
1269 cls : 'panel-footer',
1278 body.html = this.html || cfg.html;
1279 // prefix with the icons..
1281 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1284 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1289 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1290 cfg.cls = 'container';
1296 initEvents: function()
1298 if(this.expandable){
1299 var headerEl = this.headerEl();
1302 headerEl.on('click', this.onToggleClick, this);
1307 this.el.on('click', this.onClick, this);
1312 onToggleClick : function()
1314 var headerEl = this.headerEl();
1330 if(this.fireEvent('expand', this)) {
1332 this.expanded = true;
1334 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1336 this.el.select('.panel-body',true).first().removeClass('hide');
1338 var toggleEl = this.toggleEl();
1344 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1349 collapse : function()
1351 if(this.fireEvent('collapse', this)) {
1353 this.expanded = false;
1355 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1356 this.el.select('.panel-body',true).first().addClass('hide');
1358 var toggleEl = this.toggleEl();
1364 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1368 toggleEl : function()
1370 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1374 return this.el.select('.panel-heading .fa',true).first();
1377 headerEl : function()
1379 if(!this.el || !this.panel.length || !this.header.length){
1383 return this.el.select('.panel-heading',true).first()
1388 if(!this.el || !this.panel.length){
1392 return this.el.select('.panel-body',true).first()
1395 titleEl : function()
1397 if(!this.el || !this.panel.length || !this.header.length){
1401 return this.el.select('.panel-title',true).first();
1404 setTitle : function(v)
1406 var titleEl = this.titleEl();
1412 titleEl.dom.innerHTML = v;
1415 getTitle : function()
1418 var titleEl = this.titleEl();
1424 return titleEl.dom.innerHTML;
1427 setRightTitle : function(v)
1429 var t = this.el.select('.panel-header-right',true).first();
1435 t.dom.innerHTML = v;
1438 onClick : function(e)
1442 this.fireEvent('click', this, e);
1455 * @class Roo.bootstrap.Img
1456 * @extends Roo.bootstrap.Component
1457 * Bootstrap Img class
1458 * @cfg {Boolean} imgResponsive false | true
1459 * @cfg {String} border rounded | circle | thumbnail
1460 * @cfg {String} src image source
1461 * @cfg {String} alt image alternative text
1462 * @cfg {String} href a tag href
1463 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1464 * @cfg {String} xsUrl xs image source
1465 * @cfg {String} smUrl sm image source
1466 * @cfg {String} mdUrl md image source
1467 * @cfg {String} lgUrl lg image source
1470 * Create a new Input
1471 * @param {Object} config The config object
1474 Roo.bootstrap.Img = function(config){
1475 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1481 * The img click event for the img.
1482 * @param {Roo.EventObject} e
1488 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1490 imgResponsive: true,
1500 getAutoCreate : function()
1502 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1503 return this.createSingleImg();
1508 cls: 'roo-image-responsive-group',
1513 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1515 if(!_this[size + 'Url']){
1521 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1522 html: _this.html || cfg.html,
1523 src: _this[size + 'Url']
1526 img.cls += ' roo-image-responsive-' + size;
1528 var s = ['xs', 'sm', 'md', 'lg'];
1530 s.splice(s.indexOf(size), 1);
1532 Roo.each(s, function(ss){
1533 img.cls += ' hidden-' + ss;
1536 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1537 cfg.cls += ' img-' + _this.border;
1541 cfg.alt = _this.alt;
1554 a.target = _this.target;
1558 cfg.cn.push((_this.href) ? a : img);
1565 createSingleImg : function()
1569 cls: (this.imgResponsive) ? 'img-responsive' : '',
1571 src : 'about:blank' // just incase src get's set to undefined?!?
1574 cfg.html = this.html || cfg.html;
1576 cfg.src = this.src || cfg.src;
1578 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1579 cfg.cls += ' img-' + this.border;
1596 a.target = this.target;
1601 return (this.href) ? a : cfg;
1604 initEvents: function()
1607 this.el.on('click', this.onClick, this);
1612 onClick : function(e)
1614 Roo.log('img onclick');
1615 this.fireEvent('click', this, e);
1618 * Sets the url of the image - used to update it
1619 * @param {String} url the url of the image
1622 setSrc : function(url)
1626 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1627 this.el.dom.src = url;
1631 this.el.select('img', true).first().dom.src = url;
1647 * @class Roo.bootstrap.Link
1648 * @extends Roo.bootstrap.Component
1649 * Bootstrap Link Class
1650 * @cfg {String} alt image alternative text
1651 * @cfg {String} href a tag href
1652 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1653 * @cfg {String} html the content of the link.
1654 * @cfg {String} anchor name for the anchor link
1655 * @cfg {String} fa - favicon
1657 * @cfg {Boolean} preventDefault (true | false) default false
1661 * Create a new Input
1662 * @param {Object} config The config object
1665 Roo.bootstrap.Link = function(config){
1666 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1672 * The img click event for the img.
1673 * @param {Roo.EventObject} e
1679 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1683 preventDefault: false,
1689 getAutoCreate : function()
1691 var html = this.html || '';
1693 if (this.fa !== false) {
1694 html = '<i class="fa fa-' + this.fa + '"></i>';
1699 // anchor's do not require html/href...
1700 if (this.anchor === false) {
1702 cfg.href = this.href || '#';
1704 cfg.name = this.anchor;
1705 if (this.html !== false || this.fa !== false) {
1708 if (this.href !== false) {
1709 cfg.href = this.href;
1713 if(this.alt !== false){
1718 if(this.target !== false) {
1719 cfg.target = this.target;
1725 initEvents: function() {
1727 if(!this.href || this.preventDefault){
1728 this.el.on('click', this.onClick, this);
1732 onClick : function(e)
1734 if(this.preventDefault){
1737 //Roo.log('img onclick');
1738 this.fireEvent('click', this, e);
1751 * @class Roo.bootstrap.Header
1752 * @extends Roo.bootstrap.Component
1753 * Bootstrap Header class
1754 * @cfg {String} html content of header
1755 * @cfg {Number} level (1|2|3|4|5|6) default 1
1758 * Create a new Header
1759 * @param {Object} config The config object
1763 Roo.bootstrap.Header = function(config){
1764 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1767 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1775 getAutoCreate : function(){
1780 tag: 'h' + (1 *this.level),
1781 html: this.html || ''
1793 * Ext JS Library 1.1.1
1794 * Copyright(c) 2006-2007, Ext JS, LLC.
1796 * Originally Released Under LGPL - original licence link has changed is not relivant.
1799 * <script type="text/javascript">
1803 * @class Roo.bootstrap.MenuMgr
1804 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1807 Roo.bootstrap.MenuMgr = function(){
1808 var menus, active, groups = {}, attached = false, lastShow = new Date();
1810 // private - called when first menu is created
1813 active = new Roo.util.MixedCollection();
1814 Roo.get(document).addKeyListener(27, function(){
1815 if(active.length > 0){
1823 if(active && active.length > 0){
1824 var c = active.clone();
1834 if(active.length < 1){
1835 Roo.get(document).un("mouseup", onMouseDown);
1843 var last = active.last();
1844 lastShow = new Date();
1847 Roo.get(document).on("mouseup", onMouseDown);
1852 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1853 m.parentMenu.activeChild = m;
1854 }else if(last && last.isVisible()){
1855 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1860 function onBeforeHide(m){
1862 m.activeChild.hide();
1864 if(m.autoHideTimer){
1865 clearTimeout(m.autoHideTimer);
1866 delete m.autoHideTimer;
1871 function onBeforeShow(m){
1872 var pm = m.parentMenu;
1873 if(!pm && !m.allowOtherMenus){
1875 }else if(pm && pm.activeChild && active != m){
1876 pm.activeChild.hide();
1880 // private this should really trigger on mouseup..
1881 function onMouseDown(e){
1882 Roo.log("on Mouse Up");
1884 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1885 Roo.log("MenuManager hideAll");
1894 function onBeforeCheck(mi, state){
1896 var g = groups[mi.group];
1897 for(var i = 0, l = g.length; i < l; i++){
1899 g[i].setChecked(false);
1908 * Hides all menus that are currently visible
1910 hideAll : function(){
1915 register : function(menu){
1919 menus[menu.id] = menu;
1920 menu.on("beforehide", onBeforeHide);
1921 menu.on("hide", onHide);
1922 menu.on("beforeshow", onBeforeShow);
1923 menu.on("show", onShow);
1925 if(g && menu.events["checkchange"]){
1929 groups[g].push(menu);
1930 menu.on("checkchange", onCheck);
1935 * Returns a {@link Roo.menu.Menu} object
1936 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1937 * be used to generate and return a new Menu instance.
1939 get : function(menu){
1940 if(typeof menu == "string"){ // menu id
1942 }else if(menu.events){ // menu instance
1945 /*else if(typeof menu.length == 'number'){ // array of menu items?
1946 return new Roo.bootstrap.Menu({items:menu});
1947 }else{ // otherwise, must be a config
1948 return new Roo.bootstrap.Menu(menu);
1955 unregister : function(menu){
1956 delete menus[menu.id];
1957 menu.un("beforehide", onBeforeHide);
1958 menu.un("hide", onHide);
1959 menu.un("beforeshow", onBeforeShow);
1960 menu.un("show", onShow);
1962 if(g && menu.events["checkchange"]){
1963 groups[g].remove(menu);
1964 menu.un("checkchange", onCheck);
1969 registerCheckable : function(menuItem){
1970 var g = menuItem.group;
1975 groups[g].push(menuItem);
1976 menuItem.on("beforecheckchange", onBeforeCheck);
1981 unregisterCheckable : function(menuItem){
1982 var g = menuItem.group;
1984 groups[g].remove(menuItem);
1985 menuItem.un("beforecheckchange", onBeforeCheck);
1997 * @class Roo.bootstrap.Menu
1998 * @extends Roo.bootstrap.Component
1999 * Bootstrap Menu class - container for MenuItems
2000 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2001 * @cfg {bool} hidden if the menu should be hidden when rendered.
2002 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2003 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2007 * @param {Object} config The config object
2011 Roo.bootstrap.Menu = function(config){
2012 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2013 if (this.registerMenu && this.type != 'treeview') {
2014 Roo.bootstrap.MenuMgr.register(this);
2021 * Fires before this menu is displayed
2022 * @param {Roo.menu.Menu} this
2027 * Fires before this menu is hidden
2028 * @param {Roo.menu.Menu} this
2033 * Fires after this menu is displayed
2034 * @param {Roo.menu.Menu} this
2039 * Fires after this menu is hidden
2040 * @param {Roo.menu.Menu} this
2045 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2046 * @param {Roo.menu.Menu} this
2047 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2048 * @param {Roo.EventObject} e
2053 * Fires when the mouse is hovering over this menu
2054 * @param {Roo.menu.Menu} this
2055 * @param {Roo.EventObject} e
2056 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2061 * Fires when the mouse exits this menu
2062 * @param {Roo.menu.Menu} this
2063 * @param {Roo.EventObject} e
2064 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2069 * Fires when a menu item contained in this menu is clicked
2070 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2071 * @param {Roo.EventObject} e
2075 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2078 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2082 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2085 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2087 registerMenu : true,
2089 menuItems :false, // stores the menu items..
2099 getChildContainer : function() {
2103 getAutoCreate : function(){
2105 //if (['right'].indexOf(this.align)!==-1) {
2106 // cfg.cn[1].cls += ' pull-right'
2112 cls : 'dropdown-menu' ,
2113 style : 'z-index:1000'
2117 if (this.type === 'submenu') {
2118 cfg.cls = 'submenu active';
2120 if (this.type === 'treeview') {
2121 cfg.cls = 'treeview-menu';
2126 initEvents : function() {
2128 // Roo.log("ADD event");
2129 // Roo.log(this.triggerEl.dom);
2131 this.triggerEl.on('click', this.onTriggerClick, this);
2133 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2136 if (this.triggerEl.hasClass('nav-item')) {
2137 // dropdown toggle on the 'a' in BS4?
2138 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2140 this.triggerEl.addClass('dropdown-toggle');
2143 this.el.on('touchstart' , this.onTouch, this);
2145 this.el.on('click' , this.onClick, this);
2147 this.el.on("mouseover", this.onMouseOver, this);
2148 this.el.on("mouseout", this.onMouseOut, this);
2152 findTargetItem : function(e)
2154 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2158 //Roo.log(t); Roo.log(t.id);
2160 //Roo.log(this.menuitems);
2161 return this.menuitems.get(t.id);
2163 //return this.items.get(t.menuItemId);
2169 onTouch : function(e)
2171 Roo.log("menu.onTouch");
2172 //e.stopEvent(); this make the user popdown broken
2176 onClick : function(e)
2178 Roo.log("menu.onClick");
2180 var t = this.findTargetItem(e);
2181 if(!t || t.isContainer){
2186 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2187 if(t == this.activeItem && t.shouldDeactivate(e)){
2188 this.activeItem.deactivate();
2189 delete this.activeItem;
2193 this.setActiveItem(t, true);
2201 Roo.log('pass click event');
2205 this.fireEvent("click", this, t, e);
2209 if(!t.href.length || t.href == '#'){
2210 (function() { _this.hide(); }).defer(100);
2215 onMouseOver : function(e){
2216 var t = this.findTargetItem(e);
2219 // if(t.canActivate && !t.disabled){
2220 // this.setActiveItem(t, true);
2224 this.fireEvent("mouseover", this, e, t);
2226 isVisible : function(){
2227 return !this.hidden;
2229 onMouseOut : function(e){
2230 var t = this.findTargetItem(e);
2233 // if(t == this.activeItem && t.shouldDeactivate(e)){
2234 // this.activeItem.deactivate();
2235 // delete this.activeItem;
2238 this.fireEvent("mouseout", this, e, t);
2243 * Displays this menu relative to another element
2244 * @param {String/HTMLElement/Roo.Element} element The element to align to
2245 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2246 * the element (defaults to this.defaultAlign)
2247 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2249 show : function(el, pos, parentMenu){
2250 this.parentMenu = parentMenu;
2254 this.fireEvent("beforeshow", this);
2255 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2258 * Displays this menu at a specific xy position
2259 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2260 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2262 showAt : function(xy, parentMenu, /* private: */_e){
2263 this.parentMenu = parentMenu;
2268 this.fireEvent("beforeshow", this);
2269 //xy = this.el.adjustForConstraints(xy);
2273 this.hideMenuItems();
2274 this.hidden = false;
2275 this.triggerEl.addClass('open');
2276 this.el.addClass('show');
2278 // reassign x when hitting right
2279 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2280 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2283 // reassign y when hitting bottom
2284 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2285 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2288 // but the list may align on trigger left or trigger top... should it be a properity?
2290 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2295 this.fireEvent("show", this);
2301 this.doFocus.defer(50, this);
2305 doFocus : function(){
2307 this.focusEl.focus();
2312 * Hides this menu and optionally all parent menus
2313 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2315 hide : function(deep)
2318 this.hideMenuItems();
2319 if(this.el && this.isVisible()){
2320 this.fireEvent("beforehide", this);
2321 if(this.activeItem){
2322 this.activeItem.deactivate();
2323 this.activeItem = null;
2325 this.triggerEl.removeClass('open');;
2326 this.el.removeClass('show');
2328 this.fireEvent("hide", this);
2330 if(deep === true && this.parentMenu){
2331 this.parentMenu.hide(true);
2335 onTriggerClick : function(e)
2337 Roo.log('trigger click');
2339 var target = e.getTarget();
2341 Roo.log(target.nodeName.toLowerCase());
2343 if(target.nodeName.toLowerCase() === 'i'){
2349 onTriggerPress : function(e)
2351 Roo.log('trigger press');
2352 //Roo.log(e.getTarget());
2353 // Roo.log(this.triggerEl.dom);
2355 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2356 var pel = Roo.get(e.getTarget());
2357 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2358 Roo.log('is treeview or dropdown?');
2362 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2366 if (this.isVisible()) {
2371 this.show(this.triggerEl, false, false);
2374 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2381 hideMenuItems : function()
2383 Roo.log("hide Menu Items");
2387 //$(backdrop).remove()
2388 this.el.select('.open',true).each(function(aa) {
2390 aa.removeClass('open');
2391 //var parent = getParent($(this))
2392 //var relatedTarget = { relatedTarget: this }
2394 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2395 //if (e.isDefaultPrevented()) return
2396 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2399 addxtypeChild : function (tree, cntr) {
2400 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2402 this.menuitems.add(comp);
2414 this.getEl().dom.innerHTML = '';
2415 this.menuitems.clear();
2429 * @class Roo.bootstrap.MenuItem
2430 * @extends Roo.bootstrap.Component
2431 * Bootstrap MenuItem class
2432 * @cfg {String} html the menu label
2433 * @cfg {String} href the link
2434 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2435 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2436 * @cfg {Boolean} active used on sidebars to highlight active itesm
2437 * @cfg {String} fa favicon to show on left of menu item.
2438 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2442 * Create a new MenuItem
2443 * @param {Object} config The config object
2447 Roo.bootstrap.MenuItem = function(config){
2448 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2453 * The raw click event for the entire grid.
2454 * @param {Roo.bootstrap.MenuItem} this
2455 * @param {Roo.EventObject} e
2461 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2465 preventDefault: false,
2466 isContainer : false,
2470 getAutoCreate : function(){
2472 if(this.isContainer){
2475 cls: 'dropdown-menu-item dropdown-item'
2489 if (this.fa !== false) {
2492 cls : 'fa fa-' + this.fa
2501 cls: 'dropdown-menu-item dropdown-item',
2504 if (this.parent().type == 'treeview') {
2505 cfg.cls = 'treeview-menu';
2508 cfg.cls += ' active';
2513 anc.href = this.href || cfg.cn[0].href ;
2514 ctag.html = this.html || cfg.cn[0].html ;
2518 initEvents: function()
2520 if (this.parent().type == 'treeview') {
2521 this.el.select('a').on('click', this.onClick, this);
2525 this.menu.parentType = this.xtype;
2526 this.menu.triggerEl = this.el;
2527 this.menu = this.addxtype(Roo.apply({}, this.menu));
2531 onClick : function(e)
2533 Roo.log('item on click ');
2535 if(this.preventDefault){
2538 //this.parent().hideMenuItems();
2540 this.fireEvent('click', this, e);
2559 * @class Roo.bootstrap.MenuSeparator
2560 * @extends Roo.bootstrap.Component
2561 * Bootstrap MenuSeparator class
2564 * Create a new MenuItem
2565 * @param {Object} config The config object
2569 Roo.bootstrap.MenuSeparator = function(config){
2570 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2573 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2575 getAutoCreate : function(){
2594 * @class Roo.bootstrap.Modal
2595 * @extends Roo.bootstrap.Component
2596 * Bootstrap Modal class
2597 * @cfg {String} title Title of dialog
2598 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2599 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2600 * @cfg {Boolean} specificTitle default false
2601 * @cfg {Array} buttons Array of buttons or standard button set..
2602 * @cfg {String} buttonPosition (left|right|center) default right
2603 * @cfg {Boolean} animate default true
2604 * @cfg {Boolean} allow_close default true
2605 * @cfg {Boolean} fitwindow default false
2606 * @cfg {String} size (sm|lg) default empty
2607 * @cfg {Number} max_width set the max width of modal
2611 * Create a new Modal Dialog
2612 * @param {Object} config The config object
2615 Roo.bootstrap.Modal = function(config){
2616 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2621 * The raw btnclick event for the button
2622 * @param {Roo.EventObject} e
2627 * Fire when dialog resize
2628 * @param {Roo.bootstrap.Modal} this
2629 * @param {Roo.EventObject} e
2633 this.buttons = this.buttons || [];
2636 this.tmpl = Roo.factory(this.tmpl);
2641 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2643 title : 'test dialog',
2653 specificTitle: false,
2655 buttonPosition: 'right',
2678 onRender : function(ct, position)
2680 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2683 var cfg = Roo.apply({}, this.getAutoCreate());
2686 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2688 //if (!cfg.name.length) {
2692 cfg.cls += ' ' + this.cls;
2695 cfg.style = this.style;
2697 this.el = Roo.get(document.body).createChild(cfg, position);
2699 //var type = this.el.dom.type;
2702 if(this.tabIndex !== undefined){
2703 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2706 this.dialogEl = this.el.select('.modal-dialog',true).first();
2707 this.bodyEl = this.el.select('.modal-body',true).first();
2708 this.closeEl = this.el.select('.modal-header .close', true).first();
2709 this.headerEl = this.el.select('.modal-header',true).first();
2710 this.titleEl = this.el.select('.modal-title',true).first();
2711 this.footerEl = this.el.select('.modal-footer',true).first();
2713 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2715 //this.el.addClass("x-dlg-modal");
2717 if (this.buttons.length) {
2718 Roo.each(this.buttons, function(bb) {
2719 var b = Roo.apply({}, bb);
2720 b.xns = b.xns || Roo.bootstrap;
2721 b.xtype = b.xtype || 'Button';
2722 if (typeof(b.listeners) == 'undefined') {
2723 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2726 var btn = Roo.factory(b);
2728 btn.render(this.el.select('.modal-footer div').first());
2732 // render the children.
2735 if(typeof(this.items) != 'undefined'){
2736 var items = this.items;
2739 for(var i =0;i < items.length;i++) {
2740 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2744 this.items = nitems;
2746 // where are these used - they used to be body/close/footer
2750 //this.el.addClass([this.fieldClass, this.cls]);
2754 getAutoCreate : function()
2758 html : this.html || ''
2763 cls : 'modal-title',
2767 if(this.specificTitle){
2773 if (this.allow_close) {
2785 if(this.size.length){
2786 size = 'modal-' + this.size;
2793 cls: "modal-dialog " + size,
2796 cls : "modal-content",
2799 cls : 'modal-header',
2804 cls : 'modal-footer',
2808 cls: 'btn-' + this.buttonPosition
2825 modal.cls += ' fade';
2831 getChildContainer : function() {
2836 getButtonContainer : function() {
2837 return this.el.select('.modal-footer div',true).first();
2840 initEvents : function()
2842 if (this.allow_close) {
2843 this.closeEl.on('click', this.hide, this);
2845 Roo.EventManager.onWindowResize(this.resize, this, true);
2852 this.maskEl.setSize(
2853 Roo.lib.Dom.getViewWidth(true),
2854 Roo.lib.Dom.getViewHeight(true)
2857 if (this.fitwindow) {
2859 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2860 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2865 if(this.max_width !== 0) {
2867 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2870 this.setSize(w, this.height);
2874 if(this.max_height) {
2875 this.setSize(w,Math.min(
2877 Roo.lib.Dom.getViewportHeight(true) - 60
2883 if(!this.fit_content) {
2884 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2888 this.setSize(w, Math.min(
2890 this.headerEl.getHeight() +
2891 this.footerEl.getHeight() +
2892 this.getChildHeight(this.bodyEl.dom.childNodes),
2893 Roo.lib.Dom.getViewportHeight(true) - 60)
2899 setSize : function(w,h)
2910 if (!this.rendered) {
2914 //this.el.setStyle('display', 'block');
2915 this.el.removeClass('hideing');
2916 this.el.addClass('show');
2918 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2921 this.el.addClass('in');
2924 this.el.addClass('in');
2927 // not sure how we can show data in here..
2929 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2932 Roo.get(document.body).addClass("x-body-masked");
2934 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2935 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2936 this.maskEl.addClass('show');
2940 this.fireEvent('show', this);
2942 // set zindex here - otherwise it appears to be ignored...
2943 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2946 this.items.forEach( function(e) {
2947 e.layout ? e.layout() : false;
2955 if(this.fireEvent("beforehide", this) !== false){
2956 this.maskEl.removeClass('show');
2957 Roo.get(document.body).removeClass("x-body-masked");
2958 this.el.removeClass('in');
2959 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2961 if(this.animate){ // why
2962 this.el.addClass('hideing');
2964 if (!this.el.hasClass('hideing')) {
2965 return; // it's been shown again...
2967 this.el.removeClass('show');
2968 this.el.removeClass('hideing');
2972 this.el.removeClass('show');
2974 this.fireEvent('hide', this);
2977 isVisible : function()
2980 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2984 addButton : function(str, cb)
2988 var b = Roo.apply({}, { html : str } );
2989 b.xns = b.xns || Roo.bootstrap;
2990 b.xtype = b.xtype || 'Button';
2991 if (typeof(b.listeners) == 'undefined') {
2992 b.listeners = { click : cb.createDelegate(this) };
2995 var btn = Roo.factory(b);
2997 btn.render(this.el.select('.modal-footer div').first());
3003 setDefaultButton : function(btn)
3005 //this.el.select('.modal-footer').()
3009 resizeTo: function(w,h)
3013 this.dialogEl.setWidth(w);
3014 if (this.diff === false) {
3015 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3018 this.bodyEl.setHeight(h - this.diff);
3020 this.fireEvent('resize', this);
3023 setContentSize : function(w, h)
3027 onButtonClick: function(btn,e)
3030 this.fireEvent('btnclick', btn.name, e);
3033 * Set the title of the Dialog
3034 * @param {String} str new Title
3036 setTitle: function(str) {
3037 this.titleEl.dom.innerHTML = str;
3040 * Set the body of the Dialog
3041 * @param {String} str new Title
3043 setBody: function(str) {
3044 this.bodyEl.dom.innerHTML = str;
3047 * Set the body of the Dialog using the template
3048 * @param {Obj} data - apply this data to the template and replace the body contents.
3050 applyBody: function(obj)
3053 Roo.log("Error - using apply Body without a template");
3056 this.tmpl.overwrite(this.bodyEl, obj);
3059 getChildHeight : function(child_nodes)
3063 child_nodes.length == 0
3068 var child_height = 0;
3070 for(var i = 0; i < child_nodes.length; i++) {
3073 * for modal with tabs...
3074 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3076 var layout_childs = child_nodes[i].childNodes;
3078 for(var j = 0; j < layout_childs.length; j++) {
3080 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3082 var layout_body_childs = layout_childs[j].childNodes;
3084 for(var k = 0; k < layout_body_childs.length; k++) {
3086 if(layout_body_childs[k].classList.contains('navbar')) {
3087 child_height += layout_body_childs[k].offsetHeight;
3091 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3093 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3095 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3097 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3098 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3113 child_height += child_nodes[i].offsetHeight;
3114 // Roo.log(child_nodes[i].offsetHeight);
3117 return child_height;
3123 Roo.apply(Roo.bootstrap.Modal, {
3125 * Button config that displays a single OK button
3134 * Button config that displays Yes and No buttons
3150 * Button config that displays OK and Cancel buttons
3165 * Button config that displays Yes, No and Cancel buttons
3189 * messagebox - can be used as a replace
3193 * @class Roo.MessageBox
3194 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3198 Roo.Msg.alert('Status', 'Changes saved successfully.');
3200 // Prompt for user data:
3201 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3203 // process text value...
3207 // Show a dialog using config options:
3209 title:'Save Changes?',
3210 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3211 buttons: Roo.Msg.YESNOCANCEL,
3218 Roo.bootstrap.MessageBox = function(){
3219 var dlg, opt, mask, waitTimer;
3220 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3221 var buttons, activeTextEl, bwidth;
3225 var handleButton = function(button){
3227 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3231 var handleHide = function(){
3233 dlg.el.removeClass(opt.cls);
3236 // Roo.TaskMgr.stop(waitTimer);
3237 // waitTimer = null;
3242 var updateButtons = function(b){
3245 buttons["ok"].hide();
3246 buttons["cancel"].hide();
3247 buttons["yes"].hide();
3248 buttons["no"].hide();
3249 //dlg.footer.dom.style.display = 'none';
3252 dlg.footerEl.dom.style.display = '';
3253 for(var k in buttons){
3254 if(typeof buttons[k] != "function"){
3257 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3258 width += buttons[k].el.getWidth()+15;
3268 var handleEsc = function(d, k, e){
3269 if(opt && opt.closable !== false){
3279 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3280 * @return {Roo.BasicDialog} The BasicDialog element
3282 getDialog : function(){
3284 dlg = new Roo.bootstrap.Modal( {
3287 //constraintoviewport:false,
3289 //collapsible : false,
3294 //buttonAlign:"center",
3295 closeClick : function(){
3296 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3299 handleButton("cancel");
3304 dlg.on("hide", handleHide);
3306 //dlg.addKeyListener(27, handleEsc);
3308 this.buttons = buttons;
3309 var bt = this.buttonText;
3310 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3311 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3312 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3313 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3315 bodyEl = dlg.bodyEl.createChild({
3317 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3318 '<textarea class="roo-mb-textarea"></textarea>' +
3319 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3321 msgEl = bodyEl.dom.firstChild;
3322 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3323 textboxEl.enableDisplayMode();
3324 textboxEl.addKeyListener([10,13], function(){
3325 if(dlg.isVisible() && opt && opt.buttons){
3328 }else if(opt.buttons.yes){
3329 handleButton("yes");
3333 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3334 textareaEl.enableDisplayMode();
3335 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3336 progressEl.enableDisplayMode();
3338 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3339 var pf = progressEl.dom.firstChild;
3341 pp = Roo.get(pf.firstChild);
3342 pp.setHeight(pf.offsetHeight);
3350 * Updates the message box body text
3351 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3352 * the XHTML-compliant non-breaking space character '&#160;')
3353 * @return {Roo.MessageBox} This message box
3355 updateText : function(text)
3357 if(!dlg.isVisible() && !opt.width){
3358 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3359 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3361 msgEl.innerHTML = text || ' ';
3363 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3364 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3366 Math.min(opt.width || cw , this.maxWidth),
3367 Math.max(opt.minWidth || this.minWidth, bwidth)
3370 activeTextEl.setWidth(w);
3372 if(dlg.isVisible()){
3373 dlg.fixedcenter = false;
3375 // to big, make it scroll. = But as usual stupid IE does not support
3378 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3379 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3380 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3382 bodyEl.dom.style.height = '';
3383 bodyEl.dom.style.overflowY = '';
3386 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3388 bodyEl.dom.style.overflowX = '';
3391 dlg.setContentSize(w, bodyEl.getHeight());
3392 if(dlg.isVisible()){
3393 dlg.fixedcenter = true;
3399 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3400 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3401 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3402 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3403 * @return {Roo.MessageBox} This message box
3405 updateProgress : function(value, text){
3407 this.updateText(text);
3410 if (pp) { // weird bug on my firefox - for some reason this is not defined
3411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3412 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3418 * Returns true if the message box is currently displayed
3419 * @return {Boolean} True if the message box is visible, else false
3421 isVisible : function(){
3422 return dlg && dlg.isVisible();
3426 * Hides the message box if it is displayed
3429 if(this.isVisible()){
3435 * Displays a new message box, or reinitializes an existing message box, based on the config options
3436 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3437 * The following config object properties are supported:
3439 Property Type Description
3440 ---------- --------------- ------------------------------------------------------------------------------------
3441 animEl String/Element An id or Element from which the message box should animate as it opens and
3442 closes (defaults to undefined)
3443 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3444 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3445 closable Boolean False to hide the top-right close button (defaults to true). Note that
3446 progress and wait dialogs will ignore this property and always hide the
3447 close button as they can only be closed programmatically.
3448 cls String A custom CSS class to apply to the message box element
3449 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3450 displayed (defaults to 75)
3451 fn Function A callback function to execute after closing the dialog. The arguments to the
3452 function will be btn (the name of the button that was clicked, if applicable,
3453 e.g. "ok"), and text (the value of the active text field, if applicable).
3454 Progress and wait dialogs will ignore this option since they do not respond to
3455 user actions and can only be closed programmatically, so any required function
3456 should be called by the same code after it closes the dialog.
3457 icon String A CSS class that provides a background image to be used as an icon for
3458 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3459 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3460 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3461 modal Boolean False to allow user interaction with the page while the message box is
3462 displayed (defaults to true)
3463 msg String A string that will replace the existing message box body text (defaults
3464 to the XHTML-compliant non-breaking space character ' ')
3465 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3466 progress Boolean True to display a progress bar (defaults to false)
3467 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3468 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3469 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3470 title String The title text
3471 value String The string value to set into the active textbox element if displayed
3472 wait Boolean True to display a progress bar (defaults to false)
3473 width Number The width of the dialog in pixels
3480 msg: 'Please enter your address:',
3482 buttons: Roo.MessageBox.OKCANCEL,
3485 animEl: 'addAddressBtn'
3488 * @param {Object} config Configuration options
3489 * @return {Roo.MessageBox} This message box
3491 show : function(options)
3494 // this causes nightmares if you show one dialog after another
3495 // especially on callbacks..
3497 if(this.isVisible()){
3500 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3501 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3502 Roo.log("New Dialog Message:" + options.msg )
3503 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3504 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3507 var d = this.getDialog();
3509 d.setTitle(opt.title || " ");
3510 d.closeEl.setDisplayed(opt.closable !== false);
3511 activeTextEl = textboxEl;
3512 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3517 textareaEl.setHeight(typeof opt.multiline == "number" ?
3518 opt.multiline : this.defaultTextHeight);
3519 activeTextEl = textareaEl;
3528 progressEl.setDisplayed(opt.progress === true);
3529 this.updateProgress(0);
3530 activeTextEl.dom.value = opt.value || "";
3532 dlg.setDefaultButton(activeTextEl);
3534 var bs = opt.buttons;
3538 }else if(bs && bs.yes){
3539 db = buttons["yes"];
3541 dlg.setDefaultButton(db);
3543 bwidth = updateButtons(opt.buttons);
3544 this.updateText(opt.msg);
3546 d.el.addClass(opt.cls);
3548 d.proxyDrag = opt.proxyDrag === true;
3549 d.modal = opt.modal !== false;
3550 d.mask = opt.modal !== false ? mask : false;
3552 // force it to the end of the z-index stack so it gets a cursor in FF
3553 document.body.appendChild(dlg.el.dom);
3554 d.animateTarget = null;
3555 d.show(options.animEl);
3561 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3562 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3563 * and closing the message box when the process is complete.
3564 * @param {String} title The title bar text
3565 * @param {String} msg The message box body text
3566 * @return {Roo.MessageBox} This message box
3568 progress : function(title, msg){
3575 minWidth: this.minProgressWidth,
3582 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3583 * If a callback function is passed it will be called after the user clicks the button, and the
3584 * id of the button that was clicked will be passed as the only parameter to the callback
3585 * (could also be the top-right close button).
3586 * @param {String} title The title bar text
3587 * @param {String} msg The message box body text
3588 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3589 * @param {Object} scope (optional) The scope of the callback function
3590 * @return {Roo.MessageBox} This message box
3592 alert : function(title, msg, fn, scope)
3607 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3608 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3609 * You are responsible for closing the message box when the process is complete.
3610 * @param {String} msg The message box body text
3611 * @param {String} title (optional) The title bar text
3612 * @return {Roo.MessageBox} This message box
3614 wait : function(msg, title){
3625 waitTimer = Roo.TaskMgr.start({
3627 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3635 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3636 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3637 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3638 * @param {String} title The title bar text
3639 * @param {String} msg The message box body text
3640 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3641 * @param {Object} scope (optional) The scope of the callback function
3642 * @return {Roo.MessageBox} This message box
3644 confirm : function(title, msg, fn, scope){
3648 buttons: this.YESNO,
3657 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3658 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3659 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3660 * (could also be the top-right close button) and the text that was entered will be passed as the two
3661 * parameters to the callback.
3662 * @param {String} title The title bar text
3663 * @param {String} msg The message box body text
3664 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3665 * @param {Object} scope (optional) The scope of the callback function
3666 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3667 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3668 * @return {Roo.MessageBox} This message box
3670 prompt : function(title, msg, fn, scope, multiline){
3674 buttons: this.OKCANCEL,
3679 multiline: multiline,
3686 * Button config that displays a single OK button
3691 * Button config that displays Yes and No buttons
3694 YESNO : {yes:true, no:true},
3696 * Button config that displays OK and Cancel buttons
3699 OKCANCEL : {ok:true, cancel:true},
3701 * Button config that displays Yes, No and Cancel buttons
3704 YESNOCANCEL : {yes:true, no:true, cancel:true},
3707 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3710 defaultTextHeight : 75,
3712 * The maximum width in pixels of the message box (defaults to 600)
3717 * The minimum width in pixels of the message box (defaults to 100)
3722 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3723 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3726 minProgressWidth : 250,
3728 * An object containing the default button text strings that can be overriden for localized language support.
3729 * Supported properties are: ok, cancel, yes and no.
3730 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3743 * Shorthand for {@link Roo.MessageBox}
3745 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3746 Roo.Msg = Roo.Msg || Roo.MessageBox;
3755 * @class Roo.bootstrap.Navbar
3756 * @extends Roo.bootstrap.Component
3757 * Bootstrap Navbar class
3760 * Create a new Navbar
3761 * @param {Object} config The config object
3765 Roo.bootstrap.Navbar = function(config){
3766 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3770 * @event beforetoggle
3771 * Fire before toggle the menu
3772 * @param {Roo.EventObject} e
3774 "beforetoggle" : true
3778 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3787 getAutoCreate : function(){
3790 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3794 initEvents :function ()
3796 //Roo.log(this.el.select('.navbar-toggle',true));
3797 this.el.select('.navbar-toggle',true).on('click', function() {
3798 if(this.fireEvent('beforetoggle', this) !== false){
3799 this.el.select('.navbar-collapse',true).toggleClass('in');
3809 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3811 var size = this.el.getSize();
3812 this.maskEl.setSize(size.width, size.height);
3813 this.maskEl.enableDisplayMode("block");
3822 getChildContainer : function()
3824 if (this.el.select('.collapse').getCount()) {
3825 return this.el.select('.collapse',true).first();
3858 * @class Roo.bootstrap.NavSimplebar
3859 * @extends Roo.bootstrap.Navbar
3860 * Bootstrap Sidebar class
3862 * @cfg {Boolean} inverse is inverted color
3864 * @cfg {String} type (nav | pills | tabs)
3865 * @cfg {Boolean} arrangement stacked | justified
3866 * @cfg {String} align (left | right) alignment
3868 * @cfg {Boolean} main (true|false) main nav bar? default false
3869 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3871 * @cfg {String} tag (header|footer|nav|div) default is nav
3877 * Create a new Sidebar
3878 * @param {Object} config The config object
3882 Roo.bootstrap.NavSimplebar = function(config){
3883 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3886 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3902 getAutoCreate : function(){
3906 tag : this.tag || 'div',
3919 this.type = this.type || 'nav';
3920 if (['tabs','pills'].indexOf(this.type)!==-1) {
3921 cfg.cn[0].cls += ' nav-' + this.type
3925 if (this.type!=='nav') {
3926 Roo.log('nav type must be nav/tabs/pills')
3928 cfg.cn[0].cls += ' navbar-nav'
3934 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3935 cfg.cn[0].cls += ' nav-' + this.arrangement;
3939 if (this.align === 'right') {
3940 cfg.cn[0].cls += ' navbar-right';
3944 cfg.cls += ' navbar-inverse';
3968 * navbar-expand-md fixed-top
3972 * @class Roo.bootstrap.NavHeaderbar
3973 * @extends Roo.bootstrap.NavSimplebar
3974 * Bootstrap Sidebar class
3976 * @cfg {String} brand what is brand
3977 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3978 * @cfg {String} brand_href href of the brand
3979 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3980 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3981 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3982 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3985 * Create a new Sidebar
3986 * @param {Object} config The config object
3990 Roo.bootstrap.NavHeaderbar = function(config){
3991 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3995 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4002 desktopCenter : false,
4005 getAutoCreate : function(){
4008 tag: this.nav || 'nav',
4009 cls: 'navbar navbar-expand-md',
4015 if (this.desktopCenter) {
4016 cn.push({cls : 'container', cn : []});
4023 cls: 'navbar-header',
4028 cls: 'navbar-toggle navbar-toggler',
4029 'data-toggle': 'collapse',
4034 html: 'Toggle navigation'
4038 cls: 'icon-bar navbar-toggler-icon'
4056 cls: 'collapse navbar-collapse',
4060 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4062 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4063 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4065 // tag can override this..
4067 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4070 if (this.brand !== '') {
4073 href: this.brand_href ? this.brand_href : '#',
4074 cls: 'navbar-brand',
4082 cfg.cls += ' main-nav';
4090 getHeaderChildContainer : function()
4092 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4093 return this.el.select('.navbar-header',true).first();
4096 return this.getChildContainer();
4100 initEvents : function()
4102 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4104 if (this.autohide) {
4109 Roo.get(document).on('scroll',function(e) {
4110 var ns = Roo.get(document).getScroll().top;
4111 var os = prevScroll;
4115 ft.removeClass('slideDown');
4116 ft.addClass('slideUp');
4119 ft.removeClass('slideUp');
4120 ft.addClass('slideDown');
4141 * @class Roo.bootstrap.NavSidebar
4142 * @extends Roo.bootstrap.Navbar
4143 * Bootstrap Sidebar class
4146 * Create a new Sidebar
4147 * @param {Object} config The config object
4151 Roo.bootstrap.NavSidebar = function(config){
4152 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4155 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4157 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4159 getAutoCreate : function(){
4164 cls: 'sidebar sidebar-nav'
4186 * @class Roo.bootstrap.NavGroup
4187 * @extends Roo.bootstrap.Component
4188 * Bootstrap NavGroup class
4189 * @cfg {String} align (left|right)
4190 * @cfg {Boolean} inverse
4191 * @cfg {String} type (nav|pills|tab) default nav
4192 * @cfg {String} navId - reference Id for navbar.
4196 * Create a new nav group
4197 * @param {Object} config The config object
4200 Roo.bootstrap.NavGroup = function(config){
4201 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4204 Roo.bootstrap.NavGroup.register(this);
4208 * Fires when the active item changes
4209 * @param {Roo.bootstrap.NavGroup} this
4210 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4211 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4218 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4229 getAutoCreate : function()
4231 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4238 if (['tabs','pills'].indexOf(this.type)!==-1) {
4239 cfg.cls += ' nav-' + this.type
4241 if (this.type!=='nav') {
4242 Roo.log('nav type must be nav/tabs/pills')
4244 cfg.cls += ' navbar-nav mr-auto'
4247 if (this.parent() && this.parent().sidebar) {
4250 cls: 'dashboard-menu sidebar-menu'
4256 if (this.form === true) {
4262 if (this.align === 'right') {
4263 cfg.cls += ' navbar-right';
4265 cfg.cls += ' navbar-left';
4269 if (this.align === 'right') {
4270 cfg.cls += ' navbar-right';
4274 cfg.cls += ' navbar-inverse';
4282 * sets the active Navigation item
4283 * @param {Roo.bootstrap.NavItem} the new current navitem
4285 setActiveItem : function(item)
4288 Roo.each(this.navItems, function(v){
4293 v.setActive(false, true);
4300 item.setActive(true, true);
4301 this.fireEvent('changed', this, item, prev);
4306 * gets the active Navigation item
4307 * @return {Roo.bootstrap.NavItem} the current navitem
4309 getActive : function()
4313 Roo.each(this.navItems, function(v){
4324 indexOfNav : function()
4328 Roo.each(this.navItems, function(v,i){
4339 * adds a Navigation item
4340 * @param {Roo.bootstrap.NavItem} the navitem to add
4342 addItem : function(cfg)
4344 var cn = new Roo.bootstrap.NavItem(cfg);
4346 cn.parentId = this.id;
4347 cn.onRender(this.el, null);
4351 * register a Navigation item
4352 * @param {Roo.bootstrap.NavItem} the navitem to add
4354 register : function(item)
4356 this.navItems.push( item);
4357 item.navId = this.navId;
4362 * clear all the Navigation item
4365 clearAll : function()
4368 this.el.dom.innerHTML = '';
4371 getNavItem: function(tabId)
4374 Roo.each(this.navItems, function(e) {
4375 if (e.tabId == tabId) {
4385 setActiveNext : function()
4387 var i = this.indexOfNav(this.getActive());
4388 if (i > this.navItems.length) {
4391 this.setActiveItem(this.navItems[i+1]);
4393 setActivePrev : function()
4395 var i = this.indexOfNav(this.getActive());
4399 this.setActiveItem(this.navItems[i-1]);
4401 clearWasActive : function(except) {
4402 Roo.each(this.navItems, function(e) {
4403 if (e.tabId != except.tabId && e.was_active) {
4404 e.was_active = false;
4411 getWasActive : function ()
4414 Roo.each(this.navItems, function(e) {
4429 Roo.apply(Roo.bootstrap.NavGroup, {
4433 * register a Navigation Group
4434 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4436 register : function(navgrp)
4438 this.groups[navgrp.navId] = navgrp;
4442 * fetch a Navigation Group based on the navigation ID
4443 * @param {string} the navgroup to add
4444 * @returns {Roo.bootstrap.NavGroup} the navgroup
4446 get: function(navId) {
4447 if (typeof(this.groups[navId]) == 'undefined') {
4449 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4451 return this.groups[navId] ;
4466 * @class Roo.bootstrap.NavItem
4467 * @extends Roo.bootstrap.Component
4468 * Bootstrap Navbar.NavItem class
4469 * @cfg {String} href link to
4470 * @cfg {String} html content of button
4471 * @cfg {String} badge text inside badge
4472 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4473 * @cfg {String} glyphicon name of glyphicon
4474 * @cfg {String} icon name of font awesome icon
4475 * @cfg {Boolean} active Is item active
4476 * @cfg {Boolean} disabled Is item disabled
4478 * @cfg {Boolean} preventDefault (true | false) default false
4479 * @cfg {String} tabId the tab that this item activates.
4480 * @cfg {String} tagtype (a|span) render as a href or span?
4481 * @cfg {Boolean} animateRef (true|false) link to element default false
4484 * Create a new Navbar Item
4485 * @param {Object} config The config object
4487 Roo.bootstrap.NavItem = function(config){
4488 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4493 * The raw click event for the entire grid.
4494 * @param {Roo.EventObject} e
4499 * Fires when the active item active state changes
4500 * @param {Roo.bootstrap.NavItem} this
4501 * @param {boolean} state the new state
4507 * Fires when scroll to element
4508 * @param {Roo.bootstrap.NavItem} this
4509 * @param {Object} options
4510 * @param {Roo.EventObject} e
4518 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4526 preventDefault : false,
4533 getAutoCreate : function(){
4542 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4544 if (this.disabled) {
4545 cfg.cls += ' disabled';
4548 if (this.href || this.html || this.glyphicon || this.icon) {
4552 href : this.href || "#",
4553 html: this.html || ''
4556 if (this.tagtype == 'a') {
4557 cfg.cn[0].cls = 'nav-link';
4560 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4563 if(this.glyphicon) {
4564 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4569 cfg.cn[0].html += " <span class='caret'></span>";
4573 if (this.badge !== '') {
4575 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4583 initEvents: function()
4585 if (typeof (this.menu) != 'undefined') {
4586 this.menu.parentType = this.xtype;
4587 this.menu.triggerEl = this.el;
4588 this.menu = this.addxtype(Roo.apply({}, this.menu));
4591 this.el.select('a',true).on('click', this.onClick, this);
4593 if(this.tagtype == 'span'){
4594 this.el.select('span',true).on('click', this.onClick, this);
4597 // at this point parent should be available..
4598 this.parent().register(this);
4601 onClick : function(e)
4603 if (e.getTarget('.dropdown-menu-item')) {
4604 // did you click on a menu itemm.... - then don't trigger onclick..
4609 this.preventDefault ||
4612 Roo.log("NavItem - prevent Default?");
4616 if (this.disabled) {
4620 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4621 if (tg && tg.transition) {
4622 Roo.log("waiting for the transitionend");
4628 //Roo.log("fire event clicked");
4629 if(this.fireEvent('click', this, e) === false){
4633 if(this.tagtype == 'span'){
4637 //Roo.log(this.href);
4638 var ael = this.el.select('a',true).first();
4641 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4642 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4643 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4644 return; // ignore... - it's a 'hash' to another page.
4646 Roo.log("NavItem - prevent Default?");
4648 this.scrollToElement(e);
4652 var p = this.parent();
4654 if (['tabs','pills'].indexOf(p.type)!==-1) {
4655 if (typeof(p.setActiveItem) !== 'undefined') {
4656 p.setActiveItem(this);
4660 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4661 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4662 // remove the collapsed menu expand...
4663 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4667 isActive: function () {
4670 setActive : function(state, fire, is_was_active)
4672 if (this.active && !state && this.navId) {
4673 this.was_active = true;
4674 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4676 nv.clearWasActive(this);
4680 this.active = state;
4683 this.el.removeClass('active');
4684 } else if (!this.el.hasClass('active')) {
4685 this.el.addClass('active');
4688 this.fireEvent('changed', this, state);
4691 // show a panel if it's registered and related..
4693 if (!this.navId || !this.tabId || !state || is_was_active) {
4697 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4701 var pan = tg.getPanelByName(this.tabId);
4705 // if we can not flip to new panel - go back to old nav highlight..
4706 if (false == tg.showPanel(pan)) {
4707 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4709 var onav = nv.getWasActive();
4711 onav.setActive(true, false, true);
4720 // this should not be here...
4721 setDisabled : function(state)
4723 this.disabled = state;
4725 this.el.removeClass('disabled');
4726 } else if (!this.el.hasClass('disabled')) {
4727 this.el.addClass('disabled');
4733 * Fetch the element to display the tooltip on.
4734 * @return {Roo.Element} defaults to this.el
4736 tooltipEl : function()
4738 return this.el.select('' + this.tagtype + '', true).first();
4741 scrollToElement : function(e)
4743 var c = document.body;
4746 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4748 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4749 c = document.documentElement;
4752 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4758 var o = target.calcOffsetsTo(c);
4765 this.fireEvent('scrollto', this, options, e);
4767 Roo.get(c).scrollTo('top', options.value, true);
4780 * <span> icon </span>
4781 * <span> text </span>
4782 * <span>badge </span>
4786 * @class Roo.bootstrap.NavSidebarItem
4787 * @extends Roo.bootstrap.NavItem
4788 * Bootstrap Navbar.NavSidebarItem class
4789 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4790 * {Boolean} open is the menu open
4791 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4792 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4793 * {String} buttonSize (sm|md|lg)the extra classes for the button
4794 * {Boolean} showArrow show arrow next to the text (default true)
4796 * Create a new Navbar Button
4797 * @param {Object} config The config object
4799 Roo.bootstrap.NavSidebarItem = function(config){
4800 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4805 * The raw click event for the entire grid.
4806 * @param {Roo.EventObject} e
4811 * Fires when the active item active state changes
4812 * @param {Roo.bootstrap.NavSidebarItem} this
4813 * @param {boolean} state the new state
4821 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4823 badgeWeight : 'default',
4829 buttonWeight : 'default',
4835 getAutoCreate : function(){
4840 href : this.href || '#',
4846 if(this.buttonView){
4849 href : this.href || '#',
4850 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4863 cfg.cls += ' active';
4866 if (this.disabled) {
4867 cfg.cls += ' disabled';
4870 cfg.cls += ' open x-open';
4873 if (this.glyphicon || this.icon) {
4874 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4875 a.cn.push({ tag : 'i', cls : c }) ;
4878 if(!this.buttonView){
4881 html : this.html || ''
4888 if (this.badge !== '') {
4889 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4895 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4898 a.cls += ' dropdown-toggle treeview' ;
4904 initEvents : function()
4906 if (typeof (this.menu) != 'undefined') {
4907 this.menu.parentType = this.xtype;
4908 this.menu.triggerEl = this.el;
4909 this.menu = this.addxtype(Roo.apply({}, this.menu));
4912 this.el.on('click', this.onClick, this);
4914 if(this.badge !== ''){
4915 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4920 onClick : function(e)
4927 if(this.preventDefault){
4931 this.fireEvent('click', this);
4934 disable : function()
4936 this.setDisabled(true);
4941 this.setDisabled(false);
4944 setDisabled : function(state)
4946 if(this.disabled == state){
4950 this.disabled = state;
4953 this.el.addClass('disabled');
4957 this.el.removeClass('disabled');
4962 setActive : function(state)
4964 if(this.active == state){
4968 this.active = state;
4971 this.el.addClass('active');
4975 this.el.removeClass('active');
4980 isActive: function ()
4985 setBadge : function(str)
4991 this.badgeEl.dom.innerHTML = str;
5008 * @class Roo.bootstrap.Row
5009 * @extends Roo.bootstrap.Component
5010 * Bootstrap Row class (contains columns...)
5014 * @param {Object} config The config object
5017 Roo.bootstrap.Row = function(config){
5018 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5021 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5023 getAutoCreate : function(){
5042 * @class Roo.bootstrap.Element
5043 * @extends Roo.bootstrap.Component
5044 * Bootstrap Element class
5045 * @cfg {String} html contents of the element
5046 * @cfg {String} tag tag of the element
5047 * @cfg {String} cls class of the element
5048 * @cfg {Boolean} preventDefault (true|false) default false
5049 * @cfg {Boolean} clickable (true|false) default false
5052 * Create a new Element
5053 * @param {Object} config The config object
5056 Roo.bootstrap.Element = function(config){
5057 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5063 * When a element is chick
5064 * @param {Roo.bootstrap.Element} this
5065 * @param {Roo.EventObject} e
5071 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5076 preventDefault: false,
5079 getAutoCreate : function(){
5083 // cls: this.cls, double assign in parent class Component.js :: onRender
5090 initEvents: function()
5092 Roo.bootstrap.Element.superclass.initEvents.call(this);
5095 this.el.on('click', this.onClick, this);
5100 onClick : function(e)
5102 if(this.preventDefault){
5106 this.fireEvent('click', this, e);
5109 getValue : function()
5111 return this.el.dom.innerHTML;
5114 setValue : function(value)
5116 this.el.dom.innerHTML = value;
5131 * @class Roo.bootstrap.Pagination
5132 * @extends Roo.bootstrap.Component
5133 * Bootstrap Pagination class
5134 * @cfg {String} size xs | sm | md | lg
5135 * @cfg {Boolean} inverse false | true
5138 * Create a new Pagination
5139 * @param {Object} config The config object
5142 Roo.bootstrap.Pagination = function(config){
5143 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5146 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5152 getAutoCreate : function(){
5158 cfg.cls += ' inverse';
5164 cfg.cls += " " + this.cls;
5182 * @class Roo.bootstrap.PaginationItem
5183 * @extends Roo.bootstrap.Component
5184 * Bootstrap PaginationItem class
5185 * @cfg {String} html text
5186 * @cfg {String} href the link
5187 * @cfg {Boolean} preventDefault (true | false) default true
5188 * @cfg {Boolean} active (true | false) default false
5189 * @cfg {Boolean} disabled default false
5193 * Create a new PaginationItem
5194 * @param {Object} config The config object
5198 Roo.bootstrap.PaginationItem = function(config){
5199 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5204 * The raw click event for the entire grid.
5205 * @param {Roo.EventObject} e
5211 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5215 preventDefault: true,
5220 getAutoCreate : function(){
5226 href : this.href ? this.href : '#',
5227 html : this.html ? this.html : ''
5237 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5241 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5247 initEvents: function() {
5249 this.el.on('click', this.onClick, this);
5252 onClick : function(e)
5254 Roo.log('PaginationItem on click ');
5255 if(this.preventDefault){
5263 this.fireEvent('click', this, e);
5279 * @class Roo.bootstrap.Slider
5280 * @extends Roo.bootstrap.Component
5281 * Bootstrap Slider class
5284 * Create a new Slider
5285 * @param {Object} config The config object
5288 Roo.bootstrap.Slider = function(config){
5289 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5292 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5294 getAutoCreate : function(){
5298 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5302 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5314 * Ext JS Library 1.1.1
5315 * Copyright(c) 2006-2007, Ext JS, LLC.
5317 * Originally Released Under LGPL - original licence link has changed is not relivant.
5320 * <script type="text/javascript">
5325 * @class Roo.grid.ColumnModel
5326 * @extends Roo.util.Observable
5327 * This is the default implementation of a ColumnModel used by the Grid. It defines
5328 * the columns in the grid.
5331 var colModel = new Roo.grid.ColumnModel([
5332 {header: "Ticker", width: 60, sortable: true, locked: true},
5333 {header: "Company Name", width: 150, sortable: true},
5334 {header: "Market Cap.", width: 100, sortable: true},
5335 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5336 {header: "Employees", width: 100, sortable: true, resizable: false}
5341 * The config options listed for this class are options which may appear in each
5342 * individual column definition.
5343 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5345 * @param {Object} config An Array of column config objects. See this class's
5346 * config objects for details.
5348 Roo.grid.ColumnModel = function(config){
5350 * The config passed into the constructor
5352 this.config = config;
5355 // if no id, create one
5356 // if the column does not have a dataIndex mapping,
5357 // map it to the order it is in the config
5358 for(var i = 0, len = config.length; i < len; i++){
5360 if(typeof c.dataIndex == "undefined"){
5363 if(typeof c.renderer == "string"){
5364 c.renderer = Roo.util.Format[c.renderer];
5366 if(typeof c.id == "undefined"){
5369 if(c.editor && c.editor.xtype){
5370 c.editor = Roo.factory(c.editor, Roo.grid);
5372 if(c.editor && c.editor.isFormField){
5373 c.editor = new Roo.grid.GridEditor(c.editor);
5375 this.lookup[c.id] = c;
5379 * The width of columns which have no width specified (defaults to 100)
5382 this.defaultWidth = 100;
5385 * Default sortable of columns which have no sortable specified (defaults to false)
5388 this.defaultSortable = false;
5392 * @event widthchange
5393 * Fires when the width of a column changes.
5394 * @param {ColumnModel} this
5395 * @param {Number} columnIndex The column index
5396 * @param {Number} newWidth The new width
5398 "widthchange": true,
5400 * @event headerchange
5401 * Fires when the text of a header changes.
5402 * @param {ColumnModel} this
5403 * @param {Number} columnIndex The column index
5404 * @param {Number} newText The new header text
5406 "headerchange": true,
5408 * @event hiddenchange
5409 * Fires when a column is hidden or "unhidden".
5410 * @param {ColumnModel} this
5411 * @param {Number} columnIndex The column index
5412 * @param {Boolean} hidden true if hidden, false otherwise
5414 "hiddenchange": true,
5416 * @event columnmoved
5417 * Fires when a column is moved.
5418 * @param {ColumnModel} this
5419 * @param {Number} oldIndex
5420 * @param {Number} newIndex
5422 "columnmoved" : true,
5424 * @event columlockchange
5425 * Fires when a column's locked state is changed
5426 * @param {ColumnModel} this
5427 * @param {Number} colIndex
5428 * @param {Boolean} locked true if locked
5430 "columnlockchange" : true
5432 Roo.grid.ColumnModel.superclass.constructor.call(this);
5434 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5436 * @cfg {String} header The header text to display in the Grid view.
5439 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5440 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5441 * specified, the column's index is used as an index into the Record's data Array.
5444 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5445 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5448 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5449 * Defaults to the value of the {@link #defaultSortable} property.
5450 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5453 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5456 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5459 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5462 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5465 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5466 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5467 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5468 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5471 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5474 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5477 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5480 * @cfg {String} cursor (Optional)
5483 * @cfg {String} tooltip (Optional)
5486 * @cfg {Number} xs (Optional)
5489 * @cfg {Number} sm (Optional)
5492 * @cfg {Number} md (Optional)
5495 * @cfg {Number} lg (Optional)
5498 * Returns the id of the column at the specified index.
5499 * @param {Number} index The column index
5500 * @return {String} the id
5502 getColumnId : function(index){
5503 return this.config[index].id;
5507 * Returns the column for a specified id.
5508 * @param {String} id The column id
5509 * @return {Object} the column
5511 getColumnById : function(id){
5512 return this.lookup[id];
5517 * Returns the column for a specified dataIndex.
5518 * @param {String} dataIndex The column dataIndex
5519 * @return {Object|Boolean} the column or false if not found
5521 getColumnByDataIndex: function(dataIndex){
5522 var index = this.findColumnIndex(dataIndex);
5523 return index > -1 ? this.config[index] : false;
5527 * Returns the index for a specified column id.
5528 * @param {String} id The column id
5529 * @return {Number} the index, or -1 if not found
5531 getIndexById : function(id){
5532 for(var i = 0, len = this.config.length; i < len; i++){
5533 if(this.config[i].id == id){
5541 * Returns the index for a specified column dataIndex.
5542 * @param {String} dataIndex The column dataIndex
5543 * @return {Number} the index, or -1 if not found
5546 findColumnIndex : function(dataIndex){
5547 for(var i = 0, len = this.config.length; i < len; i++){
5548 if(this.config[i].dataIndex == dataIndex){
5556 moveColumn : function(oldIndex, newIndex){
5557 var c = this.config[oldIndex];
5558 this.config.splice(oldIndex, 1);
5559 this.config.splice(newIndex, 0, c);
5560 this.dataMap = null;
5561 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5564 isLocked : function(colIndex){
5565 return this.config[colIndex].locked === true;
5568 setLocked : function(colIndex, value, suppressEvent){
5569 if(this.isLocked(colIndex) == value){
5572 this.config[colIndex].locked = value;
5574 this.fireEvent("columnlockchange", this, colIndex, value);
5578 getTotalLockedWidth : function(){
5580 for(var i = 0; i < this.config.length; i++){
5581 if(this.isLocked(i) && !this.isHidden(i)){
5582 this.totalWidth += this.getColumnWidth(i);
5588 getLockedCount : function(){
5589 for(var i = 0, len = this.config.length; i < len; i++){
5590 if(!this.isLocked(i)){
5595 return this.config.length;
5599 * Returns the number of columns.
5602 getColumnCount : function(visibleOnly){
5603 if(visibleOnly === true){
5605 for(var i = 0, len = this.config.length; i < len; i++){
5606 if(!this.isHidden(i)){
5612 return this.config.length;
5616 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5617 * @param {Function} fn
5618 * @param {Object} scope (optional)
5619 * @return {Array} result
5621 getColumnsBy : function(fn, scope){
5623 for(var i = 0, len = this.config.length; i < len; i++){
5624 var c = this.config[i];
5625 if(fn.call(scope||this, c, i) === true){
5633 * Returns true if the specified column is sortable.
5634 * @param {Number} col The column index
5637 isSortable : function(col){
5638 if(typeof this.config[col].sortable == "undefined"){
5639 return this.defaultSortable;
5641 return this.config[col].sortable;
5645 * Returns the rendering (formatting) function defined for the column.
5646 * @param {Number} col The column index.
5647 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5649 getRenderer : function(col){
5650 if(!this.config[col].renderer){
5651 return Roo.grid.ColumnModel.defaultRenderer;
5653 return this.config[col].renderer;
5657 * Sets the rendering (formatting) function for a column.
5658 * @param {Number} col The column index
5659 * @param {Function} fn The function to use to process the cell's raw data
5660 * to return HTML markup for the grid view. The render function is called with
5661 * the following parameters:<ul>
5662 * <li>Data value.</li>
5663 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5664 * <li>css A CSS style string to apply to the table cell.</li>
5665 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5666 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5667 * <li>Row index</li>
5668 * <li>Column index</li>
5669 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5671 setRenderer : function(col, fn){
5672 this.config[col].renderer = fn;
5676 * Returns the width for the specified column.
5677 * @param {Number} col The column index
5680 getColumnWidth : function(col){
5681 return this.config[col].width * 1 || this.defaultWidth;
5685 * Sets the width for a column.
5686 * @param {Number} col The column index
5687 * @param {Number} width The new width
5689 setColumnWidth : function(col, width, suppressEvent){
5690 this.config[col].width = width;
5691 this.totalWidth = null;
5693 this.fireEvent("widthchange", this, col, width);
5698 * Returns the total width of all columns.
5699 * @param {Boolean} includeHidden True to include hidden column widths
5702 getTotalWidth : function(includeHidden){
5703 if(!this.totalWidth){
5704 this.totalWidth = 0;
5705 for(var i = 0, len = this.config.length; i < len; i++){
5706 if(includeHidden || !this.isHidden(i)){
5707 this.totalWidth += this.getColumnWidth(i);
5711 return this.totalWidth;
5715 * Returns the header for the specified column.
5716 * @param {Number} col The column index
5719 getColumnHeader : function(col){
5720 return this.config[col].header;
5724 * Sets the header for a column.
5725 * @param {Number} col The column index
5726 * @param {String} header The new header
5728 setColumnHeader : function(col, header){
5729 this.config[col].header = header;
5730 this.fireEvent("headerchange", this, col, header);
5734 * Returns the tooltip for the specified column.
5735 * @param {Number} col The column index
5738 getColumnTooltip : function(col){
5739 return this.config[col].tooltip;
5742 * Sets the tooltip for a column.
5743 * @param {Number} col The column index
5744 * @param {String} tooltip The new tooltip
5746 setColumnTooltip : function(col, tooltip){
5747 this.config[col].tooltip = tooltip;
5751 * Returns the dataIndex for the specified column.
5752 * @param {Number} col The column index
5755 getDataIndex : function(col){
5756 return this.config[col].dataIndex;
5760 * Sets the dataIndex for a column.
5761 * @param {Number} col The column index
5762 * @param {Number} dataIndex The new dataIndex
5764 setDataIndex : function(col, dataIndex){
5765 this.config[col].dataIndex = dataIndex;
5771 * Returns true if the cell is editable.
5772 * @param {Number} colIndex The column index
5773 * @param {Number} rowIndex The row index - this is nto actually used..?
5776 isCellEditable : function(colIndex, rowIndex){
5777 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5781 * Returns the editor defined for the cell/column.
5782 * return false or null to disable editing.
5783 * @param {Number} colIndex The column index
5784 * @param {Number} rowIndex The row index
5787 getCellEditor : function(colIndex, rowIndex){
5788 return this.config[colIndex].editor;
5792 * Sets if a column is editable.
5793 * @param {Number} col The column index
5794 * @param {Boolean} editable True if the column is editable
5796 setEditable : function(col, editable){
5797 this.config[col].editable = editable;
5802 * Returns true if the column is hidden.
5803 * @param {Number} colIndex The column index
5806 isHidden : function(colIndex){
5807 return this.config[colIndex].hidden;
5812 * Returns true if the column width cannot be changed
5814 isFixed : function(colIndex){
5815 return this.config[colIndex].fixed;
5819 * Returns true if the column can be resized
5822 isResizable : function(colIndex){
5823 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5826 * Sets if a column is hidden.
5827 * @param {Number} colIndex The column index
5828 * @param {Boolean} hidden True if the column is hidden
5830 setHidden : function(colIndex, hidden){
5831 this.config[colIndex].hidden = hidden;
5832 this.totalWidth = null;
5833 this.fireEvent("hiddenchange", this, colIndex, hidden);
5837 * Sets the editor for a column.
5838 * @param {Number} col The column index
5839 * @param {Object} editor The editor object
5841 setEditor : function(col, editor){
5842 this.config[col].editor = editor;
5846 Roo.grid.ColumnModel.defaultRenderer = function(value)
5848 if(typeof value == "object") {
5851 if(typeof value == "string" && value.length < 1){
5855 return String.format("{0}", value);
5858 // Alias for backwards compatibility
5859 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5862 * Ext JS Library 1.1.1
5863 * Copyright(c) 2006-2007, Ext JS, LLC.
5865 * Originally Released Under LGPL - original licence link has changed is not relivant.
5868 * <script type="text/javascript">
5872 * @class Roo.LoadMask
5873 * A simple utility class for generically masking elements while loading data. If the element being masked has
5874 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5875 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5876 * element's UpdateManager load indicator and will be destroyed after the initial load.
5878 * Create a new LoadMask
5879 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5880 * @param {Object} config The config object
5882 Roo.LoadMask = function(el, config){
5883 this.el = Roo.get(el);
5884 Roo.apply(this, config);
5886 this.store.on('beforeload', this.onBeforeLoad, this);
5887 this.store.on('load', this.onLoad, this);
5888 this.store.on('loadexception', this.onLoadException, this);
5889 this.removeMask = false;
5891 var um = this.el.getUpdateManager();
5892 um.showLoadIndicator = false; // disable the default indicator
5893 um.on('beforeupdate', this.onBeforeLoad, this);
5894 um.on('update', this.onLoad, this);
5895 um.on('failure', this.onLoad, this);
5896 this.removeMask = true;
5900 Roo.LoadMask.prototype = {
5902 * @cfg {Boolean} removeMask
5903 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5904 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5908 * The text to display in a centered loading message box (defaults to 'Loading...')
5912 * @cfg {String} msgCls
5913 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5915 msgCls : 'x-mask-loading',
5918 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5924 * Disables the mask to prevent it from being displayed
5926 disable : function(){
5927 this.disabled = true;
5931 * Enables the mask so that it can be displayed
5933 enable : function(){
5934 this.disabled = false;
5937 onLoadException : function()
5941 if (typeof(arguments[3]) != 'undefined') {
5942 Roo.MessageBox.alert("Error loading",arguments[3]);
5946 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5947 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5954 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5959 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5963 onBeforeLoad : function(){
5965 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5970 destroy : function(){
5972 this.store.un('beforeload', this.onBeforeLoad, this);
5973 this.store.un('load', this.onLoad, this);
5974 this.store.un('loadexception', this.onLoadException, this);
5976 var um = this.el.getUpdateManager();
5977 um.un('beforeupdate', this.onBeforeLoad, this);
5978 um.un('update', this.onLoad, this);
5979 um.un('failure', this.onLoad, this);
5990 * @class Roo.bootstrap.Table
5991 * @extends Roo.bootstrap.Component
5992 * Bootstrap Table class
5993 * @cfg {String} cls table class
5994 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5995 * @cfg {String} bgcolor Specifies the background color for a table
5996 * @cfg {Number} border Specifies whether the table cells should have borders or not
5997 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5998 * @cfg {Number} cellspacing Specifies the space between cells
5999 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6000 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6001 * @cfg {String} sortable Specifies that the table should be sortable
6002 * @cfg {String} summary Specifies a summary of the content of a table
6003 * @cfg {Number} width Specifies the width of a table
6004 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6006 * @cfg {boolean} striped Should the rows be alternative striped
6007 * @cfg {boolean} bordered Add borders to the table
6008 * @cfg {boolean} hover Add hover highlighting
6009 * @cfg {boolean} condensed Format condensed
6010 * @cfg {boolean} responsive Format condensed
6011 * @cfg {Boolean} loadMask (true|false) default false
6012 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6013 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6014 * @cfg {Boolean} rowSelection (true|false) default false
6015 * @cfg {Boolean} cellSelection (true|false) default false
6016 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6017 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6018 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6019 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6023 * Create a new Table
6024 * @param {Object} config The config object
6027 Roo.bootstrap.Table = function(config){
6028 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6033 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6034 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6035 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6036 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6038 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6040 this.sm.grid = this;
6041 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6042 this.sm = this.selModel;
6043 this.sm.xmodule = this.xmodule || false;
6046 if (this.cm && typeof(this.cm.config) == 'undefined') {
6047 this.colModel = new Roo.grid.ColumnModel(this.cm);
6048 this.cm = this.colModel;
6049 this.cm.xmodule = this.xmodule || false;
6052 this.store= Roo.factory(this.store, Roo.data);
6053 this.ds = this.store;
6054 this.ds.xmodule = this.xmodule || false;
6057 if (this.footer && this.store) {
6058 this.footer.dataSource = this.ds;
6059 this.footer = Roo.factory(this.footer);
6066 * Fires when a cell is clicked
6067 * @param {Roo.bootstrap.Table} this
6068 * @param {Roo.Element} el
6069 * @param {Number} rowIndex
6070 * @param {Number} columnIndex
6071 * @param {Roo.EventObject} e
6075 * @event celldblclick
6076 * Fires when a cell is double clicked
6077 * @param {Roo.bootstrap.Table} this
6078 * @param {Roo.Element} el
6079 * @param {Number} rowIndex
6080 * @param {Number} columnIndex
6081 * @param {Roo.EventObject} e
6083 "celldblclick" : true,
6086 * Fires when a row is clicked
6087 * @param {Roo.bootstrap.Table} this
6088 * @param {Roo.Element} el
6089 * @param {Number} rowIndex
6090 * @param {Roo.EventObject} e
6094 * @event rowdblclick
6095 * Fires when a row is double clicked
6096 * @param {Roo.bootstrap.Table} this
6097 * @param {Roo.Element} el
6098 * @param {Number} rowIndex
6099 * @param {Roo.EventObject} e
6101 "rowdblclick" : true,
6104 * Fires when a mouseover occur
6105 * @param {Roo.bootstrap.Table} this
6106 * @param {Roo.Element} el
6107 * @param {Number} rowIndex
6108 * @param {Number} columnIndex
6109 * @param {Roo.EventObject} e
6114 * Fires when a mouseout occur
6115 * @param {Roo.bootstrap.Table} this
6116 * @param {Roo.Element} el
6117 * @param {Number} rowIndex
6118 * @param {Number} columnIndex
6119 * @param {Roo.EventObject} e
6124 * Fires when a row is rendered, so you can change add a style to it.
6125 * @param {Roo.bootstrap.Table} this
6126 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6130 * @event rowsrendered
6131 * Fires when all the rows have been rendered
6132 * @param {Roo.bootstrap.Table} this
6134 'rowsrendered' : true,
6136 * @event contextmenu
6137 * The raw contextmenu event for the entire grid.
6138 * @param {Roo.EventObject} e
6140 "contextmenu" : true,
6142 * @event rowcontextmenu
6143 * Fires when a row is right clicked
6144 * @param {Roo.bootstrap.Table} this
6145 * @param {Number} rowIndex
6146 * @param {Roo.EventObject} e
6148 "rowcontextmenu" : true,
6150 * @event cellcontextmenu
6151 * Fires when a cell is right clicked
6152 * @param {Roo.bootstrap.Table} this
6153 * @param {Number} rowIndex
6154 * @param {Number} cellIndex
6155 * @param {Roo.EventObject} e
6157 "cellcontextmenu" : true,
6159 * @event headercontextmenu
6160 * Fires when a header is right clicked
6161 * @param {Roo.bootstrap.Table} this
6162 * @param {Number} columnIndex
6163 * @param {Roo.EventObject} e
6165 "headercontextmenu" : true
6169 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6195 rowSelection : false,
6196 cellSelection : false,
6199 // Roo.Element - the tbody
6201 // Roo.Element - thead element
6204 container: false, // used by gridpanel...
6210 auto_hide_footer : false,
6212 getAutoCreate : function()
6214 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6221 if (this.scrollBody) {
6222 cfg.cls += ' table-body-fixed';
6225 cfg.cls += ' table-striped';
6229 cfg.cls += ' table-hover';
6231 if (this.bordered) {
6232 cfg.cls += ' table-bordered';
6234 if (this.condensed) {
6235 cfg.cls += ' table-condensed';
6237 if (this.responsive) {
6238 cfg.cls += ' table-responsive';
6242 cfg.cls+= ' ' +this.cls;
6245 // this lot should be simplifed...
6258 ].forEach(function(k) {
6266 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6269 if(this.store || this.cm){
6270 if(this.headerShow){
6271 cfg.cn.push(this.renderHeader());
6274 cfg.cn.push(this.renderBody());
6276 if(this.footerShow){
6277 cfg.cn.push(this.renderFooter());
6279 // where does this come from?
6280 //cfg.cls+= ' TableGrid';
6283 return { cn : [ cfg ] };
6286 initEvents : function()
6288 if(!this.store || !this.cm){
6291 if (this.selModel) {
6292 this.selModel.initEvents();
6296 //Roo.log('initEvents with ds!!!!');
6298 this.mainBody = this.el.select('tbody', true).first();
6299 this.mainHead = this.el.select('thead', true).first();
6300 this.mainFoot = this.el.select('tfoot', true).first();
6306 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6307 e.on('click', _this.sort, _this);
6310 this.mainBody.on("click", this.onClick, this);
6311 this.mainBody.on("dblclick", this.onDblClick, this);
6313 // why is this done????? = it breaks dialogs??
6314 //this.parent().el.setStyle('position', 'relative');
6318 this.footer.parentId = this.id;
6319 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6322 this.el.select('tfoot tr td').first().addClass('hide');
6327 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6330 this.store.on('load', this.onLoad, this);
6331 this.store.on('beforeload', this.onBeforeLoad, this);
6332 this.store.on('update', this.onUpdate, this);
6333 this.store.on('add', this.onAdd, this);
6334 this.store.on("clear", this.clear, this);
6336 this.el.on("contextmenu", this.onContextMenu, this);
6338 this.mainBody.on('scroll', this.onBodyScroll, this);
6340 this.cm.on("headerchange", this.onHeaderChange, this);
6342 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6346 onContextMenu : function(e, t)
6348 this.processEvent("contextmenu", e);
6351 processEvent : function(name, e)
6353 if (name != 'touchstart' ) {
6354 this.fireEvent(name, e);
6357 var t = e.getTarget();
6359 var cell = Roo.get(t);
6365 if(cell.findParent('tfoot', false, true)){
6369 if(cell.findParent('thead', false, true)){
6371 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6372 cell = Roo.get(t).findParent('th', false, true);
6374 Roo.log("failed to find th in thead?");
6375 Roo.log(e.getTarget());
6380 var cellIndex = cell.dom.cellIndex;
6382 var ename = name == 'touchstart' ? 'click' : name;
6383 this.fireEvent("header" + ename, this, cellIndex, e);
6388 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6389 cell = Roo.get(t).findParent('td', false, true);
6391 Roo.log("failed to find th in tbody?");
6392 Roo.log(e.getTarget());
6397 var row = cell.findParent('tr', false, true);
6398 var cellIndex = cell.dom.cellIndex;
6399 var rowIndex = row.dom.rowIndex - 1;
6403 this.fireEvent("row" + name, this, rowIndex, e);
6407 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6413 onMouseover : function(e, el)
6415 var cell = Roo.get(el);
6421 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6422 cell = cell.findParent('td', false, true);
6425 var row = cell.findParent('tr', false, true);
6426 var cellIndex = cell.dom.cellIndex;
6427 var rowIndex = row.dom.rowIndex - 1; // start from 0
6429 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6433 onMouseout : function(e, el)
6435 var cell = Roo.get(el);
6441 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6442 cell = cell.findParent('td', false, true);
6445 var row = cell.findParent('tr', false, true);
6446 var cellIndex = cell.dom.cellIndex;
6447 var rowIndex = row.dom.rowIndex - 1; // start from 0
6449 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6453 onClick : function(e, el)
6455 var cell = Roo.get(el);
6457 if(!cell || (!this.cellSelection && !this.rowSelection)){
6461 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6462 cell = cell.findParent('td', false, true);
6465 if(!cell || typeof(cell) == 'undefined'){
6469 var row = cell.findParent('tr', false, true);
6471 if(!row || typeof(row) == 'undefined'){
6475 var cellIndex = cell.dom.cellIndex;
6476 var rowIndex = this.getRowIndex(row);
6478 // why??? - should these not be based on SelectionModel?
6479 if(this.cellSelection){
6480 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6483 if(this.rowSelection){
6484 this.fireEvent('rowclick', this, row, rowIndex, e);
6490 onDblClick : function(e,el)
6492 var cell = Roo.get(el);
6494 if(!cell || (!this.cellSelection && !this.rowSelection)){
6498 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6499 cell = cell.findParent('td', false, true);
6502 if(!cell || typeof(cell) == 'undefined'){
6506 var row = cell.findParent('tr', false, true);
6508 if(!row || typeof(row) == 'undefined'){
6512 var cellIndex = cell.dom.cellIndex;
6513 var rowIndex = this.getRowIndex(row);
6515 if(this.cellSelection){
6516 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6519 if(this.rowSelection){
6520 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6524 sort : function(e,el)
6526 var col = Roo.get(el);
6528 if(!col.hasClass('sortable')){
6532 var sort = col.attr('sort');
6535 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6539 this.store.sortInfo = {field : sort, direction : dir};
6542 Roo.log("calling footer first");
6543 this.footer.onClick('first');
6546 this.store.load({ params : { start : 0 } });
6550 renderHeader : function()
6558 this.totalWidth = 0;
6560 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6562 var config = cm.config[i];
6566 cls : 'x-hcol-' + i,
6568 html: cm.getColumnHeader(i)
6573 if(typeof(config.sortable) != 'undefined' && config.sortable){
6575 c.html = '<i class="glyphicon"></i>' + c.html;
6578 if(typeof(config.lgHeader) != 'undefined'){
6579 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6582 if(typeof(config.mdHeader) != 'undefined'){
6583 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6586 if(typeof(config.smHeader) != 'undefined'){
6587 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6590 if(typeof(config.xsHeader) != 'undefined'){
6591 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6598 if(typeof(config.tooltip) != 'undefined'){
6599 c.tooltip = config.tooltip;
6602 if(typeof(config.colspan) != 'undefined'){
6603 c.colspan = config.colspan;
6606 if(typeof(config.hidden) != 'undefined' && config.hidden){
6607 c.style += ' display:none;';
6610 if(typeof(config.dataIndex) != 'undefined'){
6611 c.sort = config.dataIndex;
6616 if(typeof(config.align) != 'undefined' && config.align.length){
6617 c.style += ' text-align:' + config.align + ';';
6620 if(typeof(config.width) != 'undefined'){
6621 c.style += ' width:' + config.width + 'px;';
6622 this.totalWidth += config.width;
6624 this.totalWidth += 100; // assume minimum of 100 per column?
6627 if(typeof(config.cls) != 'undefined'){
6628 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6631 ['xs','sm','md','lg'].map(function(size){
6633 if(typeof(config[size]) == 'undefined'){
6637 if (!config[size]) { // 0 = hidden
6638 c.cls += ' hidden-' + size;
6642 c.cls += ' col-' + size + '-' + config[size];
6652 renderBody : function()
6662 colspan : this.cm.getColumnCount()
6672 renderFooter : function()
6682 colspan : this.cm.getColumnCount()
6696 // Roo.log('ds onload');
6701 var ds = this.store;
6703 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6704 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6705 if (_this.store.sortInfo) {
6707 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6708 e.select('i', true).addClass(['glyphicon-arrow-up']);
6711 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6712 e.select('i', true).addClass(['glyphicon-arrow-down']);
6717 var tbody = this.mainBody;
6719 if(ds.getCount() > 0){
6720 ds.data.each(function(d,rowIndex){
6721 var row = this.renderRow(cm, ds, rowIndex);
6723 tbody.createChild(row);
6727 if(row.cellObjects.length){
6728 Roo.each(row.cellObjects, function(r){
6729 _this.renderCellObject(r);
6736 var tfoot = this.el.select('tfoot', true).first();
6738 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6740 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6742 var total = this.ds.getTotalCount();
6744 if(this.footer.pageSize < total){
6745 this.mainFoot.show();
6749 Roo.each(this.el.select('tbody td', true).elements, function(e){
6750 e.on('mouseover', _this.onMouseover, _this);
6753 Roo.each(this.el.select('tbody td', true).elements, function(e){
6754 e.on('mouseout', _this.onMouseout, _this);
6756 this.fireEvent('rowsrendered', this);
6762 onUpdate : function(ds,record)
6764 this.refreshRow(record);
6768 onRemove : function(ds, record, index, isUpdate){
6769 if(isUpdate !== true){
6770 this.fireEvent("beforerowremoved", this, index, record);
6772 var bt = this.mainBody.dom;
6774 var rows = this.el.select('tbody > tr', true).elements;
6776 if(typeof(rows[index]) != 'undefined'){
6777 bt.removeChild(rows[index].dom);
6780 // if(bt.rows[index]){
6781 // bt.removeChild(bt.rows[index]);
6784 if(isUpdate !== true){
6785 //this.stripeRows(index);
6786 //this.syncRowHeights(index, index);
6788 this.fireEvent("rowremoved", this, index, record);
6792 onAdd : function(ds, records, rowIndex)
6794 //Roo.log('on Add called');
6795 // - note this does not handle multiple adding very well..
6796 var bt = this.mainBody.dom;
6797 for (var i =0 ; i < records.length;i++) {
6798 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6799 //Roo.log(records[i]);
6800 //Roo.log(this.store.getAt(rowIndex+i));
6801 this.insertRow(this.store, rowIndex + i, false);
6808 refreshRow : function(record){
6809 var ds = this.store, index;
6810 if(typeof record == 'number'){
6812 record = ds.getAt(index);
6814 index = ds.indexOf(record);
6816 this.insertRow(ds, index, true);
6818 this.onRemove(ds, record, index+1, true);
6820 //this.syncRowHeights(index, index);
6822 this.fireEvent("rowupdated", this, index, record);
6825 insertRow : function(dm, rowIndex, isUpdate){
6828 this.fireEvent("beforerowsinserted", this, rowIndex);
6830 //var s = this.getScrollState();
6831 var row = this.renderRow(this.cm, this.store, rowIndex);
6832 // insert before rowIndex..
6833 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6837 if(row.cellObjects.length){
6838 Roo.each(row.cellObjects, function(r){
6839 _this.renderCellObject(r);
6844 this.fireEvent("rowsinserted", this, rowIndex);
6845 //this.syncRowHeights(firstRow, lastRow);
6846 //this.stripeRows(firstRow);
6853 getRowDom : function(rowIndex)
6855 var rows = this.el.select('tbody > tr', true).elements;
6857 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6860 // returns the object tree for a tr..
6863 renderRow : function(cm, ds, rowIndex)
6865 var d = ds.getAt(rowIndex);
6869 cls : 'x-row-' + rowIndex,
6873 var cellObjects = [];
6875 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6876 var config = cm.config[i];
6878 var renderer = cm.getRenderer(i);
6882 if(typeof(renderer) !== 'undefined'){
6883 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6885 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6886 // and are rendered into the cells after the row is rendered - using the id for the element.
6888 if(typeof(value) === 'object'){
6898 rowIndex : rowIndex,
6903 this.fireEvent('rowclass', this, rowcfg);
6907 cls : rowcfg.rowClass + ' x-col-' + i,
6909 html: (typeof(value) === 'object') ? '' : value
6916 if(typeof(config.colspan) != 'undefined'){
6917 td.colspan = config.colspan;
6920 if(typeof(config.hidden) != 'undefined' && config.hidden){
6921 td.style += ' display:none;';
6924 if(typeof(config.align) != 'undefined' && config.align.length){
6925 td.style += ' text-align:' + config.align + ';';
6927 if(typeof(config.valign) != 'undefined' && config.valign.length){
6928 td.style += ' vertical-align:' + config.valign + ';';
6931 if(typeof(config.width) != 'undefined'){
6932 td.style += ' width:' + config.width + 'px;';
6935 if(typeof(config.cursor) != 'undefined'){
6936 td.style += ' cursor:' + config.cursor + ';';
6939 if(typeof(config.cls) != 'undefined'){
6940 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6943 ['xs','sm','md','lg'].map(function(size){
6945 if(typeof(config[size]) == 'undefined'){
6949 if (!config[size]) { // 0 = hidden
6950 td.cls += ' hidden-' + size;
6954 td.cls += ' col-' + size + '-' + config[size];
6962 row.cellObjects = cellObjects;
6970 onBeforeLoad : function()
6979 this.el.select('tbody', true).first().dom.innerHTML = '';
6982 * Show or hide a row.
6983 * @param {Number} rowIndex to show or hide
6984 * @param {Boolean} state hide
6986 setRowVisibility : function(rowIndex, state)
6988 var bt = this.mainBody.dom;
6990 var rows = this.el.select('tbody > tr', true).elements;
6992 if(typeof(rows[rowIndex]) == 'undefined'){
6995 rows[rowIndex].dom.style.display = state ? '' : 'none';
6999 getSelectionModel : function(){
7001 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7003 return this.selModel;
7006 * Render the Roo.bootstrap object from renderder
7008 renderCellObject : function(r)
7012 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7014 var t = r.cfg.render(r.container);
7017 Roo.each(r.cfg.cn, function(c){
7019 container: t.getChildContainer(),
7022 _this.renderCellObject(child);
7027 getRowIndex : function(row)
7031 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7042 * Returns the grid's underlying element = used by panel.Grid
7043 * @return {Element} The element
7045 getGridEl : function(){
7049 * Forces a resize - used by panel.Grid
7050 * @return {Element} The element
7052 autoSize : function()
7054 //var ctr = Roo.get(this.container.dom.parentElement);
7055 var ctr = Roo.get(this.el.dom);
7057 var thd = this.getGridEl().select('thead',true).first();
7058 var tbd = this.getGridEl().select('tbody', true).first();
7059 var tfd = this.getGridEl().select('tfoot', true).first();
7061 var cw = ctr.getWidth();
7065 tbd.setSize(ctr.getWidth(),
7066 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7068 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7071 cw = Math.max(cw, this.totalWidth);
7072 this.getGridEl().select('tr',true).setWidth(cw);
7073 // resize 'expandable coloumn?
7075 return; // we doe not have a view in this design..
7078 onBodyScroll: function()
7080 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7082 this.mainHead.setStyle({
7083 'position' : 'relative',
7084 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7090 var scrollHeight = this.mainBody.dom.scrollHeight;
7092 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7094 var height = this.mainBody.getHeight();
7096 if(scrollHeight - height == scrollTop) {
7098 var total = this.ds.getTotalCount();
7100 if(this.footer.cursor + this.footer.pageSize < total){
7102 this.footer.ds.load({
7104 start : this.footer.cursor + this.footer.pageSize,
7105 limit : this.footer.pageSize
7115 onHeaderChange : function()
7117 var header = this.renderHeader();
7118 var table = this.el.select('table', true).first();
7120 this.mainHead.remove();
7121 this.mainHead = table.createChild(header, this.mainBody, false);
7124 onHiddenChange : function(colModel, colIndex, hidden)
7126 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7127 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7129 this.CSS.updateRule(thSelector, "display", "");
7130 this.CSS.updateRule(tdSelector, "display", "");
7133 this.CSS.updateRule(thSelector, "display", "none");
7134 this.CSS.updateRule(tdSelector, "display", "none");
7137 this.onHeaderChange();
7141 setColumnWidth: function(col_index, width)
7143 // width = "md-2 xs-2..."
7144 if(!this.colModel.config[col_index]) {
7148 var w = width.split(" ");
7150 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7152 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7155 for(var j = 0; j < w.length; j++) {
7161 var size_cls = w[j].split("-");
7163 if(!Number.isInteger(size_cls[1] * 1)) {
7167 if(!this.colModel.config[col_index][size_cls[0]]) {
7171 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7175 h_row[0].classList.replace(
7176 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7177 "col-"+size_cls[0]+"-"+size_cls[1]
7180 for(var i = 0; i < rows.length; i++) {
7182 var size_cls = w[j].split("-");
7184 if(!Number.isInteger(size_cls[1] * 1)) {
7188 if(!this.colModel.config[col_index][size_cls[0]]) {
7192 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7196 rows[i].classList.replace(
7197 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7198 "col-"+size_cls[0]+"-"+size_cls[1]
7202 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7217 * @class Roo.bootstrap.TableCell
7218 * @extends Roo.bootstrap.Component
7219 * Bootstrap TableCell class
7220 * @cfg {String} html cell contain text
7221 * @cfg {String} cls cell class
7222 * @cfg {String} tag cell tag (td|th) default td
7223 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7224 * @cfg {String} align Aligns the content in a cell
7225 * @cfg {String} axis Categorizes cells
7226 * @cfg {String} bgcolor Specifies the background color of a cell
7227 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7228 * @cfg {Number} colspan Specifies the number of columns a cell should span
7229 * @cfg {String} headers Specifies one or more header cells a cell is related to
7230 * @cfg {Number} height Sets the height of a cell
7231 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7232 * @cfg {Number} rowspan Sets the number of rows a cell should span
7233 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7234 * @cfg {String} valign Vertical aligns the content in a cell
7235 * @cfg {Number} width Specifies the width of a cell
7238 * Create a new TableCell
7239 * @param {Object} config The config object
7242 Roo.bootstrap.TableCell = function(config){
7243 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7246 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7266 getAutoCreate : function(){
7267 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7287 cfg.align=this.align
7293 cfg.bgcolor=this.bgcolor
7296 cfg.charoff=this.charoff
7299 cfg.colspan=this.colspan
7302 cfg.headers=this.headers
7305 cfg.height=this.height
7308 cfg.nowrap=this.nowrap
7311 cfg.rowspan=this.rowspan
7314 cfg.scope=this.scope
7317 cfg.valign=this.valign
7320 cfg.width=this.width
7339 * @class Roo.bootstrap.TableRow
7340 * @extends Roo.bootstrap.Component
7341 * Bootstrap TableRow class
7342 * @cfg {String} cls row class
7343 * @cfg {String} align Aligns the content in a table row
7344 * @cfg {String} bgcolor Specifies a background color for a table row
7345 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7346 * @cfg {String} valign Vertical aligns the content in a table row
7349 * Create a new TableRow
7350 * @param {Object} config The config object
7353 Roo.bootstrap.TableRow = function(config){
7354 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7357 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7365 getAutoCreate : function(){
7366 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7376 cfg.align = this.align;
7379 cfg.bgcolor = this.bgcolor;
7382 cfg.charoff = this.charoff;
7385 cfg.valign = this.valign;
7403 * @class Roo.bootstrap.TableBody
7404 * @extends Roo.bootstrap.Component
7405 * Bootstrap TableBody class
7406 * @cfg {String} cls element class
7407 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7408 * @cfg {String} align Aligns the content inside the element
7409 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7410 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7413 * Create a new TableBody
7414 * @param {Object} config The config object
7417 Roo.bootstrap.TableBody = function(config){
7418 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7421 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7429 getAutoCreate : function(){
7430 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7444 cfg.align = this.align;
7447 cfg.charoff = this.charoff;
7450 cfg.valign = this.valign;
7457 // initEvents : function()
7464 // this.store = Roo.factory(this.store, Roo.data);
7465 // this.store.on('load', this.onLoad, this);
7467 // this.store.load();
7471 // onLoad: function ()
7473 // this.fireEvent('load', this);
7483 * Ext JS Library 1.1.1
7484 * Copyright(c) 2006-2007, Ext JS, LLC.
7486 * Originally Released Under LGPL - original licence link has changed is not relivant.
7489 * <script type="text/javascript">
7492 // as we use this in bootstrap.
7493 Roo.namespace('Roo.form');
7495 * @class Roo.form.Action
7496 * Internal Class used to handle form actions
7498 * @param {Roo.form.BasicForm} el The form element or its id
7499 * @param {Object} config Configuration options
7504 // define the action interface
7505 Roo.form.Action = function(form, options){
7507 this.options = options || {};
7510 * Client Validation Failed
7513 Roo.form.Action.CLIENT_INVALID = 'client';
7515 * Server Validation Failed
7518 Roo.form.Action.SERVER_INVALID = 'server';
7520 * Connect to Server Failed
7523 Roo.form.Action.CONNECT_FAILURE = 'connect';
7525 * Reading Data from Server Failed
7528 Roo.form.Action.LOAD_FAILURE = 'load';
7530 Roo.form.Action.prototype = {
7532 failureType : undefined,
7533 response : undefined,
7537 run : function(options){
7542 success : function(response){
7547 handleResponse : function(response){
7551 // default connection failure
7552 failure : function(response){
7554 this.response = response;
7555 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7556 this.form.afterAction(this, false);
7559 processResponse : function(response){
7560 this.response = response;
7561 if(!response.responseText){
7564 this.result = this.handleResponse(response);
7568 // utility functions used internally
7569 getUrl : function(appendParams){
7570 var url = this.options.url || this.form.url || this.form.el.dom.action;
7572 var p = this.getParams();
7574 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7580 getMethod : function(){
7581 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7584 getParams : function(){
7585 var bp = this.form.baseParams;
7586 var p = this.options.params;
7588 if(typeof p == "object"){
7589 p = Roo.urlEncode(Roo.applyIf(p, bp));
7590 }else if(typeof p == 'string' && bp){
7591 p += '&' + Roo.urlEncode(bp);
7594 p = Roo.urlEncode(bp);
7599 createCallback : function(){
7601 success: this.success,
7602 failure: this.failure,
7604 timeout: (this.form.timeout*1000),
7605 upload: this.form.fileUpload ? this.success : undefined
7610 Roo.form.Action.Submit = function(form, options){
7611 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7614 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7617 haveProgress : false,
7618 uploadComplete : false,
7620 // uploadProgress indicator.
7621 uploadProgress : function()
7623 if (!this.form.progressUrl) {
7627 if (!this.haveProgress) {
7628 Roo.MessageBox.progress("Uploading", "Uploading");
7630 if (this.uploadComplete) {
7631 Roo.MessageBox.hide();
7635 this.haveProgress = true;
7637 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7639 var c = new Roo.data.Connection();
7641 url : this.form.progressUrl,
7646 success : function(req){
7647 //console.log(data);
7651 rdata = Roo.decode(req.responseText)
7653 Roo.log("Invalid data from server..");
7657 if (!rdata || !rdata.success) {
7659 Roo.MessageBox.alert(Roo.encode(rdata));
7662 var data = rdata.data;
7664 if (this.uploadComplete) {
7665 Roo.MessageBox.hide();
7670 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7671 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7674 this.uploadProgress.defer(2000,this);
7677 failure: function(data) {
7678 Roo.log('progress url failed ');
7689 // run get Values on the form, so it syncs any secondary forms.
7690 this.form.getValues();
7692 var o = this.options;
7693 var method = this.getMethod();
7694 var isPost = method == 'POST';
7695 if(o.clientValidation === false || this.form.isValid()){
7697 if (this.form.progressUrl) {
7698 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7699 (new Date() * 1) + '' + Math.random());
7704 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7705 form:this.form.el.dom,
7706 url:this.getUrl(!isPost),
7708 params:isPost ? this.getParams() : null,
7709 isUpload: this.form.fileUpload
7712 this.uploadProgress();
7714 }else if (o.clientValidation !== false){ // client validation failed
7715 this.failureType = Roo.form.Action.CLIENT_INVALID;
7716 this.form.afterAction(this, false);
7720 success : function(response)
7722 this.uploadComplete= true;
7723 if (this.haveProgress) {
7724 Roo.MessageBox.hide();
7728 var result = this.processResponse(response);
7729 if(result === true || result.success){
7730 this.form.afterAction(this, true);
7734 this.form.markInvalid(result.errors);
7735 this.failureType = Roo.form.Action.SERVER_INVALID;
7737 this.form.afterAction(this, false);
7739 failure : function(response)
7741 this.uploadComplete= true;
7742 if (this.haveProgress) {
7743 Roo.MessageBox.hide();
7746 this.response = response;
7747 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7748 this.form.afterAction(this, false);
7751 handleResponse : function(response){
7752 if(this.form.errorReader){
7753 var rs = this.form.errorReader.read(response);
7756 for(var i = 0, len = rs.records.length; i < len; i++) {
7757 var r = rs.records[i];
7761 if(errors.length < 1){
7765 success : rs.success,
7771 ret = Roo.decode(response.responseText);
7775 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7785 Roo.form.Action.Load = function(form, options){
7786 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7787 this.reader = this.form.reader;
7790 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7795 Roo.Ajax.request(Roo.apply(
7796 this.createCallback(), {
7797 method:this.getMethod(),
7798 url:this.getUrl(false),
7799 params:this.getParams()
7803 success : function(response){
7805 var result = this.processResponse(response);
7806 if(result === true || !result.success || !result.data){
7807 this.failureType = Roo.form.Action.LOAD_FAILURE;
7808 this.form.afterAction(this, false);
7811 this.form.clearInvalid();
7812 this.form.setValues(result.data);
7813 this.form.afterAction(this, true);
7816 handleResponse : function(response){
7817 if(this.form.reader){
7818 var rs = this.form.reader.read(response);
7819 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7821 success : rs.success,
7825 return Roo.decode(response.responseText);
7829 Roo.form.Action.ACTION_TYPES = {
7830 'load' : Roo.form.Action.Load,
7831 'submit' : Roo.form.Action.Submit
7840 * @class Roo.bootstrap.Form
7841 * @extends Roo.bootstrap.Component
7842 * Bootstrap Form class
7843 * @cfg {String} method GET | POST (default POST)
7844 * @cfg {String} labelAlign top | left (default top)
7845 * @cfg {String} align left | right - for navbars
7846 * @cfg {Boolean} loadMask load mask when submit (default true)
7851 * @param {Object} config The config object
7855 Roo.bootstrap.Form = function(config){
7857 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7859 Roo.bootstrap.Form.popover.apply();
7863 * @event clientvalidation
7864 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7865 * @param {Form} this
7866 * @param {Boolean} valid true if the form has passed client-side validation
7868 clientvalidation: true,
7870 * @event beforeaction
7871 * Fires before any action is performed. Return false to cancel the action.
7872 * @param {Form} this
7873 * @param {Action} action The action to be performed
7877 * @event actionfailed
7878 * Fires when an action fails.
7879 * @param {Form} this
7880 * @param {Action} action The action that failed
7882 actionfailed : true,
7884 * @event actioncomplete
7885 * Fires when an action is completed.
7886 * @param {Form} this
7887 * @param {Action} action The action that completed
7889 actioncomplete : true
7893 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7896 * @cfg {String} method
7897 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7902 * The URL to use for form actions if one isn't supplied in the action options.
7905 * @cfg {Boolean} fileUpload
7906 * Set to true if this form is a file upload.
7910 * @cfg {Object} baseParams
7911 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7915 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7919 * @cfg {Sting} align (left|right) for navbar forms
7924 activeAction : null,
7927 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7928 * element by passing it or its id or mask the form itself by passing in true.
7931 waitMsgTarget : false,
7936 * @cfg {Boolean} errorMask (true|false) default false
7941 * @cfg {Number} maskOffset Default 100
7946 * @cfg {Boolean} maskBody
7950 getAutoCreate : function(){
7954 method : this.method || 'POST',
7955 id : this.id || Roo.id(),
7958 if (this.parent().xtype.match(/^Nav/)) {
7959 cfg.cls = 'navbar-form navbar-' + this.align;
7963 if (this.labelAlign == 'left' ) {
7964 cfg.cls += ' form-horizontal';
7970 initEvents : function()
7972 this.el.on('submit', this.onSubmit, this);
7973 // this was added as random key presses on the form where triggering form submit.
7974 this.el.on('keypress', function(e) {
7975 if (e.getCharCode() != 13) {
7978 // we might need to allow it for textareas.. and some other items.
7979 // check e.getTarget().
7981 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7985 Roo.log("keypress blocked");
7993 onSubmit : function(e){
7998 * Returns true if client-side validation on the form is successful.
8001 isValid : function(){
8002 var items = this.getItems();
8006 items.each(function(f){
8012 Roo.log('invalid field: ' + f.name);
8016 if(!target && f.el.isVisible(true)){
8022 if(this.errorMask && !valid){
8023 Roo.bootstrap.Form.popover.mask(this, target);
8030 * Returns true if any fields in this form have changed since their original load.
8033 isDirty : function(){
8035 var items = this.getItems();
8036 items.each(function(f){
8046 * Performs a predefined action (submit or load) or custom actions you define on this form.
8047 * @param {String} actionName The name of the action type
8048 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8049 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8050 * accept other config options):
8052 Property Type Description
8053 ---------------- --------------- ----------------------------------------------------------------------------------
8054 url String The url for the action (defaults to the form's url)
8055 method String The form method to use (defaults to the form's method, or POST if not defined)
8056 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8057 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8058 validate the form on the client (defaults to false)
8060 * @return {BasicForm} this
8062 doAction : function(action, options){
8063 if(typeof action == 'string'){
8064 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8066 if(this.fireEvent('beforeaction', this, action) !== false){
8067 this.beforeAction(action);
8068 action.run.defer(100, action);
8074 beforeAction : function(action){
8075 var o = action.options;
8080 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8082 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8085 // not really supported yet.. ??
8087 //if(this.waitMsgTarget === true){
8088 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8089 //}else if(this.waitMsgTarget){
8090 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8091 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8093 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8099 afterAction : function(action, success){
8100 this.activeAction = null;
8101 var o = action.options;
8106 Roo.get(document.body).unmask();
8112 //if(this.waitMsgTarget === true){
8113 // this.el.unmask();
8114 //}else if(this.waitMsgTarget){
8115 // this.waitMsgTarget.unmask();
8117 // Roo.MessageBox.updateProgress(1);
8118 // Roo.MessageBox.hide();
8125 Roo.callback(o.success, o.scope, [this, action]);
8126 this.fireEvent('actioncomplete', this, action);
8130 // failure condition..
8131 // we have a scenario where updates need confirming.
8132 // eg. if a locking scenario exists..
8133 // we look for { errors : { needs_confirm : true }} in the response.
8135 (typeof(action.result) != 'undefined') &&
8136 (typeof(action.result.errors) != 'undefined') &&
8137 (typeof(action.result.errors.needs_confirm) != 'undefined')
8140 Roo.log("not supported yet");
8143 Roo.MessageBox.confirm(
8144 "Change requires confirmation",
8145 action.result.errorMsg,
8150 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8160 Roo.callback(o.failure, o.scope, [this, action]);
8161 // show an error message if no failed handler is set..
8162 if (!this.hasListener('actionfailed')) {
8163 Roo.log("need to add dialog support");
8165 Roo.MessageBox.alert("Error",
8166 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8167 action.result.errorMsg :
8168 "Saving Failed, please check your entries or try again"
8173 this.fireEvent('actionfailed', this, action);
8178 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8179 * @param {String} id The value to search for
8182 findField : function(id){
8183 var items = this.getItems();
8184 var field = items.get(id);
8186 items.each(function(f){
8187 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8194 return field || null;
8197 * Mark fields in this form invalid in bulk.
8198 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8199 * @return {BasicForm} this
8201 markInvalid : function(errors){
8202 if(errors instanceof Array){
8203 for(var i = 0, len = errors.length; i < len; i++){
8204 var fieldError = errors[i];
8205 var f = this.findField(fieldError.id);
8207 f.markInvalid(fieldError.msg);
8213 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8214 field.markInvalid(errors[id]);
8218 //Roo.each(this.childForms || [], function (f) {
8219 // f.markInvalid(errors);
8226 * Set values for fields in this form in bulk.
8227 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8228 * @return {BasicForm} this
8230 setValues : function(values){
8231 if(values instanceof Array){ // array of objects
8232 for(var i = 0, len = values.length; i < len; i++){
8234 var f = this.findField(v.id);
8236 f.setValue(v.value);
8237 if(this.trackResetOnLoad){
8238 f.originalValue = f.getValue();
8242 }else{ // object hash
8245 if(typeof values[id] != 'function' && (field = this.findField(id))){
8247 if (field.setFromData &&
8249 field.displayField &&
8250 // combos' with local stores can
8251 // be queried via setValue()
8252 // to set their value..
8253 (field.store && !field.store.isLocal)
8257 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8258 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8259 field.setFromData(sd);
8261 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8263 field.setFromData(values);
8266 field.setValue(values[id]);
8270 if(this.trackResetOnLoad){
8271 field.originalValue = field.getValue();
8277 //Roo.each(this.childForms || [], function (f) {
8278 // f.setValues(values);
8285 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8286 * they are returned as an array.
8287 * @param {Boolean} asString
8290 getValues : function(asString){
8291 //if (this.childForms) {
8292 // copy values from the child forms
8293 // Roo.each(this.childForms, function (f) {
8294 // this.setValues(f.getValues());
8300 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8301 if(asString === true){
8304 return Roo.urlDecode(fs);
8308 * Returns the fields in this form as an object with key/value pairs.
8309 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8312 getFieldValues : function(with_hidden)
8314 var items = this.getItems();
8316 items.each(function(f){
8322 var v = f.getValue();
8324 if (f.inputType =='radio') {
8325 if (typeof(ret[f.getName()]) == 'undefined') {
8326 ret[f.getName()] = ''; // empty..
8329 if (!f.el.dom.checked) {
8337 if(f.xtype == 'MoneyField'){
8338 ret[f.currencyName] = f.getCurrency();
8341 // not sure if this supported any more..
8342 if ((typeof(v) == 'object') && f.getRawValue) {
8343 v = f.getRawValue() ; // dates..
8345 // combo boxes where name != hiddenName...
8346 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8347 ret[f.name] = f.getRawValue();
8349 ret[f.getName()] = v;
8356 * Clears all invalid messages in this form.
8357 * @return {BasicForm} this
8359 clearInvalid : function(){
8360 var items = this.getItems();
8362 items.each(function(f){
8371 * @return {BasicForm} this
8374 var items = this.getItems();
8375 items.each(function(f){
8379 Roo.each(this.childForms || [], function (f) {
8387 getItems : function()
8389 var r=new Roo.util.MixedCollection(false, function(o){
8390 return o.id || (o.id = Roo.id());
8392 var iter = function(el) {
8399 Roo.each(el.items,function(e) {
8408 hideFields : function(items)
8410 Roo.each(items, function(i){
8412 var f = this.findField(i);
8423 showFields : function(items)
8425 Roo.each(items, function(i){
8427 var f = this.findField(i);
8440 Roo.apply(Roo.bootstrap.Form, {
8467 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8468 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8469 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8470 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8473 this.maskEl.top.enableDisplayMode("block");
8474 this.maskEl.left.enableDisplayMode("block");
8475 this.maskEl.bottom.enableDisplayMode("block");
8476 this.maskEl.right.enableDisplayMode("block");
8478 this.toolTip = new Roo.bootstrap.Tooltip({
8479 cls : 'roo-form-error-popover',
8481 'left' : ['r-l', [-2,0], 'right'],
8482 'right' : ['l-r', [2,0], 'left'],
8483 'bottom' : ['tl-bl', [0,2], 'top'],
8484 'top' : [ 'bl-tl', [0,-2], 'bottom']
8488 this.toolTip.render(Roo.get(document.body));
8490 this.toolTip.el.enableDisplayMode("block");
8492 Roo.get(document.body).on('click', function(){
8496 Roo.get(document.body).on('touchstart', function(){
8500 this.isApplied = true
8503 mask : function(form, target)
8507 this.target = target;
8509 if(!this.form.errorMask || !target.el){
8513 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8515 Roo.log(scrollable);
8517 var ot = this.target.el.calcOffsetsTo(scrollable);
8519 var scrollTo = ot[1] - this.form.maskOffset;
8521 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8523 scrollable.scrollTo('top', scrollTo);
8525 var box = this.target.el.getBox();
8527 var zIndex = Roo.bootstrap.Modal.zIndex++;
8530 this.maskEl.top.setStyle('position', 'absolute');
8531 this.maskEl.top.setStyle('z-index', zIndex);
8532 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8533 this.maskEl.top.setLeft(0);
8534 this.maskEl.top.setTop(0);
8535 this.maskEl.top.show();
8537 this.maskEl.left.setStyle('position', 'absolute');
8538 this.maskEl.left.setStyle('z-index', zIndex);
8539 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8540 this.maskEl.left.setLeft(0);
8541 this.maskEl.left.setTop(box.y - this.padding);
8542 this.maskEl.left.show();
8544 this.maskEl.bottom.setStyle('position', 'absolute');
8545 this.maskEl.bottom.setStyle('z-index', zIndex);
8546 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8547 this.maskEl.bottom.setLeft(0);
8548 this.maskEl.bottom.setTop(box.bottom + this.padding);
8549 this.maskEl.bottom.show();
8551 this.maskEl.right.setStyle('position', 'absolute');
8552 this.maskEl.right.setStyle('z-index', zIndex);
8553 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8554 this.maskEl.right.setLeft(box.right + this.padding);
8555 this.maskEl.right.setTop(box.y - this.padding);
8556 this.maskEl.right.show();
8558 this.toolTip.bindEl = this.target.el;
8560 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8562 var tip = this.target.blankText;
8564 if(this.target.getValue() !== '' ) {
8566 if (this.target.invalidText.length) {
8567 tip = this.target.invalidText;
8568 } else if (this.target.regexText.length){
8569 tip = this.target.regexText;
8573 this.toolTip.show(tip);
8575 this.intervalID = window.setInterval(function() {
8576 Roo.bootstrap.Form.popover.unmask();
8579 window.onwheel = function(){ return false;};
8581 (function(){ this.isMasked = true; }).defer(500, this);
8587 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8591 this.maskEl.top.setStyle('position', 'absolute');
8592 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8593 this.maskEl.top.hide();
8595 this.maskEl.left.setStyle('position', 'absolute');
8596 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8597 this.maskEl.left.hide();
8599 this.maskEl.bottom.setStyle('position', 'absolute');
8600 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8601 this.maskEl.bottom.hide();
8603 this.maskEl.right.setStyle('position', 'absolute');
8604 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8605 this.maskEl.right.hide();
8607 this.toolTip.hide();
8609 this.toolTip.el.hide();
8611 window.onwheel = function(){ return true;};
8613 if(this.intervalID){
8614 window.clearInterval(this.intervalID);
8615 this.intervalID = false;
8618 this.isMasked = false;
8628 * Ext JS Library 1.1.1
8629 * Copyright(c) 2006-2007, Ext JS, LLC.
8631 * Originally Released Under LGPL - original licence link has changed is not relivant.
8634 * <script type="text/javascript">
8637 * @class Roo.form.VTypes
8638 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8641 Roo.form.VTypes = function(){
8642 // closure these in so they are only created once.
8643 var alpha = /^[a-zA-Z_]+$/;
8644 var alphanum = /^[a-zA-Z0-9_]+$/;
8645 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8646 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8648 // All these messages and functions are configurable
8651 * The function used to validate email addresses
8652 * @param {String} value The email address
8654 'email' : function(v){
8655 return email.test(v);
8658 * The error text to display when the email validation function returns false
8661 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8663 * The keystroke filter mask to be applied on email input
8666 'emailMask' : /[a-z0-9_\.\-@]/i,
8669 * The function used to validate URLs
8670 * @param {String} value The URL
8672 'url' : function(v){
8676 * The error text to display when the url validation function returns false
8679 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8682 * The function used to validate alpha values
8683 * @param {String} value The value
8685 'alpha' : function(v){
8686 return alpha.test(v);
8689 * The error text to display when the alpha validation function returns false
8692 'alphaText' : 'This field should only contain letters and _',
8694 * The keystroke filter mask to be applied on alpha input
8697 'alphaMask' : /[a-z_]/i,
8700 * The function used to validate alphanumeric values
8701 * @param {String} value The value
8703 'alphanum' : function(v){
8704 return alphanum.test(v);
8707 * The error text to display when the alphanumeric validation function returns false
8710 'alphanumText' : 'This field should only contain letters, numbers and _',
8712 * The keystroke filter mask to be applied on alphanumeric input
8715 'alphanumMask' : /[a-z0-9_]/i
8725 * @class Roo.bootstrap.Input
8726 * @extends Roo.bootstrap.Component
8727 * Bootstrap Input class
8728 * @cfg {Boolean} disabled is it disabled
8729 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8730 * @cfg {String} name name of the input
8731 * @cfg {string} fieldLabel - the label associated
8732 * @cfg {string} placeholder - placeholder to put in text.
8733 * @cfg {string} before - input group add on before
8734 * @cfg {string} after - input group add on after
8735 * @cfg {string} size - (lg|sm) or leave empty..
8736 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8737 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8738 * @cfg {Number} md colspan out of 12 for computer-sized screens
8739 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8740 * @cfg {string} value default value of the input
8741 * @cfg {Number} labelWidth set the width of label
8742 * @cfg {Number} labellg set the width of label (1-12)
8743 * @cfg {Number} labelmd set the width of label (1-12)
8744 * @cfg {Number} labelsm set the width of label (1-12)
8745 * @cfg {Number} labelxs set the width of label (1-12)
8746 * @cfg {String} labelAlign (top|left)
8747 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8748 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8749 * @cfg {String} indicatorpos (left|right) default left
8750 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8751 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8753 * @cfg {String} align (left|center|right) Default left
8754 * @cfg {Boolean} forceFeedback (true|false) Default false
8757 * Create a new Input
8758 * @param {Object} config The config object
8761 Roo.bootstrap.Input = function(config){
8763 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8768 * Fires when this field receives input focus.
8769 * @param {Roo.form.Field} this
8774 * Fires when this field loses input focus.
8775 * @param {Roo.form.Field} this
8780 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8781 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8782 * @param {Roo.form.Field} this
8783 * @param {Roo.EventObject} e The event object
8788 * Fires just before the field blurs if the field value has changed.
8789 * @param {Roo.form.Field} this
8790 * @param {Mixed} newValue The new value
8791 * @param {Mixed} oldValue The original value
8796 * Fires after the field has been marked as invalid.
8797 * @param {Roo.form.Field} this
8798 * @param {String} msg The validation message
8803 * Fires after the field has been validated with no errors.
8804 * @param {Roo.form.Field} this
8809 * Fires after the key up
8810 * @param {Roo.form.Field} this
8811 * @param {Roo.EventObject} e The event Object
8817 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8819 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8820 automatic validation (defaults to "keyup").
8822 validationEvent : "keyup",
8824 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8826 validateOnBlur : true,
8828 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8830 validationDelay : 250,
8832 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8834 focusClass : "x-form-focus", // not needed???
8838 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8840 invalidClass : "has-warning",
8843 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8845 validClass : "has-success",
8848 * @cfg {Boolean} hasFeedback (true|false) default true
8853 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8855 invalidFeedbackClass : "glyphicon-warning-sign",
8858 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8860 validFeedbackClass : "glyphicon-ok",
8863 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8865 selectOnFocus : false,
8868 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8872 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8877 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8879 disableKeyFilter : false,
8882 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8886 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8890 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8892 blankText : "Please complete this mandatory field",
8895 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8899 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8901 maxLength : Number.MAX_VALUE,
8903 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8905 minLengthText : "The minimum length for this field is {0}",
8907 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8909 maxLengthText : "The maximum length for this field is {0}",
8913 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8914 * If available, this function will be called only after the basic validators all return true, and will be passed the
8915 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8919 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8920 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8921 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8925 * @cfg {String} regexText -- Depricated - use Invalid Text
8930 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8936 autocomplete: false,
8955 formatedValue : false,
8956 forceFeedback : false,
8958 indicatorpos : 'left',
8968 parentLabelAlign : function()
8971 while (parent.parent()) {
8972 parent = parent.parent();
8973 if (typeof(parent.labelAlign) !='undefined') {
8974 return parent.labelAlign;
8981 getAutoCreate : function()
8983 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8989 if(this.inputType != 'hidden'){
8990 cfg.cls = 'form-group' //input-group
8996 type : this.inputType,
8998 cls : 'form-control',
8999 placeholder : this.placeholder || '',
9000 autocomplete : this.autocomplete || 'new-password'
9003 if(this.capture.length){
9004 input.capture = this.capture;
9007 if(this.accept.length){
9008 input.accept = this.accept + "/*";
9012 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9015 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9016 input.maxLength = this.maxLength;
9019 if (this.disabled) {
9020 input.disabled=true;
9023 if (this.readOnly) {
9024 input.readonly=true;
9028 input.name = this.name;
9032 input.cls += ' input-' + this.size;
9036 ['xs','sm','md','lg'].map(function(size){
9037 if (settings[size]) {
9038 cfg.cls += ' col-' + size + '-' + settings[size];
9042 var inputblock = input;
9046 cls: 'glyphicon form-control-feedback'
9049 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9052 cls : 'has-feedback',
9060 if (this.before || this.after) {
9063 cls : 'input-group',
9067 if (this.before && typeof(this.before) == 'string') {
9069 inputblock.cn.push({
9071 cls : 'roo-input-before input-group-addon',
9075 if (this.before && typeof(this.before) == 'object') {
9076 this.before = Roo.factory(this.before);
9078 inputblock.cn.push({
9080 cls : 'roo-input-before input-group-' +
9081 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9085 inputblock.cn.push(input);
9087 if (this.after && typeof(this.after) == 'string') {
9088 inputblock.cn.push({
9090 cls : 'roo-input-after input-group-addon',
9094 if (this.after && typeof(this.after) == 'object') {
9095 this.after = Roo.factory(this.after);
9097 inputblock.cn.push({
9099 cls : 'roo-input-after input-group-' +
9100 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9104 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9105 inputblock.cls += ' has-feedback';
9106 inputblock.cn.push(feedback);
9110 if (align ==='left' && this.fieldLabel.length) {
9112 cfg.cls += ' roo-form-group-label-left';
9117 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9118 tooltip : 'This field is required'
9123 cls : 'control-label',
9124 html : this.fieldLabel
9135 var labelCfg = cfg.cn[1];
9136 var contentCfg = cfg.cn[2];
9138 if(this.indicatorpos == 'right'){
9143 cls : 'control-label',
9147 html : this.fieldLabel
9151 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9152 tooltip : 'This field is required'
9165 labelCfg = cfg.cn[0];
9166 contentCfg = cfg.cn[1];
9170 if(this.labelWidth > 12){
9171 labelCfg.style = "width: " + this.labelWidth + 'px';
9174 if(this.labelWidth < 13 && this.labelmd == 0){
9175 this.labelmd = this.labelWidth;
9178 if(this.labellg > 0){
9179 labelCfg.cls += ' col-lg-' + this.labellg;
9180 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9183 if(this.labelmd > 0){
9184 labelCfg.cls += ' col-md-' + this.labelmd;
9185 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9188 if(this.labelsm > 0){
9189 labelCfg.cls += ' col-sm-' + this.labelsm;
9190 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9193 if(this.labelxs > 0){
9194 labelCfg.cls += ' col-xs-' + this.labelxs;
9195 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9199 } else if ( this.fieldLabel.length) {
9204 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9205 tooltip : 'This field is required'
9209 //cls : 'input-group-addon',
9210 html : this.fieldLabel
9218 if(this.indicatorpos == 'right'){
9223 //cls : 'input-group-addon',
9224 html : this.fieldLabel
9229 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9230 tooltip : 'This field is required'
9250 if (this.parentType === 'Navbar' && this.parent().bar) {
9251 cfg.cls += ' navbar-form';
9254 if (this.parentType === 'NavGroup') {
9255 cfg.cls += ' navbar-form';
9263 * return the real input element.
9265 inputEl: function ()
9267 return this.el.select('input.form-control',true).first();
9270 tooltipEl : function()
9272 return this.inputEl();
9275 indicatorEl : function()
9277 var indicator = this.el.select('i.roo-required-indicator',true).first();
9287 setDisabled : function(v)
9289 var i = this.inputEl().dom;
9291 i.removeAttribute('disabled');
9295 i.setAttribute('disabled','true');
9297 initEvents : function()
9300 this.inputEl().on("keydown" , this.fireKey, this);
9301 this.inputEl().on("focus", this.onFocus, this);
9302 this.inputEl().on("blur", this.onBlur, this);
9304 this.inputEl().relayEvent('keyup', this);
9306 this.indicator = this.indicatorEl();
9309 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9312 // reference to original value for reset
9313 this.originalValue = this.getValue();
9314 //Roo.form.TextField.superclass.initEvents.call(this);
9315 if(this.validationEvent == 'keyup'){
9316 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9317 this.inputEl().on('keyup', this.filterValidation, this);
9319 else if(this.validationEvent !== false){
9320 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9323 if(this.selectOnFocus){
9324 this.on("focus", this.preFocus, this);
9327 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9328 this.inputEl().on("keypress", this.filterKeys, this);
9330 this.inputEl().relayEvent('keypress', this);
9333 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9334 this.el.on("click", this.autoSize, this);
9337 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9338 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9341 if (typeof(this.before) == 'object') {
9342 this.before.render(this.el.select('.roo-input-before',true).first());
9344 if (typeof(this.after) == 'object') {
9345 this.after.render(this.el.select('.roo-input-after',true).first());
9348 this.inputEl().on('change', this.onChange, this);
9351 filterValidation : function(e){
9352 if(!e.isNavKeyPress()){
9353 this.validationTask.delay(this.validationDelay);
9357 * Validates the field value
9358 * @return {Boolean} True if the value is valid, else false
9360 validate : function(){
9361 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9362 if(this.disabled || this.validateValue(this.getRawValue())){
9373 * Validates a value according to the field's validation rules and marks the field as invalid
9374 * if the validation fails
9375 * @param {Mixed} value The value to validate
9376 * @return {Boolean} True if the value is valid, else false
9378 validateValue : function(value)
9380 if(this.getVisibilityEl().hasClass('hidden')){
9384 if(value.length < 1) { // if it's blank
9385 if(this.allowBlank){
9391 if(value.length < this.minLength){
9394 if(value.length > this.maxLength){
9398 var vt = Roo.form.VTypes;
9399 if(!vt[this.vtype](value, this)){
9403 if(typeof this.validator == "function"){
9404 var msg = this.validator(value);
9408 if (typeof(msg) == 'string') {
9409 this.invalidText = msg;
9413 if(this.regex && !this.regex.test(value)){
9421 fireKey : function(e){
9422 //Roo.log('field ' + e.getKey());
9423 if(e.isNavKeyPress()){
9424 this.fireEvent("specialkey", this, e);
9427 focus : function (selectText){
9429 this.inputEl().focus();
9430 if(selectText === true){
9431 this.inputEl().dom.select();
9437 onFocus : function(){
9438 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9439 // this.el.addClass(this.focusClass);
9442 this.hasFocus = true;
9443 this.startValue = this.getValue();
9444 this.fireEvent("focus", this);
9448 beforeBlur : Roo.emptyFn,
9452 onBlur : function(){
9454 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9455 //this.el.removeClass(this.focusClass);
9457 this.hasFocus = false;
9458 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9461 var v = this.getValue();
9462 if(String(v) !== String(this.startValue)){
9463 this.fireEvent('change', this, v, this.startValue);
9465 this.fireEvent("blur", this);
9468 onChange : function(e)
9470 var v = this.getValue();
9471 if(String(v) !== String(this.startValue)){
9472 this.fireEvent('change', this, v, this.startValue);
9478 * Resets the current field value to the originally loaded value and clears any validation messages
9481 this.setValue(this.originalValue);
9485 * Returns the name of the field
9486 * @return {Mixed} name The name field
9488 getName: function(){
9492 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9493 * @return {Mixed} value The field value
9495 getValue : function(){
9497 var v = this.inputEl().getValue();
9502 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9503 * @return {Mixed} value The field value
9505 getRawValue : function(){
9506 var v = this.inputEl().getValue();
9512 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9513 * @param {Mixed} value The value to set
9515 setRawValue : function(v){
9516 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9519 selectText : function(start, end){
9520 var v = this.getRawValue();
9522 start = start === undefined ? 0 : start;
9523 end = end === undefined ? v.length : end;
9524 var d = this.inputEl().dom;
9525 if(d.setSelectionRange){
9526 d.setSelectionRange(start, end);
9527 }else if(d.createTextRange){
9528 var range = d.createTextRange();
9529 range.moveStart("character", start);
9530 range.moveEnd("character", v.length-end);
9537 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9538 * @param {Mixed} value The value to set
9540 setValue : function(v){
9543 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9549 processValue : function(value){
9550 if(this.stripCharsRe){
9551 var newValue = value.replace(this.stripCharsRe, '');
9552 if(newValue !== value){
9553 this.setRawValue(newValue);
9560 preFocus : function(){
9562 if(this.selectOnFocus){
9563 this.inputEl().dom.select();
9566 filterKeys : function(e){
9568 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9571 var c = e.getCharCode(), cc = String.fromCharCode(c);
9572 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9575 if(!this.maskRe.test(cc)){
9580 * Clear any invalid styles/messages for this field
9582 clearInvalid : function(){
9584 if(!this.el || this.preventMark){ // not rendered
9589 this.el.removeClass(this.invalidClass);
9591 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9593 var feedback = this.el.select('.form-control-feedback', true).first();
9596 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9602 this.indicator.removeClass('visible');
9603 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9606 this.fireEvent('valid', this);
9610 * Mark this field as valid
9612 markValid : function()
9614 if(!this.el || this.preventMark){ // not rendered...
9618 this.el.removeClass([this.invalidClass, this.validClass]);
9620 var feedback = this.el.select('.form-control-feedback', true).first();
9623 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9627 this.indicator.removeClass('visible');
9628 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9635 if(this.allowBlank && !this.getRawValue().length){
9639 this.el.addClass(this.validClass);
9641 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9643 var feedback = this.el.select('.form-control-feedback', true).first();
9646 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9647 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9652 this.fireEvent('valid', this);
9656 * Mark this field as invalid
9657 * @param {String} msg The validation message
9659 markInvalid : function(msg)
9661 if(!this.el || this.preventMark){ // not rendered
9665 this.el.removeClass([this.invalidClass, this.validClass]);
9667 var feedback = this.el.select('.form-control-feedback', true).first();
9670 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9677 if(this.allowBlank && !this.getRawValue().length){
9682 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9683 this.indicator.addClass('visible');
9686 this.el.addClass(this.invalidClass);
9688 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9690 var feedback = this.el.select('.form-control-feedback', true).first();
9693 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9695 if(this.getValue().length || this.forceFeedback){
9696 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9703 this.fireEvent('invalid', this, msg);
9706 SafariOnKeyDown : function(event)
9708 // this is a workaround for a password hang bug on chrome/ webkit.
9709 if (this.inputEl().dom.type != 'password') {
9713 var isSelectAll = false;
9715 if(this.inputEl().dom.selectionEnd > 0){
9716 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9718 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9719 event.preventDefault();
9724 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9726 event.preventDefault();
9727 // this is very hacky as keydown always get's upper case.
9729 var cc = String.fromCharCode(event.getCharCode());
9730 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9734 adjustWidth : function(tag, w){
9735 tag = tag.toLowerCase();
9736 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9737 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9741 if(tag == 'textarea'){
9744 }else if(Roo.isOpera){
9748 if(tag == 'textarea'){
9756 setFieldLabel : function(v)
9763 var ar = this.el.select('label > span',true);
9765 if (ar.elements.length) {
9766 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9767 this.fieldLabel = v;
9771 var br = this.el.select('label',true);
9773 if(br.elements.length) {
9774 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9775 this.fieldLabel = v;
9779 Roo.log('Cannot Found any of label > span || label in input');
9783 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9784 this.fieldLabel = v;
9799 * @class Roo.bootstrap.TextArea
9800 * @extends Roo.bootstrap.Input
9801 * Bootstrap TextArea class
9802 * @cfg {Number} cols Specifies the visible width of a text area
9803 * @cfg {Number} rows Specifies the visible number of lines in a text area
9804 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9805 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9806 * @cfg {string} html text
9809 * Create a new TextArea
9810 * @param {Object} config The config object
9813 Roo.bootstrap.TextArea = function(config){
9814 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9818 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9828 getAutoCreate : function(){
9830 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9836 if(this.inputType != 'hidden'){
9837 cfg.cls = 'form-group' //input-group
9845 value : this.value || '',
9846 html: this.html || '',
9847 cls : 'form-control',
9848 placeholder : this.placeholder || ''
9852 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9853 input.maxLength = this.maxLength;
9857 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9861 input.cols = this.cols;
9864 if (this.readOnly) {
9865 input.readonly = true;
9869 input.name = this.name;
9873 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9877 ['xs','sm','md','lg'].map(function(size){
9878 if (settings[size]) {
9879 cfg.cls += ' col-' + size + '-' + settings[size];
9883 var inputblock = input;
9885 if(this.hasFeedback && !this.allowBlank){
9889 cls: 'glyphicon form-control-feedback'
9893 cls : 'has-feedback',
9902 if (this.before || this.after) {
9905 cls : 'input-group',
9909 inputblock.cn.push({
9911 cls : 'input-group-addon',
9916 inputblock.cn.push(input);
9918 if(this.hasFeedback && !this.allowBlank){
9919 inputblock.cls += ' has-feedback';
9920 inputblock.cn.push(feedback);
9924 inputblock.cn.push({
9926 cls : 'input-group-addon',
9933 if (align ==='left' && this.fieldLabel.length) {
9938 cls : 'control-label',
9939 html : this.fieldLabel
9950 if(this.labelWidth > 12){
9951 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9954 if(this.labelWidth < 13 && this.labelmd == 0){
9955 this.labelmd = this.labelWidth;
9958 if(this.labellg > 0){
9959 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9960 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9963 if(this.labelmd > 0){
9964 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9965 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9968 if(this.labelsm > 0){
9969 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9970 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9973 if(this.labelxs > 0){
9974 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9975 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9978 } else if ( this.fieldLabel.length) {
9983 //cls : 'input-group-addon',
9984 html : this.fieldLabel
10002 if (this.disabled) {
10003 input.disabled=true;
10010 * return the real textarea element.
10012 inputEl: function ()
10014 return this.el.select('textarea.form-control',true).first();
10018 * Clear any invalid styles/messages for this field
10020 clearInvalid : function()
10023 if(!this.el || this.preventMark){ // not rendered
10027 var label = this.el.select('label', true).first();
10028 var icon = this.el.select('i.fa-star', true).first();
10034 this.el.removeClass(this.invalidClass);
10036 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10038 var feedback = this.el.select('.form-control-feedback', true).first();
10041 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10046 this.fireEvent('valid', this);
10050 * Mark this field as valid
10052 markValid : function()
10054 if(!this.el || this.preventMark){ // not rendered
10058 this.el.removeClass([this.invalidClass, this.validClass]);
10060 var feedback = this.el.select('.form-control-feedback', true).first();
10063 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10066 if(this.disabled || this.allowBlank){
10070 var label = this.el.select('label', true).first();
10071 var icon = this.el.select('i.fa-star', true).first();
10077 this.el.addClass(this.validClass);
10079 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10081 var feedback = this.el.select('.form-control-feedback', true).first();
10084 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10085 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10090 this.fireEvent('valid', this);
10094 * Mark this field as invalid
10095 * @param {String} msg The validation message
10097 markInvalid : function(msg)
10099 if(!this.el || this.preventMark){ // not rendered
10103 this.el.removeClass([this.invalidClass, this.validClass]);
10105 var feedback = this.el.select('.form-control-feedback', true).first();
10108 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10111 if(this.disabled || this.allowBlank){
10115 var label = this.el.select('label', true).first();
10116 var icon = this.el.select('i.fa-star', true).first();
10118 if(!this.getValue().length && label && !icon){
10119 this.el.createChild({
10121 cls : 'text-danger fa fa-lg fa-star',
10122 tooltip : 'This field is required',
10123 style : 'margin-right:5px;'
10127 this.el.addClass(this.invalidClass);
10129 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10131 var feedback = this.el.select('.form-control-feedback', true).first();
10134 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10136 if(this.getValue().length || this.forceFeedback){
10137 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10144 this.fireEvent('invalid', this, msg);
10152 * trigger field - base class for combo..
10157 * @class Roo.bootstrap.TriggerField
10158 * @extends Roo.bootstrap.Input
10159 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10160 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10161 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10162 * for which you can provide a custom implementation. For example:
10164 var trigger = new Roo.bootstrap.TriggerField();
10165 trigger.onTriggerClick = myTriggerFn;
10166 trigger.applyTo('my-field');
10169 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10170 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10171 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10172 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10173 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10176 * Create a new TriggerField.
10177 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10178 * to the base TextField)
10180 Roo.bootstrap.TriggerField = function(config){
10181 this.mimicing = false;
10182 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10185 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10187 * @cfg {String} triggerClass A CSS class to apply to the trigger
10190 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10195 * @cfg {Boolean} removable (true|false) special filter default false
10199 /** @cfg {Boolean} grow @hide */
10200 /** @cfg {Number} growMin @hide */
10201 /** @cfg {Number} growMax @hide */
10207 autoSize: Roo.emptyFn,
10211 deferHeight : true,
10214 actionMode : 'wrap',
10219 getAutoCreate : function(){
10221 var align = this.labelAlign || this.parentLabelAlign();
10226 cls: 'form-group' //input-group
10233 type : this.inputType,
10234 cls : 'form-control',
10235 autocomplete: 'new-password',
10236 placeholder : this.placeholder || ''
10240 input.name = this.name;
10243 input.cls += ' input-' + this.size;
10246 if (this.disabled) {
10247 input.disabled=true;
10250 var inputblock = input;
10252 if(this.hasFeedback && !this.allowBlank){
10256 cls: 'glyphicon form-control-feedback'
10259 if(this.removable && !this.editable && !this.tickable){
10261 cls : 'has-feedback',
10267 cls : 'roo-combo-removable-btn close'
10274 cls : 'has-feedback',
10283 if(this.removable && !this.editable && !this.tickable){
10285 cls : 'roo-removable',
10291 cls : 'roo-combo-removable-btn close'
10298 if (this.before || this.after) {
10301 cls : 'input-group',
10305 inputblock.cn.push({
10307 cls : 'input-group-addon',
10312 inputblock.cn.push(input);
10314 if(this.hasFeedback && !this.allowBlank){
10315 inputblock.cls += ' has-feedback';
10316 inputblock.cn.push(feedback);
10320 inputblock.cn.push({
10322 cls : 'input-group-addon',
10335 cls: 'form-hidden-field'
10349 cls: 'form-hidden-field'
10353 cls: 'roo-select2-choices',
10357 cls: 'roo-select2-search-field',
10370 cls: 'roo-select2-container input-group',
10375 // cls: 'typeahead typeahead-long dropdown-menu',
10376 // style: 'display:none'
10381 if(!this.multiple && this.showToggleBtn){
10387 if (this.caret != false) {
10390 cls: 'fa fa-' + this.caret
10397 cls : 'input-group-addon btn dropdown-toggle',
10402 cls: 'combobox-clear',
10416 combobox.cls += ' roo-select2-container-multi';
10419 if (align ==='left' && this.fieldLabel.length) {
10421 cfg.cls += ' roo-form-group-label-left';
10426 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10427 tooltip : 'This field is required'
10432 cls : 'control-label',
10433 html : this.fieldLabel
10445 var labelCfg = cfg.cn[1];
10446 var contentCfg = cfg.cn[2];
10448 if(this.indicatorpos == 'right'){
10453 cls : 'control-label',
10457 html : this.fieldLabel
10461 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10462 tooltip : 'This field is required'
10475 labelCfg = cfg.cn[0];
10476 contentCfg = cfg.cn[1];
10479 if(this.labelWidth > 12){
10480 labelCfg.style = "width: " + this.labelWidth + 'px';
10483 if(this.labelWidth < 13 && this.labelmd == 0){
10484 this.labelmd = this.labelWidth;
10487 if(this.labellg > 0){
10488 labelCfg.cls += ' col-lg-' + this.labellg;
10489 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10492 if(this.labelmd > 0){
10493 labelCfg.cls += ' col-md-' + this.labelmd;
10494 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10497 if(this.labelsm > 0){
10498 labelCfg.cls += ' col-sm-' + this.labelsm;
10499 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10502 if(this.labelxs > 0){
10503 labelCfg.cls += ' col-xs-' + this.labelxs;
10504 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10507 } else if ( this.fieldLabel.length) {
10508 // Roo.log(" label");
10512 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10513 tooltip : 'This field is required'
10517 //cls : 'input-group-addon',
10518 html : this.fieldLabel
10526 if(this.indicatorpos == 'right'){
10534 html : this.fieldLabel
10538 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10539 tooltip : 'This field is required'
10552 // Roo.log(" no label && no align");
10559 ['xs','sm','md','lg'].map(function(size){
10560 if (settings[size]) {
10561 cfg.cls += ' col-' + size + '-' + settings[size];
10572 onResize : function(w, h){
10573 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10574 // if(typeof w == 'number'){
10575 // var x = w - this.trigger.getWidth();
10576 // this.inputEl().setWidth(this.adjustWidth('input', x));
10577 // this.trigger.setStyle('left', x+'px');
10582 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10585 getResizeEl : function(){
10586 return this.inputEl();
10590 getPositionEl : function(){
10591 return this.inputEl();
10595 alignErrorIcon : function(){
10596 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10600 initEvents : function(){
10604 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10605 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10606 if(!this.multiple && this.showToggleBtn){
10607 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10608 if(this.hideTrigger){
10609 this.trigger.setDisplayed(false);
10611 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10615 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10618 if(this.removable && !this.editable && !this.tickable){
10619 var close = this.closeTriggerEl();
10622 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10623 close.on('click', this.removeBtnClick, this, close);
10627 //this.trigger.addClassOnOver('x-form-trigger-over');
10628 //this.trigger.addClassOnClick('x-form-trigger-click');
10631 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10635 closeTriggerEl : function()
10637 var close = this.el.select('.roo-combo-removable-btn', true).first();
10638 return close ? close : false;
10641 removeBtnClick : function(e, h, el)
10643 e.preventDefault();
10645 if(this.fireEvent("remove", this) !== false){
10647 this.fireEvent("afterremove", this)
10651 createList : function()
10653 this.list = Roo.get(document.body).createChild({
10655 cls: 'typeahead typeahead-long dropdown-menu',
10656 style: 'display:none'
10659 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10664 initTrigger : function(){
10669 onDestroy : function(){
10671 this.trigger.removeAllListeners();
10672 // this.trigger.remove();
10675 // this.wrap.remove();
10677 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10681 onFocus : function(){
10682 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10684 if(!this.mimicing){
10685 this.wrap.addClass('x-trigger-wrap-focus');
10686 this.mimicing = true;
10687 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10688 if(this.monitorTab){
10689 this.el.on("keydown", this.checkTab, this);
10696 checkTab : function(e){
10697 if(e.getKey() == e.TAB){
10698 this.triggerBlur();
10703 onBlur : function(){
10708 mimicBlur : function(e, t){
10710 if(!this.wrap.contains(t) && this.validateBlur()){
10711 this.triggerBlur();
10717 triggerBlur : function(){
10718 this.mimicing = false;
10719 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10720 if(this.monitorTab){
10721 this.el.un("keydown", this.checkTab, this);
10723 //this.wrap.removeClass('x-trigger-wrap-focus');
10724 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10728 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10729 validateBlur : function(e, t){
10734 onDisable : function(){
10735 this.inputEl().dom.disabled = true;
10736 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10738 // this.wrap.addClass('x-item-disabled');
10743 onEnable : function(){
10744 this.inputEl().dom.disabled = false;
10745 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10747 // this.el.removeClass('x-item-disabled');
10752 onShow : function(){
10753 var ae = this.getActionEl();
10756 ae.dom.style.display = '';
10757 ae.dom.style.visibility = 'visible';
10763 onHide : function(){
10764 var ae = this.getActionEl();
10765 ae.dom.style.display = 'none';
10769 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10770 * by an implementing function.
10772 * @param {EventObject} e
10774 onTriggerClick : Roo.emptyFn
10778 * Ext JS Library 1.1.1
10779 * Copyright(c) 2006-2007, Ext JS, LLC.
10781 * Originally Released Under LGPL - original licence link has changed is not relivant.
10784 * <script type="text/javascript">
10789 * @class Roo.data.SortTypes
10791 * Defines the default sorting (casting?) comparison functions used when sorting data.
10793 Roo.data.SortTypes = {
10795 * Default sort that does nothing
10796 * @param {Mixed} s The value being converted
10797 * @return {Mixed} The comparison value
10799 none : function(s){
10804 * The regular expression used to strip tags
10808 stripTagsRE : /<\/?[^>]+>/gi,
10811 * Strips all HTML tags to sort on text only
10812 * @param {Mixed} s The value being converted
10813 * @return {String} The comparison value
10815 asText : function(s){
10816 return String(s).replace(this.stripTagsRE, "");
10820 * Strips all HTML tags to sort on text only - Case insensitive
10821 * @param {Mixed} s The value being converted
10822 * @return {String} The comparison value
10824 asUCText : function(s){
10825 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10829 * Case insensitive string
10830 * @param {Mixed} s The value being converted
10831 * @return {String} The comparison value
10833 asUCString : function(s) {
10834 return String(s).toUpperCase();
10839 * @param {Mixed} s The value being converted
10840 * @return {Number} The comparison value
10842 asDate : function(s) {
10846 if(s instanceof Date){
10847 return s.getTime();
10849 return Date.parse(String(s));
10854 * @param {Mixed} s The value being converted
10855 * @return {Float} The comparison value
10857 asFloat : function(s) {
10858 var val = parseFloat(String(s).replace(/,/g, ""));
10867 * @param {Mixed} s The value being converted
10868 * @return {Number} The comparison value
10870 asInt : function(s) {
10871 var val = parseInt(String(s).replace(/,/g, ""));
10879 * Ext JS Library 1.1.1
10880 * Copyright(c) 2006-2007, Ext JS, LLC.
10882 * Originally Released Under LGPL - original licence link has changed is not relivant.
10885 * <script type="text/javascript">
10889 * @class Roo.data.Record
10890 * Instances of this class encapsulate both record <em>definition</em> information, and record
10891 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10892 * to access Records cached in an {@link Roo.data.Store} object.<br>
10894 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10895 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10898 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10900 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10901 * {@link #create}. The parameters are the same.
10902 * @param {Array} data An associative Array of data values keyed by the field name.
10903 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10904 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10905 * not specified an integer id is generated.
10907 Roo.data.Record = function(data, id){
10908 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10913 * Generate a constructor for a specific record layout.
10914 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10915 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10916 * Each field definition object may contain the following properties: <ul>
10917 * <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,
10918 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10919 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10920 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10921 * is being used, then this is a string containing the javascript expression to reference the data relative to
10922 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10923 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10924 * this may be omitted.</p></li>
10925 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10926 * <ul><li>auto (Default, implies no conversion)</li>
10931 * <li>date</li></ul></p></li>
10932 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10933 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10934 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10935 * by the Reader into an object that will be stored in the Record. It is passed the
10936 * following parameters:<ul>
10937 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10939 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10941 * <br>usage:<br><pre><code>
10942 var TopicRecord = Roo.data.Record.create(
10943 {name: 'title', mapping: 'topic_title'},
10944 {name: 'author', mapping: 'username'},
10945 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10946 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10947 {name: 'lastPoster', mapping: 'user2'},
10948 {name: 'excerpt', mapping: 'post_text'}
10951 var myNewRecord = new TopicRecord({
10952 title: 'Do my job please',
10955 lastPost: new Date(),
10956 lastPoster: 'Animal',
10957 excerpt: 'No way dude!'
10959 myStore.add(myNewRecord);
10964 Roo.data.Record.create = function(o){
10965 var f = function(){
10966 f.superclass.constructor.apply(this, arguments);
10968 Roo.extend(f, Roo.data.Record);
10969 var p = f.prototype;
10970 p.fields = new Roo.util.MixedCollection(false, function(field){
10973 for(var i = 0, len = o.length; i < len; i++){
10974 p.fields.add(new Roo.data.Field(o[i]));
10976 f.getField = function(name){
10977 return p.fields.get(name);
10982 Roo.data.Record.AUTO_ID = 1000;
10983 Roo.data.Record.EDIT = 'edit';
10984 Roo.data.Record.REJECT = 'reject';
10985 Roo.data.Record.COMMIT = 'commit';
10987 Roo.data.Record.prototype = {
10989 * Readonly flag - true if this record has been modified.
10998 join : function(store){
10999 this.store = store;
11003 * Set the named field to the specified value.
11004 * @param {String} name The name of the field to set.
11005 * @param {Object} value The value to set the field to.
11007 set : function(name, value){
11008 if(this.data[name] == value){
11012 if(!this.modified){
11013 this.modified = {};
11015 if(typeof this.modified[name] == 'undefined'){
11016 this.modified[name] = this.data[name];
11018 this.data[name] = value;
11019 if(!this.editing && this.store){
11020 this.store.afterEdit(this);
11025 * Get the value of the named field.
11026 * @param {String} name The name of the field to get the value of.
11027 * @return {Object} The value of the field.
11029 get : function(name){
11030 return this.data[name];
11034 beginEdit : function(){
11035 this.editing = true;
11036 this.modified = {};
11040 cancelEdit : function(){
11041 this.editing = false;
11042 delete this.modified;
11046 endEdit : function(){
11047 this.editing = false;
11048 if(this.dirty && this.store){
11049 this.store.afterEdit(this);
11054 * Usually called by the {@link Roo.data.Store} which owns the Record.
11055 * Rejects all changes made to the Record since either creation, or the last commit operation.
11056 * Modified fields are reverted to their original values.
11058 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11059 * of reject operations.
11061 reject : function(){
11062 var m = this.modified;
11064 if(typeof m[n] != "function"){
11065 this.data[n] = m[n];
11068 this.dirty = false;
11069 delete this.modified;
11070 this.editing = false;
11072 this.store.afterReject(this);
11077 * Usually called by the {@link Roo.data.Store} which owns the Record.
11078 * Commits all changes made to the Record since either creation, or the last commit operation.
11080 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11081 * of commit operations.
11083 commit : function(){
11084 this.dirty = false;
11085 delete this.modified;
11086 this.editing = false;
11088 this.store.afterCommit(this);
11093 hasError : function(){
11094 return this.error != null;
11098 clearError : function(){
11103 * Creates a copy of this record.
11104 * @param {String} id (optional) A new record id if you don't want to use this record's id
11107 copy : function(newId) {
11108 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11112 * Ext JS Library 1.1.1
11113 * Copyright(c) 2006-2007, Ext JS, LLC.
11115 * Originally Released Under LGPL - original licence link has changed is not relivant.
11118 * <script type="text/javascript">
11124 * @class Roo.data.Store
11125 * @extends Roo.util.Observable
11126 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11127 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11129 * 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
11130 * has no knowledge of the format of the data returned by the Proxy.<br>
11132 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11133 * instances from the data object. These records are cached and made available through accessor functions.
11135 * Creates a new Store.
11136 * @param {Object} config A config object containing the objects needed for the Store to access data,
11137 * and read the data into Records.
11139 Roo.data.Store = function(config){
11140 this.data = new Roo.util.MixedCollection(false);
11141 this.data.getKey = function(o){
11144 this.baseParams = {};
11146 this.paramNames = {
11151 "multisort" : "_multisort"
11154 if(config && config.data){
11155 this.inlineData = config.data;
11156 delete config.data;
11159 Roo.apply(this, config);
11161 if(this.reader){ // reader passed
11162 this.reader = Roo.factory(this.reader, Roo.data);
11163 this.reader.xmodule = this.xmodule || false;
11164 if(!this.recordType){
11165 this.recordType = this.reader.recordType;
11167 if(this.reader.onMetaChange){
11168 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11172 if(this.recordType){
11173 this.fields = this.recordType.prototype.fields;
11175 this.modified = [];
11179 * @event datachanged
11180 * Fires when the data cache has changed, and a widget which is using this Store
11181 * as a Record cache should refresh its view.
11182 * @param {Store} this
11184 datachanged : true,
11186 * @event metachange
11187 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11188 * @param {Store} this
11189 * @param {Object} meta The JSON metadata
11194 * Fires when Records have been added to the Store
11195 * @param {Store} this
11196 * @param {Roo.data.Record[]} records The array of Records added
11197 * @param {Number} index The index at which the record(s) were added
11202 * Fires when a Record has been removed from the Store
11203 * @param {Store} this
11204 * @param {Roo.data.Record} record The Record that was removed
11205 * @param {Number} index The index at which the record was removed
11210 * Fires when a Record has been updated
11211 * @param {Store} this
11212 * @param {Roo.data.Record} record The Record that was updated
11213 * @param {String} operation The update operation being performed. Value may be one of:
11215 Roo.data.Record.EDIT
11216 Roo.data.Record.REJECT
11217 Roo.data.Record.COMMIT
11223 * Fires when the data cache has been cleared.
11224 * @param {Store} this
11228 * @event beforeload
11229 * Fires before a request is made for a new data object. If the beforeload handler returns false
11230 * the load action will be canceled.
11231 * @param {Store} this
11232 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11236 * @event beforeloadadd
11237 * Fires after a new set of Records has been loaded.
11238 * @param {Store} this
11239 * @param {Roo.data.Record[]} records The Records that were loaded
11240 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11242 beforeloadadd : true,
11245 * Fires after a new set of Records has been loaded, before they are added to the store.
11246 * @param {Store} this
11247 * @param {Roo.data.Record[]} records The Records that were loaded
11248 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11249 * @params {Object} return from reader
11253 * @event loadexception
11254 * Fires if an exception occurs in the Proxy during loading.
11255 * Called with the signature of the Proxy's "loadexception" event.
11256 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11259 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11260 * @param {Object} load options
11261 * @param {Object} jsonData from your request (normally this contains the Exception)
11263 loadexception : true
11267 this.proxy = Roo.factory(this.proxy, Roo.data);
11268 this.proxy.xmodule = this.xmodule || false;
11269 this.relayEvents(this.proxy, ["loadexception"]);
11271 this.sortToggle = {};
11272 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11274 Roo.data.Store.superclass.constructor.call(this);
11276 if(this.inlineData){
11277 this.loadData(this.inlineData);
11278 delete this.inlineData;
11282 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11284 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11285 * without a remote query - used by combo/forms at present.
11289 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11292 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11295 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11296 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11299 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11300 * on any HTTP request
11303 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11306 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11310 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11311 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11313 remoteSort : false,
11316 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11317 * loaded or when a record is removed. (defaults to false).
11319 pruneModifiedRecords : false,
11322 lastOptions : null,
11325 * Add Records to the Store and fires the add event.
11326 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11328 add : function(records){
11329 records = [].concat(records);
11330 for(var i = 0, len = records.length; i < len; i++){
11331 records[i].join(this);
11333 var index = this.data.length;
11334 this.data.addAll(records);
11335 this.fireEvent("add", this, records, index);
11339 * Remove a Record from the Store and fires the remove event.
11340 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11342 remove : function(record){
11343 var index = this.data.indexOf(record);
11344 this.data.removeAt(index);
11346 if(this.pruneModifiedRecords){
11347 this.modified.remove(record);
11349 this.fireEvent("remove", this, record, index);
11353 * Remove all Records from the Store and fires the clear event.
11355 removeAll : function(){
11357 if(this.pruneModifiedRecords){
11358 this.modified = [];
11360 this.fireEvent("clear", this);
11364 * Inserts Records to the Store at the given index and fires the add event.
11365 * @param {Number} index The start index at which to insert the passed Records.
11366 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11368 insert : function(index, records){
11369 records = [].concat(records);
11370 for(var i = 0, len = records.length; i < len; i++){
11371 this.data.insert(index, records[i]);
11372 records[i].join(this);
11374 this.fireEvent("add", this, records, index);
11378 * Get the index within the cache of the passed Record.
11379 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11380 * @return {Number} The index of the passed Record. Returns -1 if not found.
11382 indexOf : function(record){
11383 return this.data.indexOf(record);
11387 * Get the index within the cache of the Record with the passed id.
11388 * @param {String} id The id of the Record to find.
11389 * @return {Number} The index of the Record. Returns -1 if not found.
11391 indexOfId : function(id){
11392 return this.data.indexOfKey(id);
11396 * Get the Record with the specified id.
11397 * @param {String} id The id of the Record to find.
11398 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11400 getById : function(id){
11401 return this.data.key(id);
11405 * Get the Record at the specified index.
11406 * @param {Number} index The index of the Record to find.
11407 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11409 getAt : function(index){
11410 return this.data.itemAt(index);
11414 * Returns a range of Records between specified indices.
11415 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11416 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11417 * @return {Roo.data.Record[]} An array of Records
11419 getRange : function(start, end){
11420 return this.data.getRange(start, end);
11424 storeOptions : function(o){
11425 o = Roo.apply({}, o);
11428 this.lastOptions = o;
11432 * Loads the Record cache from the configured Proxy using the configured Reader.
11434 * If using remote paging, then the first load call must specify the <em>start</em>
11435 * and <em>limit</em> properties in the options.params property to establish the initial
11436 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11438 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11439 * and this call will return before the new data has been loaded. Perform any post-processing
11440 * in a callback function, or in a "load" event handler.</strong>
11442 * @param {Object} options An object containing properties which control loading options:<ul>
11443 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11444 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11445 * passed the following arguments:<ul>
11446 * <li>r : Roo.data.Record[]</li>
11447 * <li>options: Options object from the load call</li>
11448 * <li>success: Boolean success indicator</li></ul></li>
11449 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11450 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11453 load : function(options){
11454 options = options || {};
11455 if(this.fireEvent("beforeload", this, options) !== false){
11456 this.storeOptions(options);
11457 var p = Roo.apply(options.params || {}, this.baseParams);
11458 // if meta was not loaded from remote source.. try requesting it.
11459 if (!this.reader.metaFromRemote) {
11460 p._requestMeta = 1;
11462 if(this.sortInfo && this.remoteSort){
11463 var pn = this.paramNames;
11464 p[pn["sort"]] = this.sortInfo.field;
11465 p[pn["dir"]] = this.sortInfo.direction;
11467 if (this.multiSort) {
11468 var pn = this.paramNames;
11469 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11472 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11477 * Reloads the Record cache from the configured Proxy using the configured Reader and
11478 * the options from the last load operation performed.
11479 * @param {Object} options (optional) An object containing properties which may override the options
11480 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11481 * the most recently used options are reused).
11483 reload : function(options){
11484 this.load(Roo.applyIf(options||{}, this.lastOptions));
11488 // Called as a callback by the Reader during a load operation.
11489 loadRecords : function(o, options, success){
11490 if(!o || success === false){
11491 if(success !== false){
11492 this.fireEvent("load", this, [], options, o);
11494 if(options.callback){
11495 options.callback.call(options.scope || this, [], options, false);
11499 // if data returned failure - throw an exception.
11500 if (o.success === false) {
11501 // show a message if no listener is registered.
11502 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11503 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11505 // loadmask wil be hooked into this..
11506 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11509 var r = o.records, t = o.totalRecords || r.length;
11511 this.fireEvent("beforeloadadd", this, r, options, o);
11513 if(!options || options.add !== true){
11514 if(this.pruneModifiedRecords){
11515 this.modified = [];
11517 for(var i = 0, len = r.length; i < len; i++){
11521 this.data = this.snapshot;
11522 delete this.snapshot;
11525 this.data.addAll(r);
11526 this.totalLength = t;
11528 this.fireEvent("datachanged", this);
11530 this.totalLength = Math.max(t, this.data.length+r.length);
11534 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11536 var e = new Roo.data.Record({});
11538 e.set(this.parent.displayField, this.parent.emptyTitle);
11539 e.set(this.parent.valueField, '');
11544 this.fireEvent("load", this, r, options, o);
11545 if(options.callback){
11546 options.callback.call(options.scope || this, r, options, true);
11552 * Loads data from a passed data block. A Reader which understands the format of the data
11553 * must have been configured in the constructor.
11554 * @param {Object} data The data block from which to read the Records. The format of the data expected
11555 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11556 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11558 loadData : function(o, append){
11559 var r = this.reader.readRecords(o);
11560 this.loadRecords(r, {add: append}, true);
11564 * Gets the number of cached records.
11566 * <em>If using paging, this may not be the total size of the dataset. If the data object
11567 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11568 * the data set size</em>
11570 getCount : function(){
11571 return this.data.length || 0;
11575 * Gets the total number of records in the dataset as returned by the server.
11577 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11578 * the dataset size</em>
11580 getTotalCount : function(){
11581 return this.totalLength || 0;
11585 * Returns the sort state of the Store as an object with two properties:
11587 field {String} The name of the field by which the Records are sorted
11588 direction {String} The sort order, "ASC" or "DESC"
11591 getSortState : function(){
11592 return this.sortInfo;
11596 applySort : function(){
11597 if(this.sortInfo && !this.remoteSort){
11598 var s = this.sortInfo, f = s.field;
11599 var st = this.fields.get(f).sortType;
11600 var fn = function(r1, r2){
11601 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11602 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11604 this.data.sort(s.direction, fn);
11605 if(this.snapshot && this.snapshot != this.data){
11606 this.snapshot.sort(s.direction, fn);
11612 * Sets the default sort column and order to be used by the next load operation.
11613 * @param {String} fieldName The name of the field to sort by.
11614 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11616 setDefaultSort : function(field, dir){
11617 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11621 * Sort the Records.
11622 * If remote sorting is used, the sort is performed on the server, and the cache is
11623 * reloaded. If local sorting is used, the cache is sorted internally.
11624 * @param {String} fieldName The name of the field to sort by.
11625 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11627 sort : function(fieldName, dir){
11628 var f = this.fields.get(fieldName);
11630 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11632 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11633 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11638 this.sortToggle[f.name] = dir;
11639 this.sortInfo = {field: f.name, direction: dir};
11640 if(!this.remoteSort){
11642 this.fireEvent("datachanged", this);
11644 this.load(this.lastOptions);
11649 * Calls the specified function for each of the Records in the cache.
11650 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11651 * Returning <em>false</em> aborts and exits the iteration.
11652 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11654 each : function(fn, scope){
11655 this.data.each(fn, scope);
11659 * Gets all records modified since the last commit. Modified records are persisted across load operations
11660 * (e.g., during paging).
11661 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11663 getModifiedRecords : function(){
11664 return this.modified;
11668 createFilterFn : function(property, value, anyMatch){
11669 if(!value.exec){ // not a regex
11670 value = String(value);
11671 if(value.length == 0){
11674 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11676 return function(r){
11677 return value.test(r.data[property]);
11682 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11683 * @param {String} property A field on your records
11684 * @param {Number} start The record index to start at (defaults to 0)
11685 * @param {Number} end The last record index to include (defaults to length - 1)
11686 * @return {Number} The sum
11688 sum : function(property, start, end){
11689 var rs = this.data.items, v = 0;
11690 start = start || 0;
11691 end = (end || end === 0) ? end : rs.length-1;
11693 for(var i = start; i <= end; i++){
11694 v += (rs[i].data[property] || 0);
11700 * Filter the records by a specified property.
11701 * @param {String} field A field on your records
11702 * @param {String/RegExp} value Either a string that the field
11703 * should start with or a RegExp to test against the field
11704 * @param {Boolean} anyMatch True to match any part not just the beginning
11706 filter : function(property, value, anyMatch){
11707 var fn = this.createFilterFn(property, value, anyMatch);
11708 return fn ? this.filterBy(fn) : this.clearFilter();
11712 * Filter by a function. The specified function will be called with each
11713 * record in this data source. If the function returns true the record is included,
11714 * otherwise it is filtered.
11715 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11716 * @param {Object} scope (optional) The scope of the function (defaults to this)
11718 filterBy : function(fn, scope){
11719 this.snapshot = this.snapshot || this.data;
11720 this.data = this.queryBy(fn, scope||this);
11721 this.fireEvent("datachanged", this);
11725 * Query the records by a specified property.
11726 * @param {String} field A field on your records
11727 * @param {String/RegExp} value Either a string that the field
11728 * should start with or a RegExp to test against the field
11729 * @param {Boolean} anyMatch True to match any part not just the beginning
11730 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11732 query : function(property, value, anyMatch){
11733 var fn = this.createFilterFn(property, value, anyMatch);
11734 return fn ? this.queryBy(fn) : this.data.clone();
11738 * Query by a function. The specified function will be called with each
11739 * record in this data source. If the function returns true the record is included
11741 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11742 * @param {Object} scope (optional) The scope of the function (defaults to this)
11743 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11745 queryBy : function(fn, scope){
11746 var data = this.snapshot || this.data;
11747 return data.filterBy(fn, scope||this);
11751 * Collects unique values for a particular dataIndex from this store.
11752 * @param {String} dataIndex The property to collect
11753 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11754 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11755 * @return {Array} An array of the unique values
11757 collect : function(dataIndex, allowNull, bypassFilter){
11758 var d = (bypassFilter === true && this.snapshot) ?
11759 this.snapshot.items : this.data.items;
11760 var v, sv, r = [], l = {};
11761 for(var i = 0, len = d.length; i < len; i++){
11762 v = d[i].data[dataIndex];
11764 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11773 * Revert to a view of the Record cache with no filtering applied.
11774 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11776 clearFilter : function(suppressEvent){
11777 if(this.snapshot && this.snapshot != this.data){
11778 this.data = this.snapshot;
11779 delete this.snapshot;
11780 if(suppressEvent !== true){
11781 this.fireEvent("datachanged", this);
11787 afterEdit : function(record){
11788 if(this.modified.indexOf(record) == -1){
11789 this.modified.push(record);
11791 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11795 afterReject : function(record){
11796 this.modified.remove(record);
11797 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11801 afterCommit : function(record){
11802 this.modified.remove(record);
11803 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11807 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11808 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11810 commitChanges : function(){
11811 var m = this.modified.slice(0);
11812 this.modified = [];
11813 for(var i = 0, len = m.length; i < len; i++){
11819 * Cancel outstanding changes on all changed records.
11821 rejectChanges : function(){
11822 var m = this.modified.slice(0);
11823 this.modified = [];
11824 for(var i = 0, len = m.length; i < len; i++){
11829 onMetaChange : function(meta, rtype, o){
11830 this.recordType = rtype;
11831 this.fields = rtype.prototype.fields;
11832 delete this.snapshot;
11833 this.sortInfo = meta.sortInfo || this.sortInfo;
11834 this.modified = [];
11835 this.fireEvent('metachange', this, this.reader.meta);
11838 moveIndex : function(data, type)
11840 var index = this.indexOf(data);
11842 var newIndex = index + type;
11846 this.insert(newIndex, data);
11851 * Ext JS Library 1.1.1
11852 * Copyright(c) 2006-2007, Ext JS, LLC.
11854 * Originally Released Under LGPL - original licence link has changed is not relivant.
11857 * <script type="text/javascript">
11861 * @class Roo.data.SimpleStore
11862 * @extends Roo.data.Store
11863 * Small helper class to make creating Stores from Array data easier.
11864 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11865 * @cfg {Array} fields An array of field definition objects, or field name strings.
11866 * @cfg {Array} data The multi-dimensional array of data
11868 * @param {Object} config
11870 Roo.data.SimpleStore = function(config){
11871 Roo.data.SimpleStore.superclass.constructor.call(this, {
11873 reader: new Roo.data.ArrayReader({
11876 Roo.data.Record.create(config.fields)
11878 proxy : new Roo.data.MemoryProxy(config.data)
11882 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11884 * Ext JS Library 1.1.1
11885 * Copyright(c) 2006-2007, Ext JS, LLC.
11887 * Originally Released Under LGPL - original licence link has changed is not relivant.
11890 * <script type="text/javascript">
11895 * @extends Roo.data.Store
11896 * @class Roo.data.JsonStore
11897 * Small helper class to make creating Stores for JSON data easier. <br/>
11899 var store = new Roo.data.JsonStore({
11900 url: 'get-images.php',
11902 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11905 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11906 * JsonReader and HttpProxy (unless inline data is provided).</b>
11907 * @cfg {Array} fields An array of field definition objects, or field name strings.
11909 * @param {Object} config
11911 Roo.data.JsonStore = function(c){
11912 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11913 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11914 reader: new Roo.data.JsonReader(c, c.fields)
11917 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11919 * Ext JS Library 1.1.1
11920 * Copyright(c) 2006-2007, Ext JS, LLC.
11922 * Originally Released Under LGPL - original licence link has changed is not relivant.
11925 * <script type="text/javascript">
11929 Roo.data.Field = function(config){
11930 if(typeof config == "string"){
11931 config = {name: config};
11933 Roo.apply(this, config);
11936 this.type = "auto";
11939 var st = Roo.data.SortTypes;
11940 // named sortTypes are supported, here we look them up
11941 if(typeof this.sortType == "string"){
11942 this.sortType = st[this.sortType];
11945 // set default sortType for strings and dates
11946 if(!this.sortType){
11949 this.sortType = st.asUCString;
11952 this.sortType = st.asDate;
11955 this.sortType = st.none;
11960 var stripRe = /[\$,%]/g;
11962 // prebuilt conversion function for this field, instead of
11963 // switching every time we're reading a value
11965 var cv, dateFormat = this.dateFormat;
11970 cv = function(v){ return v; };
11973 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11977 return v !== undefined && v !== null && v !== '' ?
11978 parseInt(String(v).replace(stripRe, ""), 10) : '';
11983 return v !== undefined && v !== null && v !== '' ?
11984 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11989 cv = function(v){ return v === true || v === "true" || v == 1; };
11996 if(v instanceof Date){
12000 if(dateFormat == "timestamp"){
12001 return new Date(v*1000);
12003 return Date.parseDate(v, dateFormat);
12005 var parsed = Date.parse(v);
12006 return parsed ? new Date(parsed) : null;
12015 Roo.data.Field.prototype = {
12023 * Ext JS Library 1.1.1
12024 * Copyright(c) 2006-2007, Ext JS, LLC.
12026 * Originally Released Under LGPL - original licence link has changed is not relivant.
12029 * <script type="text/javascript">
12032 // Base class for reading structured data from a data source. This class is intended to be
12033 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12036 * @class Roo.data.DataReader
12037 * Base class for reading structured data from a data source. This class is intended to be
12038 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12041 Roo.data.DataReader = function(meta, recordType){
12045 this.recordType = recordType instanceof Array ?
12046 Roo.data.Record.create(recordType) : recordType;
12049 Roo.data.DataReader.prototype = {
12051 * Create an empty record
12052 * @param {Object} data (optional) - overlay some values
12053 * @return {Roo.data.Record} record created.
12055 newRow : function(d) {
12057 this.recordType.prototype.fields.each(function(c) {
12059 case 'int' : da[c.name] = 0; break;
12060 case 'date' : da[c.name] = new Date(); break;
12061 case 'float' : da[c.name] = 0.0; break;
12062 case 'boolean' : da[c.name] = false; break;
12063 default : da[c.name] = ""; break;
12067 return new this.recordType(Roo.apply(da, d));
12072 * Ext JS Library 1.1.1
12073 * Copyright(c) 2006-2007, Ext JS, LLC.
12075 * Originally Released Under LGPL - original licence link has changed is not relivant.
12078 * <script type="text/javascript">
12082 * @class Roo.data.DataProxy
12083 * @extends Roo.data.Observable
12084 * This class is an abstract base class for implementations which provide retrieval of
12085 * unformatted data objects.<br>
12087 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12088 * (of the appropriate type which knows how to parse the data object) to provide a block of
12089 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12091 * Custom implementations must implement the load method as described in
12092 * {@link Roo.data.HttpProxy#load}.
12094 Roo.data.DataProxy = function(){
12097 * @event beforeload
12098 * Fires before a network request is made to retrieve a data object.
12099 * @param {Object} This DataProxy object.
12100 * @param {Object} params The params parameter to the load function.
12105 * Fires before the load method's callback is called.
12106 * @param {Object} This DataProxy object.
12107 * @param {Object} o The data object.
12108 * @param {Object} arg The callback argument object passed to the load function.
12112 * @event loadexception
12113 * Fires if an Exception occurs during data retrieval.
12114 * @param {Object} This DataProxy object.
12115 * @param {Object} o The data object.
12116 * @param {Object} arg The callback argument object passed to the load function.
12117 * @param {Object} e The Exception.
12119 loadexception : true
12121 Roo.data.DataProxy.superclass.constructor.call(this);
12124 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12127 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12131 * Ext JS Library 1.1.1
12132 * Copyright(c) 2006-2007, Ext JS, LLC.
12134 * Originally Released Under LGPL - original licence link has changed is not relivant.
12137 * <script type="text/javascript">
12140 * @class Roo.data.MemoryProxy
12141 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12142 * to the Reader when its load method is called.
12144 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12146 Roo.data.MemoryProxy = function(data){
12150 Roo.data.MemoryProxy.superclass.constructor.call(this);
12154 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12157 * Load data from the requested source (in this case an in-memory
12158 * data object passed to the constructor), read the data object into
12159 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12160 * process that block using the passed callback.
12161 * @param {Object} params This parameter is not used by the MemoryProxy class.
12162 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12163 * object into a block of Roo.data.Records.
12164 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12165 * The function must be passed <ul>
12166 * <li>The Record block object</li>
12167 * <li>The "arg" argument from the load function</li>
12168 * <li>A boolean success indicator</li>
12170 * @param {Object} scope The scope in which to call the callback
12171 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12173 load : function(params, reader, callback, scope, arg){
12174 params = params || {};
12177 result = reader.readRecords(this.data);
12179 this.fireEvent("loadexception", this, arg, null, e);
12180 callback.call(scope, null, arg, false);
12183 callback.call(scope, result, arg, true);
12187 update : function(params, records){
12192 * Ext JS Library 1.1.1
12193 * Copyright(c) 2006-2007, Ext JS, LLC.
12195 * Originally Released Under LGPL - original licence link has changed is not relivant.
12198 * <script type="text/javascript">
12201 * @class Roo.data.HttpProxy
12202 * @extends Roo.data.DataProxy
12203 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12204 * configured to reference a certain URL.<br><br>
12206 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12207 * from which the running page was served.<br><br>
12209 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12211 * Be aware that to enable the browser to parse an XML document, the server must set
12212 * the Content-Type header in the HTTP response to "text/xml".
12214 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12215 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12216 * will be used to make the request.
12218 Roo.data.HttpProxy = function(conn){
12219 Roo.data.HttpProxy.superclass.constructor.call(this);
12220 // is conn a conn config or a real conn?
12222 this.useAjax = !conn || !conn.events;
12226 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12227 // thse are take from connection...
12230 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12233 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12234 * extra parameters to each request made by this object. (defaults to undefined)
12237 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12238 * to each request made by this object. (defaults to undefined)
12241 * @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)
12244 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12247 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12253 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12257 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12258 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12259 * a finer-grained basis than the DataProxy events.
12261 getConnection : function(){
12262 return this.useAjax ? Roo.Ajax : this.conn;
12266 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12267 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12268 * process that block using the passed callback.
12269 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12270 * for the request to the remote server.
12271 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12272 * object into a block of Roo.data.Records.
12273 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12274 * The function must be passed <ul>
12275 * <li>The Record block object</li>
12276 * <li>The "arg" argument from the load function</li>
12277 * <li>A boolean success indicator</li>
12279 * @param {Object} scope The scope in which to call the callback
12280 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12282 load : function(params, reader, callback, scope, arg){
12283 if(this.fireEvent("beforeload", this, params) !== false){
12285 params : params || {},
12287 callback : callback,
12292 callback : this.loadResponse,
12296 Roo.applyIf(o, this.conn);
12297 if(this.activeRequest){
12298 Roo.Ajax.abort(this.activeRequest);
12300 this.activeRequest = Roo.Ajax.request(o);
12302 this.conn.request(o);
12305 callback.call(scope||this, null, arg, false);
12310 loadResponse : function(o, success, response){
12311 delete this.activeRequest;
12313 this.fireEvent("loadexception", this, o, response);
12314 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12319 result = o.reader.read(response);
12321 this.fireEvent("loadexception", this, o, response, e);
12322 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12326 this.fireEvent("load", this, o, o.request.arg);
12327 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12331 update : function(dataSet){
12336 updateResponse : function(dataSet){
12341 * Ext JS Library 1.1.1
12342 * Copyright(c) 2006-2007, Ext JS, LLC.
12344 * Originally Released Under LGPL - original licence link has changed is not relivant.
12347 * <script type="text/javascript">
12351 * @class Roo.data.ScriptTagProxy
12352 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12353 * other than the originating domain of the running page.<br><br>
12355 * <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
12356 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12358 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12359 * source code that is used as the source inside a <script> tag.<br><br>
12361 * In order for the browser to process the returned data, the server must wrap the data object
12362 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12363 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12364 * depending on whether the callback name was passed:
12367 boolean scriptTag = false;
12368 String cb = request.getParameter("callback");
12371 response.setContentType("text/javascript");
12373 response.setContentType("application/x-json");
12375 Writer out = response.getWriter();
12377 out.write(cb + "(");
12379 out.print(dataBlock.toJsonString());
12386 * @param {Object} config A configuration object.
12388 Roo.data.ScriptTagProxy = function(config){
12389 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12390 Roo.apply(this, config);
12391 this.head = document.getElementsByTagName("head")[0];
12394 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12396 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12398 * @cfg {String} url The URL from which to request the data object.
12401 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12405 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12406 * the server the name of the callback function set up by the load call to process the returned data object.
12407 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12408 * javascript output which calls this named function passing the data object as its only parameter.
12410 callbackParam : "callback",
12412 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12413 * name to the request.
12418 * Load data from the configured URL, read the data object into
12419 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12420 * process that block using the passed callback.
12421 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12422 * for the request to the remote server.
12423 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12424 * object into a block of Roo.data.Records.
12425 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12426 * The function must be passed <ul>
12427 * <li>The Record block object</li>
12428 * <li>The "arg" argument from the load function</li>
12429 * <li>A boolean success indicator</li>
12431 * @param {Object} scope The scope in which to call the callback
12432 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12434 load : function(params, reader, callback, scope, arg){
12435 if(this.fireEvent("beforeload", this, params) !== false){
12437 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12439 var url = this.url;
12440 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12442 url += "&_dc=" + (new Date().getTime());
12444 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12447 cb : "stcCallback"+transId,
12448 scriptId : "stcScript"+transId,
12452 callback : callback,
12458 window[trans.cb] = function(o){
12459 conn.handleResponse(o, trans);
12462 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12464 if(this.autoAbort !== false){
12468 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12470 var script = document.createElement("script");
12471 script.setAttribute("src", url);
12472 script.setAttribute("type", "text/javascript");
12473 script.setAttribute("id", trans.scriptId);
12474 this.head.appendChild(script);
12476 this.trans = trans;
12478 callback.call(scope||this, null, arg, false);
12483 isLoading : function(){
12484 return this.trans ? true : false;
12488 * Abort the current server request.
12490 abort : function(){
12491 if(this.isLoading()){
12492 this.destroyTrans(this.trans);
12497 destroyTrans : function(trans, isLoaded){
12498 this.head.removeChild(document.getElementById(trans.scriptId));
12499 clearTimeout(trans.timeoutId);
12501 window[trans.cb] = undefined;
12503 delete window[trans.cb];
12506 // if hasn't been loaded, wait for load to remove it to prevent script error
12507 window[trans.cb] = function(){
12508 window[trans.cb] = undefined;
12510 delete window[trans.cb];
12517 handleResponse : function(o, trans){
12518 this.trans = false;
12519 this.destroyTrans(trans, true);
12522 result = trans.reader.readRecords(o);
12524 this.fireEvent("loadexception", this, o, trans.arg, e);
12525 trans.callback.call(trans.scope||window, null, trans.arg, false);
12528 this.fireEvent("load", this, o, trans.arg);
12529 trans.callback.call(trans.scope||window, result, trans.arg, true);
12533 handleFailure : function(trans){
12534 this.trans = false;
12535 this.destroyTrans(trans, false);
12536 this.fireEvent("loadexception", this, null, trans.arg);
12537 trans.callback.call(trans.scope||window, null, trans.arg, false);
12541 * Ext JS Library 1.1.1
12542 * Copyright(c) 2006-2007, Ext JS, LLC.
12544 * Originally Released Under LGPL - original licence link has changed is not relivant.
12547 * <script type="text/javascript">
12551 * @class Roo.data.JsonReader
12552 * @extends Roo.data.DataReader
12553 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12554 * based on mappings in a provided Roo.data.Record constructor.
12556 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12557 * in the reply previously.
12562 var RecordDef = Roo.data.Record.create([
12563 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12564 {name: 'occupation'} // This field will use "occupation" as the mapping.
12566 var myReader = new Roo.data.JsonReader({
12567 totalProperty: "results", // The property which contains the total dataset size (optional)
12568 root: "rows", // The property which contains an Array of row objects
12569 id: "id" // The property within each row object that provides an ID for the record (optional)
12573 * This would consume a JSON file like this:
12575 { 'results': 2, 'rows': [
12576 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12577 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12580 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12581 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12582 * paged from the remote server.
12583 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12584 * @cfg {String} root name of the property which contains the Array of row objects.
12585 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12586 * @cfg {Array} fields Array of field definition objects
12588 * Create a new JsonReader
12589 * @param {Object} meta Metadata configuration options
12590 * @param {Object} recordType Either an Array of field definition objects,
12591 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12593 Roo.data.JsonReader = function(meta, recordType){
12596 // set some defaults:
12597 Roo.applyIf(meta, {
12598 totalProperty: 'total',
12599 successProperty : 'success',
12604 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12606 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12609 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12610 * Used by Store query builder to append _requestMeta to params.
12613 metaFromRemote : false,
12615 * This method is only used by a DataProxy which has retrieved data from a remote server.
12616 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12617 * @return {Object} data A data block which is used by an Roo.data.Store object as
12618 * a cache of Roo.data.Records.
12620 read : function(response){
12621 var json = response.responseText;
12623 var o = /* eval:var:o */ eval("("+json+")");
12625 throw {message: "JsonReader.read: Json object not found"};
12631 this.metaFromRemote = true;
12632 this.meta = o.metaData;
12633 this.recordType = Roo.data.Record.create(o.metaData.fields);
12634 this.onMetaChange(this.meta, this.recordType, o);
12636 return this.readRecords(o);
12639 // private function a store will implement
12640 onMetaChange : function(meta, recordType, o){
12647 simpleAccess: function(obj, subsc) {
12654 getJsonAccessor: function(){
12656 return function(expr) {
12658 return(re.test(expr))
12659 ? new Function("obj", "return obj." + expr)
12664 return Roo.emptyFn;
12669 * Create a data block containing Roo.data.Records from an XML document.
12670 * @param {Object} o An object which contains an Array of row objects in the property specified
12671 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12672 * which contains the total size of the dataset.
12673 * @return {Object} data A data block which is used by an Roo.data.Store object as
12674 * a cache of Roo.data.Records.
12676 readRecords : function(o){
12678 * After any data loads, the raw JSON data is available for further custom processing.
12682 var s = this.meta, Record = this.recordType,
12683 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12685 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12687 if(s.totalProperty) {
12688 this.getTotal = this.getJsonAccessor(s.totalProperty);
12690 if(s.successProperty) {
12691 this.getSuccess = this.getJsonAccessor(s.successProperty);
12693 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12695 var g = this.getJsonAccessor(s.id);
12696 this.getId = function(rec) {
12698 return (r === undefined || r === "") ? null : r;
12701 this.getId = function(){return null;};
12704 for(var jj = 0; jj < fl; jj++){
12706 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12707 this.ef[jj] = this.getJsonAccessor(map);
12711 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12712 if(s.totalProperty){
12713 var vt = parseInt(this.getTotal(o), 10);
12718 if(s.successProperty){
12719 var vs = this.getSuccess(o);
12720 if(vs === false || vs === 'false'){
12725 for(var i = 0; i < c; i++){
12728 var id = this.getId(n);
12729 for(var j = 0; j < fl; j++){
12731 var v = this.ef[j](n);
12733 Roo.log('missing convert for ' + f.name);
12737 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12739 var record = new Record(values, id);
12741 records[i] = record;
12747 totalRecords : totalRecords
12752 * Ext JS Library 1.1.1
12753 * Copyright(c) 2006-2007, Ext JS, LLC.
12755 * Originally Released Under LGPL - original licence link has changed is not relivant.
12758 * <script type="text/javascript">
12762 * @class Roo.data.ArrayReader
12763 * @extends Roo.data.DataReader
12764 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12765 * Each element of that Array represents a row of data fields. The
12766 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12767 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12771 var RecordDef = Roo.data.Record.create([
12772 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12773 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12775 var myReader = new Roo.data.ArrayReader({
12776 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12780 * This would consume an Array like this:
12782 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12784 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12786 * Create a new JsonReader
12787 * @param {Object} meta Metadata configuration options.
12788 * @param {Object} recordType Either an Array of field definition objects
12789 * as specified to {@link Roo.data.Record#create},
12790 * or an {@link Roo.data.Record} object
12791 * created using {@link Roo.data.Record#create}.
12793 Roo.data.ArrayReader = function(meta, recordType){
12794 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12797 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12799 * Create a data block containing Roo.data.Records from an XML document.
12800 * @param {Object} o An Array of row objects which represents the dataset.
12801 * @return {Object} data A data block which is used by an Roo.data.Store object as
12802 * a cache of Roo.data.Records.
12804 readRecords : function(o){
12805 var sid = this.meta ? this.meta.id : null;
12806 var recordType = this.recordType, fields = recordType.prototype.fields;
12809 for(var i = 0; i < root.length; i++){
12812 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12813 for(var j = 0, jlen = fields.length; j < jlen; j++){
12814 var f = fields.items[j];
12815 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12816 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12818 values[f.name] = v;
12820 var record = new recordType(values, id);
12822 records[records.length] = record;
12826 totalRecords : records.length
12835 * @class Roo.bootstrap.ComboBox
12836 * @extends Roo.bootstrap.TriggerField
12837 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12838 * @cfg {Boolean} append (true|false) default false
12839 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12840 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12841 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12842 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12843 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12844 * @cfg {Boolean} animate default true
12845 * @cfg {Boolean} emptyResultText only for touch device
12846 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12847 * @cfg {String} emptyTitle default ''
12849 * Create a new ComboBox.
12850 * @param {Object} config Configuration options
12852 Roo.bootstrap.ComboBox = function(config){
12853 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12857 * Fires when the dropdown list is expanded
12858 * @param {Roo.bootstrap.ComboBox} combo This combo box
12863 * Fires when the dropdown list is collapsed
12864 * @param {Roo.bootstrap.ComboBox} combo This combo box
12868 * @event beforeselect
12869 * Fires before a list item is selected. Return false to cancel the selection.
12870 * @param {Roo.bootstrap.ComboBox} combo This combo box
12871 * @param {Roo.data.Record} record The data record returned from the underlying store
12872 * @param {Number} index The index of the selected item in the dropdown list
12874 'beforeselect' : true,
12877 * Fires when a list item is selected
12878 * @param {Roo.bootstrap.ComboBox} combo This combo box
12879 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12880 * @param {Number} index The index of the selected item in the dropdown list
12884 * @event beforequery
12885 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12886 * The event object passed has these properties:
12887 * @param {Roo.bootstrap.ComboBox} combo This combo box
12888 * @param {String} query The query
12889 * @param {Boolean} forceAll true to force "all" query
12890 * @param {Boolean} cancel true to cancel the query
12891 * @param {Object} e The query event object
12893 'beforequery': true,
12896 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12897 * @param {Roo.bootstrap.ComboBox} combo This combo box
12902 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12903 * @param {Roo.bootstrap.ComboBox} combo This combo box
12904 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12909 * Fires when the remove value from the combobox array
12910 * @param {Roo.bootstrap.ComboBox} combo This combo box
12914 * @event afterremove
12915 * Fires when the remove value from the combobox array
12916 * @param {Roo.bootstrap.ComboBox} combo This combo box
12918 'afterremove' : true,
12920 * @event specialfilter
12921 * Fires when specialfilter
12922 * @param {Roo.bootstrap.ComboBox} combo This combo box
12924 'specialfilter' : true,
12927 * Fires when tick the element
12928 * @param {Roo.bootstrap.ComboBox} combo This combo box
12932 * @event touchviewdisplay
12933 * Fires when touch view require special display (default is using displayField)
12934 * @param {Roo.bootstrap.ComboBox} combo This combo box
12935 * @param {Object} cfg set html .
12937 'touchviewdisplay' : true
12942 this.tickItems = [];
12944 this.selectedIndex = -1;
12945 if(this.mode == 'local'){
12946 if(config.queryDelay === undefined){
12947 this.queryDelay = 10;
12949 if(config.minChars === undefined){
12955 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12958 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12959 * rendering into an Roo.Editor, defaults to false)
12962 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12963 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12966 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12969 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12970 * the dropdown list (defaults to undefined, with no header element)
12974 * @cfg {String/Roo.Template} tpl The template to use to render the output
12978 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12980 listWidth: undefined,
12982 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12983 * mode = 'remote' or 'text' if mode = 'local')
12985 displayField: undefined,
12988 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12989 * mode = 'remote' or 'value' if mode = 'local').
12990 * Note: use of a valueField requires the user make a selection
12991 * in order for a value to be mapped.
12993 valueField: undefined,
12995 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13000 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13001 * field's data value (defaults to the underlying DOM element's name)
13003 hiddenName: undefined,
13005 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13009 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13011 selectedClass: 'active',
13014 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13018 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13019 * anchor positions (defaults to 'tl-bl')
13021 listAlign: 'tl-bl?',
13023 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13027 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13028 * query specified by the allQuery config option (defaults to 'query')
13030 triggerAction: 'query',
13032 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13033 * (defaults to 4, does not apply if editable = false)
13037 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13038 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13042 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13043 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13047 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13048 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13052 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13053 * when editable = true (defaults to false)
13055 selectOnFocus:false,
13057 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13059 queryParam: 'query',
13061 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13062 * when mode = 'remote' (defaults to 'Loading...')
13064 loadingText: 'Loading...',
13066 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13070 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13074 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13075 * traditional select (defaults to true)
13079 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13083 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13087 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13088 * listWidth has a higher value)
13092 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13093 * allow the user to set arbitrary text into the field (defaults to false)
13095 forceSelection:false,
13097 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13098 * if typeAhead = true (defaults to 250)
13100 typeAheadDelay : 250,
13102 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13103 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13105 valueNotFoundText : undefined,
13107 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13109 blockFocus : false,
13112 * @cfg {Boolean} disableClear Disable showing of clear button.
13114 disableClear : false,
13116 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13118 alwaysQuery : false,
13121 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13126 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13128 invalidClass : "has-warning",
13131 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13133 validClass : "has-success",
13136 * @cfg {Boolean} specialFilter (true|false) special filter default false
13138 specialFilter : false,
13141 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13143 mobileTouchView : true,
13146 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13148 useNativeIOS : false,
13151 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13153 mobile_restrict_height : false,
13155 ios_options : false,
13167 btnPosition : 'right',
13168 triggerList : true,
13169 showToggleBtn : true,
13171 emptyResultText: 'Empty',
13172 triggerText : 'Select',
13175 // element that contains real text value.. (when hidden is used..)
13177 getAutoCreate : function()
13182 * Render classic select for iso
13185 if(Roo.isIOS && this.useNativeIOS){
13186 cfg = this.getAutoCreateNativeIOS();
13194 if(Roo.isTouch && this.mobileTouchView){
13195 cfg = this.getAutoCreateTouchView();
13202 if(!this.tickable){
13203 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13208 * ComboBox with tickable selections
13211 var align = this.labelAlign || this.parentLabelAlign();
13214 cls : 'form-group roo-combobox-tickable' //input-group
13217 var btn_text_select = '';
13218 var btn_text_done = '';
13219 var btn_text_cancel = '';
13221 if (this.btn_text_show) {
13222 btn_text_select = 'Select';
13223 btn_text_done = 'Done';
13224 btn_text_cancel = 'Cancel';
13229 cls : 'tickable-buttons',
13234 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13235 //html : this.triggerText
13236 html: btn_text_select
13242 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13244 html: btn_text_done
13250 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13252 html: btn_text_cancel
13258 buttons.cn.unshift({
13260 cls: 'roo-select2-search-field-input'
13266 Roo.each(buttons.cn, function(c){
13268 c.cls += ' btn-' + _this.size;
13271 if (_this.disabled) {
13282 cls: 'form-hidden-field'
13286 cls: 'roo-select2-choices',
13290 cls: 'roo-select2-search-field',
13301 cls: 'roo-select2-container input-group roo-select2-container-multi',
13306 // cls: 'typeahead typeahead-long dropdown-menu',
13307 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13312 if(this.hasFeedback && !this.allowBlank){
13316 cls: 'glyphicon form-control-feedback'
13319 combobox.cn.push(feedback);
13323 if (align ==='left' && this.fieldLabel.length) {
13325 cfg.cls += ' roo-form-group-label-left';
13330 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13331 tooltip : 'This field is required'
13336 cls : 'control-label',
13337 html : this.fieldLabel
13349 var labelCfg = cfg.cn[1];
13350 var contentCfg = cfg.cn[2];
13353 if(this.indicatorpos == 'right'){
13359 cls : 'control-label',
13363 html : this.fieldLabel
13367 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13368 tooltip : 'This field is required'
13383 labelCfg = cfg.cn[0];
13384 contentCfg = cfg.cn[1];
13388 if(this.labelWidth > 12){
13389 labelCfg.style = "width: " + this.labelWidth + 'px';
13392 if(this.labelWidth < 13 && this.labelmd == 0){
13393 this.labelmd = this.labelWidth;
13396 if(this.labellg > 0){
13397 labelCfg.cls += ' col-lg-' + this.labellg;
13398 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13401 if(this.labelmd > 0){
13402 labelCfg.cls += ' col-md-' + this.labelmd;
13403 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13406 if(this.labelsm > 0){
13407 labelCfg.cls += ' col-sm-' + this.labelsm;
13408 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13411 if(this.labelxs > 0){
13412 labelCfg.cls += ' col-xs-' + this.labelxs;
13413 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13417 } else if ( this.fieldLabel.length) {
13418 // Roo.log(" label");
13422 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13423 tooltip : 'This field is required'
13427 //cls : 'input-group-addon',
13428 html : this.fieldLabel
13433 if(this.indicatorpos == 'right'){
13437 //cls : 'input-group-addon',
13438 html : this.fieldLabel
13442 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13443 tooltip : 'This field is required'
13452 // Roo.log(" no label && no align");
13459 ['xs','sm','md','lg'].map(function(size){
13460 if (settings[size]) {
13461 cfg.cls += ' col-' + size + '-' + settings[size];
13469 _initEventsCalled : false,
13472 initEvents: function()
13474 if (this._initEventsCalled) { // as we call render... prevent looping...
13477 this._initEventsCalled = true;
13480 throw "can not find store for combo";
13483 this.indicator = this.indicatorEl();
13485 this.store = Roo.factory(this.store, Roo.data);
13486 this.store.parent = this;
13488 // if we are building from html. then this element is so complex, that we can not really
13489 // use the rendered HTML.
13490 // so we have to trash and replace the previous code.
13491 if (Roo.XComponent.build_from_html) {
13492 // remove this element....
13493 var e = this.el.dom, k=0;
13494 while (e ) { e = e.previousSibling; ++k;}
13499 this.rendered = false;
13501 this.render(this.parent().getChildContainer(true), k);
13504 if(Roo.isIOS && this.useNativeIOS){
13505 this.initIOSView();
13513 if(Roo.isTouch && this.mobileTouchView){
13514 this.initTouchView();
13519 this.initTickableEvents();
13523 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13525 if(this.hiddenName){
13527 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13529 this.hiddenField.dom.value =
13530 this.hiddenValue !== undefined ? this.hiddenValue :
13531 this.value !== undefined ? this.value : '';
13533 // prevent input submission
13534 this.el.dom.removeAttribute('name');
13535 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13540 // this.el.dom.setAttribute('autocomplete', 'off');
13543 var cls = 'x-combo-list';
13545 //this.list = new Roo.Layer({
13546 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13552 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13553 _this.list.setWidth(lw);
13556 this.list.on('mouseover', this.onViewOver, this);
13557 this.list.on('mousemove', this.onViewMove, this);
13558 this.list.on('scroll', this.onViewScroll, this);
13561 this.list.swallowEvent('mousewheel');
13562 this.assetHeight = 0;
13565 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13566 this.assetHeight += this.header.getHeight();
13569 this.innerList = this.list.createChild({cls:cls+'-inner'});
13570 this.innerList.on('mouseover', this.onViewOver, this);
13571 this.innerList.on('mousemove', this.onViewMove, this);
13572 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13574 if(this.allowBlank && !this.pageSize && !this.disableClear){
13575 this.footer = this.list.createChild({cls:cls+'-ft'});
13576 this.pageTb = new Roo.Toolbar(this.footer);
13580 this.footer = this.list.createChild({cls:cls+'-ft'});
13581 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13582 {pageSize: this.pageSize});
13586 if (this.pageTb && this.allowBlank && !this.disableClear) {
13588 this.pageTb.add(new Roo.Toolbar.Fill(), {
13589 cls: 'x-btn-icon x-btn-clear',
13591 handler: function()
13594 _this.clearValue();
13595 _this.onSelect(false, -1);
13600 this.assetHeight += this.footer.getHeight();
13605 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13608 this.view = new Roo.View(this.list, this.tpl, {
13609 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13611 //this.view.wrapEl.setDisplayed(false);
13612 this.view.on('click', this.onViewClick, this);
13615 this.store.on('beforeload', this.onBeforeLoad, this);
13616 this.store.on('load', this.onLoad, this);
13617 this.store.on('loadexception', this.onLoadException, this);
13619 if(this.resizable){
13620 this.resizer = new Roo.Resizable(this.list, {
13621 pinned:true, handles:'se'
13623 this.resizer.on('resize', function(r, w, h){
13624 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13625 this.listWidth = w;
13626 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13627 this.restrictHeight();
13629 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13632 if(!this.editable){
13633 this.editable = true;
13634 this.setEditable(false);
13639 if (typeof(this.events.add.listeners) != 'undefined') {
13641 this.addicon = this.wrap.createChild(
13642 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13644 this.addicon.on('click', function(e) {
13645 this.fireEvent('add', this);
13648 if (typeof(this.events.edit.listeners) != 'undefined') {
13650 this.editicon = this.wrap.createChild(
13651 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13652 if (this.addicon) {
13653 this.editicon.setStyle('margin-left', '40px');
13655 this.editicon.on('click', function(e) {
13657 // we fire even if inothing is selected..
13658 this.fireEvent('edit', this, this.lastData );
13664 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13665 "up" : function(e){
13666 this.inKeyMode = true;
13670 "down" : function(e){
13671 if(!this.isExpanded()){
13672 this.onTriggerClick();
13674 this.inKeyMode = true;
13679 "enter" : function(e){
13680 // this.onViewClick();
13684 if(this.fireEvent("specialkey", this, e)){
13685 this.onViewClick(false);
13691 "esc" : function(e){
13695 "tab" : function(e){
13698 if(this.fireEvent("specialkey", this, e)){
13699 this.onViewClick(false);
13707 doRelay : function(foo, bar, hname){
13708 if(hname == 'down' || this.scope.isExpanded()){
13709 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13718 this.queryDelay = Math.max(this.queryDelay || 10,
13719 this.mode == 'local' ? 10 : 250);
13722 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13724 if(this.typeAhead){
13725 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13727 if(this.editable !== false){
13728 this.inputEl().on("keyup", this.onKeyUp, this);
13730 if(this.forceSelection){
13731 this.inputEl().on('blur', this.doForce, this);
13735 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13736 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13740 initTickableEvents: function()
13744 if(this.hiddenName){
13746 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13748 this.hiddenField.dom.value =
13749 this.hiddenValue !== undefined ? this.hiddenValue :
13750 this.value !== undefined ? this.value : '';
13752 // prevent input submission
13753 this.el.dom.removeAttribute('name');
13754 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13759 // this.list = this.el.select('ul.dropdown-menu',true).first();
13761 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13762 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13763 if(this.triggerList){
13764 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13767 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13768 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13770 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13771 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13773 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13774 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13776 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13777 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13778 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13781 this.cancelBtn.hide();
13786 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13787 _this.list.setWidth(lw);
13790 this.list.on('mouseover', this.onViewOver, this);
13791 this.list.on('mousemove', this.onViewMove, this);
13793 this.list.on('scroll', this.onViewScroll, this);
13796 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13797 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13800 this.view = new Roo.View(this.list, this.tpl, {
13805 selectedClass: this.selectedClass
13808 //this.view.wrapEl.setDisplayed(false);
13809 this.view.on('click', this.onViewClick, this);
13813 this.store.on('beforeload', this.onBeforeLoad, this);
13814 this.store.on('load', this.onLoad, this);
13815 this.store.on('loadexception', this.onLoadException, this);
13818 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13819 "up" : function(e){
13820 this.inKeyMode = true;
13824 "down" : function(e){
13825 this.inKeyMode = true;
13829 "enter" : function(e){
13830 if(this.fireEvent("specialkey", this, e)){
13831 this.onViewClick(false);
13837 "esc" : function(e){
13838 this.onTickableFooterButtonClick(e, false, false);
13841 "tab" : function(e){
13842 this.fireEvent("specialkey", this, e);
13844 this.onTickableFooterButtonClick(e, false, false);
13851 doRelay : function(e, fn, key){
13852 if(this.scope.isExpanded()){
13853 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13862 this.queryDelay = Math.max(this.queryDelay || 10,
13863 this.mode == 'local' ? 10 : 250);
13866 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13868 if(this.typeAhead){
13869 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13872 if(this.editable !== false){
13873 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13876 this.indicator = this.indicatorEl();
13878 if(this.indicator){
13879 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13880 this.indicator.hide();
13885 onDestroy : function(){
13887 this.view.setStore(null);
13888 this.view.el.removeAllListeners();
13889 this.view.el.remove();
13890 this.view.purgeListeners();
13893 this.list.dom.innerHTML = '';
13897 this.store.un('beforeload', this.onBeforeLoad, this);
13898 this.store.un('load', this.onLoad, this);
13899 this.store.un('loadexception', this.onLoadException, this);
13901 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13905 fireKey : function(e){
13906 if(e.isNavKeyPress() && !this.list.isVisible()){
13907 this.fireEvent("specialkey", this, e);
13912 onResize: function(w, h){
13913 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13915 // if(typeof w != 'number'){
13916 // // we do not handle it!?!?
13919 // var tw = this.trigger.getWidth();
13920 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13921 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13923 // this.inputEl().setWidth( this.adjustWidth('input', x));
13925 // //this.trigger.setStyle('left', x+'px');
13927 // if(this.list && this.listWidth === undefined){
13928 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13929 // this.list.setWidth(lw);
13930 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13938 * Allow or prevent the user from directly editing the field text. If false is passed,
13939 * the user will only be able to select from the items defined in the dropdown list. This method
13940 * is the runtime equivalent of setting the 'editable' config option at config time.
13941 * @param {Boolean} value True to allow the user to directly edit the field text
13943 setEditable : function(value){
13944 if(value == this.editable){
13947 this.editable = value;
13949 this.inputEl().dom.setAttribute('readOnly', true);
13950 this.inputEl().on('mousedown', this.onTriggerClick, this);
13951 this.inputEl().addClass('x-combo-noedit');
13953 this.inputEl().dom.setAttribute('readOnly', false);
13954 this.inputEl().un('mousedown', this.onTriggerClick, this);
13955 this.inputEl().removeClass('x-combo-noedit');
13961 onBeforeLoad : function(combo,opts){
13962 if(!this.hasFocus){
13966 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13968 this.restrictHeight();
13969 this.selectedIndex = -1;
13973 onLoad : function(){
13975 this.hasQuery = false;
13977 if(!this.hasFocus){
13981 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13982 this.loading.hide();
13985 if(this.store.getCount() > 0){
13988 this.restrictHeight();
13989 if(this.lastQuery == this.allQuery){
13990 if(this.editable && !this.tickable){
13991 this.inputEl().dom.select();
13995 !this.selectByValue(this.value, true) &&
13998 !this.store.lastOptions ||
13999 typeof(this.store.lastOptions.add) == 'undefined' ||
14000 this.store.lastOptions.add != true
14003 this.select(0, true);
14006 if(this.autoFocus){
14009 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14010 this.taTask.delay(this.typeAheadDelay);
14014 this.onEmptyResults();
14020 onLoadException : function()
14022 this.hasQuery = false;
14024 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14025 this.loading.hide();
14028 if(this.tickable && this.editable){
14033 // only causes errors at present
14034 //Roo.log(this.store.reader.jsonData);
14035 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14037 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14043 onTypeAhead : function(){
14044 if(this.store.getCount() > 0){
14045 var r = this.store.getAt(0);
14046 var newValue = r.data[this.displayField];
14047 var len = newValue.length;
14048 var selStart = this.getRawValue().length;
14050 if(selStart != len){
14051 this.setRawValue(newValue);
14052 this.selectText(selStart, newValue.length);
14058 onSelect : function(record, index){
14060 if(this.fireEvent('beforeselect', this, record, index) !== false){
14062 this.setFromData(index > -1 ? record.data : false);
14065 this.fireEvent('select', this, record, index);
14070 * Returns the currently selected field value or empty string if no value is set.
14071 * @return {String} value The selected value
14073 getValue : function()
14075 if(Roo.isIOS && this.useNativeIOS){
14076 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14080 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14083 if(this.valueField){
14084 return typeof this.value != 'undefined' ? this.value : '';
14086 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14090 getRawValue : function()
14092 if(Roo.isIOS && this.useNativeIOS){
14093 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14096 var v = this.inputEl().getValue();
14102 * Clears any text/value currently set in the field
14104 clearValue : function(){
14106 if(this.hiddenField){
14107 this.hiddenField.dom.value = '';
14110 this.setRawValue('');
14111 this.lastSelectionText = '';
14112 this.lastData = false;
14114 var close = this.closeTriggerEl();
14125 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14126 * will be displayed in the field. If the value does not match the data value of an existing item,
14127 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14128 * Otherwise the field will be blank (although the value will still be set).
14129 * @param {String} value The value to match
14131 setValue : function(v)
14133 if(Roo.isIOS && this.useNativeIOS){
14134 this.setIOSValue(v);
14144 if(this.valueField){
14145 var r = this.findRecord(this.valueField, v);
14147 text = r.data[this.displayField];
14148 }else if(this.valueNotFoundText !== undefined){
14149 text = this.valueNotFoundText;
14152 this.lastSelectionText = text;
14153 if(this.hiddenField){
14154 this.hiddenField.dom.value = v;
14156 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14159 var close = this.closeTriggerEl();
14162 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14168 * @property {Object} the last set data for the element
14173 * Sets the value of the field based on a object which is related to the record format for the store.
14174 * @param {Object} value the value to set as. or false on reset?
14176 setFromData : function(o){
14183 var dv = ''; // display value
14184 var vv = ''; // value value..
14186 if (this.displayField) {
14187 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14189 // this is an error condition!!!
14190 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14193 if(this.valueField){
14194 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14197 var close = this.closeTriggerEl();
14200 if(dv.length || vv * 1 > 0){
14202 this.blockFocus=true;
14208 if(this.hiddenField){
14209 this.hiddenField.dom.value = vv;
14211 this.lastSelectionText = dv;
14212 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14216 // no hidden field.. - we store the value in 'value', but still display
14217 // display field!!!!
14218 this.lastSelectionText = dv;
14219 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14226 reset : function(){
14227 // overridden so that last data is reset..
14234 this.setValue(this.originalValue);
14235 //this.clearInvalid();
14236 this.lastData = false;
14238 this.view.clearSelections();
14244 findRecord : function(prop, value){
14246 if(this.store.getCount() > 0){
14247 this.store.each(function(r){
14248 if(r.data[prop] == value){
14258 getName: function()
14260 // returns hidden if it's set..
14261 if (!this.rendered) {return ''};
14262 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14266 onViewMove : function(e, t){
14267 this.inKeyMode = false;
14271 onViewOver : function(e, t){
14272 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14275 var item = this.view.findItemFromChild(t);
14278 var index = this.view.indexOf(item);
14279 this.select(index, false);
14284 onViewClick : function(view, doFocus, el, e)
14286 var index = this.view.getSelectedIndexes()[0];
14288 var r = this.store.getAt(index);
14292 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14299 Roo.each(this.tickItems, function(v,k){
14301 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14303 _this.tickItems.splice(k, 1);
14305 if(typeof(e) == 'undefined' && view == false){
14306 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14318 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14319 this.tickItems.push(r.data);
14322 if(typeof(e) == 'undefined' && view == false){
14323 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14330 this.onSelect(r, index);
14332 if(doFocus !== false && !this.blockFocus){
14333 this.inputEl().focus();
14338 restrictHeight : function(){
14339 //this.innerList.dom.style.height = '';
14340 //var inner = this.innerList.dom;
14341 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14342 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14343 //this.list.beginUpdate();
14344 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14345 this.list.alignTo(this.inputEl(), this.listAlign);
14346 this.list.alignTo(this.inputEl(), this.listAlign);
14347 //this.list.endUpdate();
14351 onEmptyResults : function(){
14353 if(this.tickable && this.editable){
14354 this.hasFocus = false;
14355 this.restrictHeight();
14363 * Returns true if the dropdown list is expanded, else false.
14365 isExpanded : function(){
14366 return this.list.isVisible();
14370 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14371 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14372 * @param {String} value The data value of the item to select
14373 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14374 * selected item if it is not currently in view (defaults to true)
14375 * @return {Boolean} True if the value matched an item in the list, else false
14377 selectByValue : function(v, scrollIntoView){
14378 if(v !== undefined && v !== null){
14379 var r = this.findRecord(this.valueField || this.displayField, v);
14381 this.select(this.store.indexOf(r), scrollIntoView);
14389 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14390 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14391 * @param {Number} index The zero-based index of the list item to select
14392 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14393 * selected item if it is not currently in view (defaults to true)
14395 select : function(index, scrollIntoView){
14396 this.selectedIndex = index;
14397 this.view.select(index);
14398 if(scrollIntoView !== false){
14399 var el = this.view.getNode(index);
14401 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14404 this.list.scrollChildIntoView(el, false);
14410 selectNext : function(){
14411 var ct = this.store.getCount();
14413 if(this.selectedIndex == -1){
14415 }else if(this.selectedIndex < ct-1){
14416 this.select(this.selectedIndex+1);
14422 selectPrev : function(){
14423 var ct = this.store.getCount();
14425 if(this.selectedIndex == -1){
14427 }else if(this.selectedIndex != 0){
14428 this.select(this.selectedIndex-1);
14434 onKeyUp : function(e){
14435 if(this.editable !== false && !e.isSpecialKey()){
14436 this.lastKey = e.getKey();
14437 this.dqTask.delay(this.queryDelay);
14442 validateBlur : function(){
14443 return !this.list || !this.list.isVisible();
14447 initQuery : function(){
14449 var v = this.getRawValue();
14451 if(this.tickable && this.editable){
14452 v = this.tickableInputEl().getValue();
14459 doForce : function(){
14460 if(this.inputEl().dom.value.length > 0){
14461 this.inputEl().dom.value =
14462 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14468 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14469 * query allowing the query action to be canceled if needed.
14470 * @param {String} query The SQL query to execute
14471 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14472 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14473 * saved in the current store (defaults to false)
14475 doQuery : function(q, forceAll){
14477 if(q === undefined || q === null){
14482 forceAll: forceAll,
14486 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14491 forceAll = qe.forceAll;
14492 if(forceAll === true || (q.length >= this.minChars)){
14494 this.hasQuery = true;
14496 if(this.lastQuery != q || this.alwaysQuery){
14497 this.lastQuery = q;
14498 if(this.mode == 'local'){
14499 this.selectedIndex = -1;
14501 this.store.clearFilter();
14504 if(this.specialFilter){
14505 this.fireEvent('specialfilter', this);
14510 this.store.filter(this.displayField, q);
14513 this.store.fireEvent("datachanged", this.store);
14520 this.store.baseParams[this.queryParam] = q;
14522 var options = {params : this.getParams(q)};
14525 options.add = true;
14526 options.params.start = this.page * this.pageSize;
14529 this.store.load(options);
14532 * this code will make the page width larger, at the beginning, the list not align correctly,
14533 * we should expand the list on onLoad
14534 * so command out it
14539 this.selectedIndex = -1;
14544 this.loadNext = false;
14548 getParams : function(q){
14550 //p[this.queryParam] = q;
14554 p.limit = this.pageSize;
14560 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14562 collapse : function(){
14563 if(!this.isExpanded()){
14569 this.hasFocus = false;
14573 this.cancelBtn.hide();
14574 this.trigger.show();
14577 this.tickableInputEl().dom.value = '';
14578 this.tickableInputEl().blur();
14583 Roo.get(document).un('mousedown', this.collapseIf, this);
14584 Roo.get(document).un('mousewheel', this.collapseIf, this);
14585 if (!this.editable) {
14586 Roo.get(document).un('keydown', this.listKeyPress, this);
14588 this.fireEvent('collapse', this);
14594 collapseIf : function(e){
14595 var in_combo = e.within(this.el);
14596 var in_list = e.within(this.list);
14597 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14599 if (in_combo || in_list || is_list) {
14600 //e.stopPropagation();
14605 this.onTickableFooterButtonClick(e, false, false);
14613 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14615 expand : function(){
14617 if(this.isExpanded() || !this.hasFocus){
14621 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14622 this.list.setWidth(lw);
14628 this.restrictHeight();
14632 this.tickItems = Roo.apply([], this.item);
14635 this.cancelBtn.show();
14636 this.trigger.hide();
14639 this.tickableInputEl().focus();
14644 Roo.get(document).on('mousedown', this.collapseIf, this);
14645 Roo.get(document).on('mousewheel', this.collapseIf, this);
14646 if (!this.editable) {
14647 Roo.get(document).on('keydown', this.listKeyPress, this);
14650 this.fireEvent('expand', this);
14654 // Implements the default empty TriggerField.onTriggerClick function
14655 onTriggerClick : function(e)
14657 Roo.log('trigger click');
14659 if(this.disabled || !this.triggerList){
14664 this.loadNext = false;
14666 if(this.isExpanded()){
14668 if (!this.blockFocus) {
14669 this.inputEl().focus();
14673 this.hasFocus = true;
14674 if(this.triggerAction == 'all') {
14675 this.doQuery(this.allQuery, true);
14677 this.doQuery(this.getRawValue());
14679 if (!this.blockFocus) {
14680 this.inputEl().focus();
14685 onTickableTriggerClick : function(e)
14692 this.loadNext = false;
14693 this.hasFocus = true;
14695 if(this.triggerAction == 'all') {
14696 this.doQuery(this.allQuery, true);
14698 this.doQuery(this.getRawValue());
14702 onSearchFieldClick : function(e)
14704 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14705 this.onTickableFooterButtonClick(e, false, false);
14709 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14714 this.loadNext = false;
14715 this.hasFocus = true;
14717 if(this.triggerAction == 'all') {
14718 this.doQuery(this.allQuery, true);
14720 this.doQuery(this.getRawValue());
14724 listKeyPress : function(e)
14726 //Roo.log('listkeypress');
14727 // scroll to first matching element based on key pres..
14728 if (e.isSpecialKey()) {
14731 var k = String.fromCharCode(e.getKey()).toUpperCase();
14734 var csel = this.view.getSelectedNodes();
14735 var cselitem = false;
14737 var ix = this.view.indexOf(csel[0]);
14738 cselitem = this.store.getAt(ix);
14739 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14745 this.store.each(function(v) {
14747 // start at existing selection.
14748 if (cselitem.id == v.id) {
14754 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14755 match = this.store.indexOf(v);
14761 if (match === false) {
14762 return true; // no more action?
14765 this.view.select(match);
14766 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14767 sn.scrollIntoView(sn.dom.parentNode, false);
14770 onViewScroll : function(e, t){
14772 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){
14776 this.hasQuery = true;
14778 this.loading = this.list.select('.loading', true).first();
14780 if(this.loading === null){
14781 this.list.createChild({
14783 cls: 'loading roo-select2-more-results roo-select2-active',
14784 html: 'Loading more results...'
14787 this.loading = this.list.select('.loading', true).first();
14789 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14791 this.loading.hide();
14794 this.loading.show();
14799 this.loadNext = true;
14801 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14806 addItem : function(o)
14808 var dv = ''; // display value
14810 if (this.displayField) {
14811 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14813 // this is an error condition!!!
14814 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14821 var choice = this.choices.createChild({
14823 cls: 'roo-select2-search-choice',
14832 cls: 'roo-select2-search-choice-close fa fa-times',
14837 }, this.searchField);
14839 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14841 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14849 this.inputEl().dom.value = '';
14854 onRemoveItem : function(e, _self, o)
14856 e.preventDefault();
14858 this.lastItem = Roo.apply([], this.item);
14860 var index = this.item.indexOf(o.data) * 1;
14863 Roo.log('not this item?!');
14867 this.item.splice(index, 1);
14872 this.fireEvent('remove', this, e);
14878 syncValue : function()
14880 if(!this.item.length){
14887 Roo.each(this.item, function(i){
14888 if(_this.valueField){
14889 value.push(i[_this.valueField]);
14896 this.value = value.join(',');
14898 if(this.hiddenField){
14899 this.hiddenField.dom.value = this.value;
14902 this.store.fireEvent("datachanged", this.store);
14907 clearItem : function()
14909 if(!this.multiple){
14915 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14923 if(this.tickable && !Roo.isTouch){
14924 this.view.refresh();
14928 inputEl: function ()
14930 if(Roo.isIOS && this.useNativeIOS){
14931 return this.el.select('select.roo-ios-select', true).first();
14934 if(Roo.isTouch && this.mobileTouchView){
14935 return this.el.select('input.form-control',true).first();
14939 return this.searchField;
14942 return this.el.select('input.form-control',true).first();
14945 onTickableFooterButtonClick : function(e, btn, el)
14947 e.preventDefault();
14949 this.lastItem = Roo.apply([], this.item);
14951 if(btn && btn.name == 'cancel'){
14952 this.tickItems = Roo.apply([], this.item);
14961 Roo.each(this.tickItems, function(o){
14969 validate : function()
14971 if(this.getVisibilityEl().hasClass('hidden')){
14975 var v = this.getRawValue();
14978 v = this.getValue();
14981 if(this.disabled || this.allowBlank || v.length){
14986 this.markInvalid();
14990 tickableInputEl : function()
14992 if(!this.tickable || !this.editable){
14993 return this.inputEl();
14996 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15000 getAutoCreateTouchView : function()
15005 cls: 'form-group' //input-group
15011 type : this.inputType,
15012 cls : 'form-control x-combo-noedit',
15013 autocomplete: 'new-password',
15014 placeholder : this.placeholder || '',
15019 input.name = this.name;
15023 input.cls += ' input-' + this.size;
15026 if (this.disabled) {
15027 input.disabled = true;
15038 inputblock.cls += ' input-group';
15040 inputblock.cn.unshift({
15042 cls : 'input-group-addon',
15047 if(this.removable && !this.multiple){
15048 inputblock.cls += ' roo-removable';
15050 inputblock.cn.push({
15053 cls : 'roo-combo-removable-btn close'
15057 if(this.hasFeedback && !this.allowBlank){
15059 inputblock.cls += ' has-feedback';
15061 inputblock.cn.push({
15063 cls: 'glyphicon form-control-feedback'
15070 inputblock.cls += (this.before) ? '' : ' input-group';
15072 inputblock.cn.push({
15074 cls : 'input-group-addon',
15085 cls: 'form-hidden-field'
15099 cls: 'form-hidden-field'
15103 cls: 'roo-select2-choices',
15107 cls: 'roo-select2-search-field',
15120 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15126 if(!this.multiple && this.showToggleBtn){
15133 if (this.caret != false) {
15136 cls: 'fa fa-' + this.caret
15143 cls : 'input-group-addon btn dropdown-toggle',
15148 cls: 'combobox-clear',
15162 combobox.cls += ' roo-select2-container-multi';
15165 var align = this.labelAlign || this.parentLabelAlign();
15167 if (align ==='left' && this.fieldLabel.length) {
15172 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15173 tooltip : 'This field is required'
15177 cls : 'control-label',
15178 html : this.fieldLabel
15189 var labelCfg = cfg.cn[1];
15190 var contentCfg = cfg.cn[2];
15193 if(this.indicatorpos == 'right'){
15198 cls : 'control-label',
15202 html : this.fieldLabel
15206 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15207 tooltip : 'This field is required'
15220 labelCfg = cfg.cn[0];
15221 contentCfg = cfg.cn[1];
15226 if(this.labelWidth > 12){
15227 labelCfg.style = "width: " + this.labelWidth + 'px';
15230 if(this.labelWidth < 13 && this.labelmd == 0){
15231 this.labelmd = this.labelWidth;
15234 if(this.labellg > 0){
15235 labelCfg.cls += ' col-lg-' + this.labellg;
15236 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15239 if(this.labelmd > 0){
15240 labelCfg.cls += ' col-md-' + this.labelmd;
15241 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15244 if(this.labelsm > 0){
15245 labelCfg.cls += ' col-sm-' + this.labelsm;
15246 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15249 if(this.labelxs > 0){
15250 labelCfg.cls += ' col-xs-' + this.labelxs;
15251 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15255 } else if ( this.fieldLabel.length) {
15259 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15260 tooltip : 'This field is required'
15264 cls : 'control-label',
15265 html : this.fieldLabel
15276 if(this.indicatorpos == 'right'){
15280 cls : 'control-label',
15281 html : this.fieldLabel,
15285 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15286 tooltip : 'This field is required'
15303 var settings = this;
15305 ['xs','sm','md','lg'].map(function(size){
15306 if (settings[size]) {
15307 cfg.cls += ' col-' + size + '-' + settings[size];
15314 initTouchView : function()
15316 this.renderTouchView();
15318 this.touchViewEl.on('scroll', function(){
15319 this.el.dom.scrollTop = 0;
15322 this.originalValue = this.getValue();
15324 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15326 this.inputEl().on("click", this.showTouchView, this);
15327 if (this.triggerEl) {
15328 this.triggerEl.on("click", this.showTouchView, this);
15332 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15333 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15335 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15337 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15338 this.store.on('load', this.onTouchViewLoad, this);
15339 this.store.on('loadexception', this.onTouchViewLoadException, this);
15341 if(this.hiddenName){
15343 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15345 this.hiddenField.dom.value =
15346 this.hiddenValue !== undefined ? this.hiddenValue :
15347 this.value !== undefined ? this.value : '';
15349 this.el.dom.removeAttribute('name');
15350 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15354 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15355 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15358 if(this.removable && !this.multiple){
15359 var close = this.closeTriggerEl();
15361 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15362 close.on('click', this.removeBtnClick, this, close);
15366 * fix the bug in Safari iOS8
15368 this.inputEl().on("focus", function(e){
15369 document.activeElement.blur();
15372 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15379 renderTouchView : function()
15381 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15382 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15384 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15385 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15387 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15388 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15389 this.touchViewBodyEl.setStyle('overflow', 'auto');
15391 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15392 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15394 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15395 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15399 showTouchView : function()
15405 this.touchViewHeaderEl.hide();
15407 if(this.modalTitle.length){
15408 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15409 this.touchViewHeaderEl.show();
15412 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15413 this.touchViewEl.show();
15415 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15417 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15418 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15420 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15422 if(this.modalTitle.length){
15423 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15426 this.touchViewBodyEl.setHeight(bodyHeight);
15430 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15432 this.touchViewEl.addClass('in');
15435 if(this._touchViewMask){
15436 Roo.get(document.body).addClass("x-body-masked");
15437 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15438 this._touchViewMask.setStyle('z-index', 10000);
15439 this._touchViewMask.addClass('show');
15442 this.doTouchViewQuery();
15446 hideTouchView : function()
15448 this.touchViewEl.removeClass('in');
15452 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15454 this.touchViewEl.setStyle('display', 'none');
15457 if(this._touchViewMask){
15458 this._touchViewMask.removeClass('show');
15459 Roo.get(document.body).removeClass("x-body-masked");
15463 setTouchViewValue : function()
15470 Roo.each(this.tickItems, function(o){
15475 this.hideTouchView();
15478 doTouchViewQuery : function()
15487 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15491 if(!this.alwaysQuery || this.mode == 'local'){
15492 this.onTouchViewLoad();
15499 onTouchViewBeforeLoad : function(combo,opts)
15505 onTouchViewLoad : function()
15507 if(this.store.getCount() < 1){
15508 this.onTouchViewEmptyResults();
15512 this.clearTouchView();
15514 var rawValue = this.getRawValue();
15516 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15518 this.tickItems = [];
15520 this.store.data.each(function(d, rowIndex){
15521 var row = this.touchViewListGroup.createChild(template);
15523 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15524 row.addClass(d.data.cls);
15527 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15530 html : d.data[this.displayField]
15533 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15534 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15537 row.removeClass('selected');
15538 if(!this.multiple && this.valueField &&
15539 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15542 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15543 row.addClass('selected');
15546 if(this.multiple && this.valueField &&
15547 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15551 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15552 this.tickItems.push(d.data);
15555 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15559 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15561 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15563 if(this.modalTitle.length){
15564 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15567 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15569 if(this.mobile_restrict_height && listHeight < bodyHeight){
15570 this.touchViewBodyEl.setHeight(listHeight);
15575 if(firstChecked && listHeight > bodyHeight){
15576 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15581 onTouchViewLoadException : function()
15583 this.hideTouchView();
15586 onTouchViewEmptyResults : function()
15588 this.clearTouchView();
15590 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15592 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15596 clearTouchView : function()
15598 this.touchViewListGroup.dom.innerHTML = '';
15601 onTouchViewClick : function(e, el, o)
15603 e.preventDefault();
15606 var rowIndex = o.rowIndex;
15608 var r = this.store.getAt(rowIndex);
15610 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15612 if(!this.multiple){
15613 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15614 c.dom.removeAttribute('checked');
15617 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15619 this.setFromData(r.data);
15621 var close = this.closeTriggerEl();
15627 this.hideTouchView();
15629 this.fireEvent('select', this, r, rowIndex);
15634 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15635 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15636 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15640 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15641 this.addItem(r.data);
15642 this.tickItems.push(r.data);
15646 getAutoCreateNativeIOS : function()
15649 cls: 'form-group' //input-group,
15654 cls : 'roo-ios-select'
15658 combobox.name = this.name;
15661 if (this.disabled) {
15662 combobox.disabled = true;
15665 var settings = this;
15667 ['xs','sm','md','lg'].map(function(size){
15668 if (settings[size]) {
15669 cfg.cls += ' col-' + size + '-' + settings[size];
15679 initIOSView : function()
15681 this.store.on('load', this.onIOSViewLoad, this);
15686 onIOSViewLoad : function()
15688 if(this.store.getCount() < 1){
15692 this.clearIOSView();
15694 if(this.allowBlank) {
15696 var default_text = '-- SELECT --';
15698 if(this.placeholder.length){
15699 default_text = this.placeholder;
15702 if(this.emptyTitle.length){
15703 default_text += ' - ' + this.emptyTitle + ' -';
15706 var opt = this.inputEl().createChild({
15709 html : default_text
15713 o[this.valueField] = 0;
15714 o[this.displayField] = default_text;
15716 this.ios_options.push({
15723 this.store.data.each(function(d, rowIndex){
15727 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15728 html = d.data[this.displayField];
15733 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15734 value = d.data[this.valueField];
15743 if(this.value == d.data[this.valueField]){
15744 option['selected'] = true;
15747 var opt = this.inputEl().createChild(option);
15749 this.ios_options.push({
15756 this.inputEl().on('change', function(){
15757 this.fireEvent('select', this);
15762 clearIOSView: function()
15764 this.inputEl().dom.innerHTML = '';
15766 this.ios_options = [];
15769 setIOSValue: function(v)
15773 if(!this.ios_options){
15777 Roo.each(this.ios_options, function(opts){
15779 opts.el.dom.removeAttribute('selected');
15781 if(opts.data[this.valueField] != v){
15785 opts.el.dom.setAttribute('selected', true);
15791 * @cfg {Boolean} grow
15795 * @cfg {Number} growMin
15799 * @cfg {Number} growMax
15808 Roo.apply(Roo.bootstrap.ComboBox, {
15812 cls: 'modal-header',
15834 cls: 'list-group-item',
15838 cls: 'roo-combobox-list-group-item-value'
15842 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15856 listItemCheckbox : {
15858 cls: 'list-group-item',
15862 cls: 'roo-combobox-list-group-item-value'
15866 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15882 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15887 cls: 'modal-footer',
15895 cls: 'col-xs-6 text-left',
15898 cls: 'btn btn-danger roo-touch-view-cancel',
15904 cls: 'col-xs-6 text-right',
15907 cls: 'btn btn-success roo-touch-view-ok',
15918 Roo.apply(Roo.bootstrap.ComboBox, {
15920 touchViewTemplate : {
15922 cls: 'modal fade roo-combobox-touch-view',
15926 cls: 'modal-dialog',
15927 style : 'position:fixed', // we have to fix position....
15931 cls: 'modal-content',
15933 Roo.bootstrap.ComboBox.header,
15934 Roo.bootstrap.ComboBox.body,
15935 Roo.bootstrap.ComboBox.footer
15944 * Ext JS Library 1.1.1
15945 * Copyright(c) 2006-2007, Ext JS, LLC.
15947 * Originally Released Under LGPL - original licence link has changed is not relivant.
15950 * <script type="text/javascript">
15955 * @extends Roo.util.Observable
15956 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15957 * This class also supports single and multi selection modes. <br>
15958 * Create a data model bound view:
15960 var store = new Roo.data.Store(...);
15962 var view = new Roo.View({
15964 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15966 singleSelect: true,
15967 selectedClass: "ydataview-selected",
15971 // listen for node click?
15972 view.on("click", function(vw, index, node, e){
15973 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15977 dataModel.load("foobar.xml");
15979 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15981 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15982 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15984 * Note: old style constructor is still suported (container, template, config)
15987 * Create a new View
15988 * @param {Object} config The config object
15991 Roo.View = function(config, depreciated_tpl, depreciated_config){
15993 this.parent = false;
15995 if (typeof(depreciated_tpl) == 'undefined') {
15996 // new way.. - universal constructor.
15997 Roo.apply(this, config);
15998 this.el = Roo.get(this.el);
16001 this.el = Roo.get(config);
16002 this.tpl = depreciated_tpl;
16003 Roo.apply(this, depreciated_config);
16005 this.wrapEl = this.el.wrap().wrap();
16006 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16009 if(typeof(this.tpl) == "string"){
16010 this.tpl = new Roo.Template(this.tpl);
16012 // support xtype ctors..
16013 this.tpl = new Roo.factory(this.tpl, Roo);
16017 this.tpl.compile();
16022 * @event beforeclick
16023 * Fires before a click is processed. Returns false to cancel the default action.
16024 * @param {Roo.View} this
16025 * @param {Number} index The index of the target node
16026 * @param {HTMLElement} node The target node
16027 * @param {Roo.EventObject} e The raw event object
16029 "beforeclick" : true,
16032 * Fires when a template node is clicked.
16033 * @param {Roo.View} this
16034 * @param {Number} index The index of the target node
16035 * @param {HTMLElement} node The target node
16036 * @param {Roo.EventObject} e The raw event object
16041 * Fires when a template node is double clicked.
16042 * @param {Roo.View} this
16043 * @param {Number} index The index of the target node
16044 * @param {HTMLElement} node The target node
16045 * @param {Roo.EventObject} e The raw event object
16049 * @event contextmenu
16050 * Fires when a template node is right clicked.
16051 * @param {Roo.View} this
16052 * @param {Number} index The index of the target node
16053 * @param {HTMLElement} node The target node
16054 * @param {Roo.EventObject} e The raw event object
16056 "contextmenu" : true,
16058 * @event selectionchange
16059 * Fires when the selected nodes change.
16060 * @param {Roo.View} this
16061 * @param {Array} selections Array of the selected nodes
16063 "selectionchange" : true,
16066 * @event beforeselect
16067 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16068 * @param {Roo.View} this
16069 * @param {HTMLElement} node The node to be selected
16070 * @param {Array} selections Array of currently selected nodes
16072 "beforeselect" : true,
16074 * @event preparedata
16075 * Fires on every row to render, to allow you to change the data.
16076 * @param {Roo.View} this
16077 * @param {Object} data to be rendered (change this)
16079 "preparedata" : true
16087 "click": this.onClick,
16088 "dblclick": this.onDblClick,
16089 "contextmenu": this.onContextMenu,
16093 this.selections = [];
16095 this.cmp = new Roo.CompositeElementLite([]);
16097 this.store = Roo.factory(this.store, Roo.data);
16098 this.setStore(this.store, true);
16101 if ( this.footer && this.footer.xtype) {
16103 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16105 this.footer.dataSource = this.store;
16106 this.footer.container = fctr;
16107 this.footer = Roo.factory(this.footer, Roo);
16108 fctr.insertFirst(this.el);
16110 // this is a bit insane - as the paging toolbar seems to detach the el..
16111 // dom.parentNode.parentNode.parentNode
16112 // they get detached?
16116 Roo.View.superclass.constructor.call(this);
16121 Roo.extend(Roo.View, Roo.util.Observable, {
16124 * @cfg {Roo.data.Store} store Data store to load data from.
16129 * @cfg {String|Roo.Element} el The container element.
16134 * @cfg {String|Roo.Template} tpl The template used by this View
16138 * @cfg {String} dataName the named area of the template to use as the data area
16139 * Works with domtemplates roo-name="name"
16143 * @cfg {String} selectedClass The css class to add to selected nodes
16145 selectedClass : "x-view-selected",
16147 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16152 * @cfg {String} text to display on mask (default Loading)
16156 * @cfg {Boolean} multiSelect Allow multiple selection
16158 multiSelect : false,
16160 * @cfg {Boolean} singleSelect Allow single selection
16162 singleSelect: false,
16165 * @cfg {Boolean} toggleSelect - selecting
16167 toggleSelect : false,
16170 * @cfg {Boolean} tickable - selecting
16175 * Returns the element this view is bound to.
16176 * @return {Roo.Element}
16178 getEl : function(){
16179 return this.wrapEl;
16185 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16187 refresh : function(){
16188 //Roo.log('refresh');
16191 // if we are using something like 'domtemplate', then
16192 // the what gets used is:
16193 // t.applySubtemplate(NAME, data, wrapping data..)
16194 // the outer template then get' applied with
16195 // the store 'extra data'
16196 // and the body get's added to the
16197 // roo-name="data" node?
16198 // <span class='roo-tpl-{name}'></span> ?????
16202 this.clearSelections();
16203 this.el.update("");
16205 var records = this.store.getRange();
16206 if(records.length < 1) {
16208 // is this valid?? = should it render a template??
16210 this.el.update(this.emptyText);
16214 if (this.dataName) {
16215 this.el.update(t.apply(this.store.meta)); //????
16216 el = this.el.child('.roo-tpl-' + this.dataName);
16219 for(var i = 0, len = records.length; i < len; i++){
16220 var data = this.prepareData(records[i].data, i, records[i]);
16221 this.fireEvent("preparedata", this, data, i, records[i]);
16223 var d = Roo.apply({}, data);
16226 Roo.apply(d, {'roo-id' : Roo.id()});
16230 Roo.each(this.parent.item, function(item){
16231 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16234 Roo.apply(d, {'roo-data-checked' : 'checked'});
16238 html[html.length] = Roo.util.Format.trim(
16240 t.applySubtemplate(this.dataName, d, this.store.meta) :
16247 el.update(html.join(""));
16248 this.nodes = el.dom.childNodes;
16249 this.updateIndexes(0);
16254 * Function to override to reformat the data that is sent to
16255 * the template for each node.
16256 * DEPRICATED - use the preparedata event handler.
16257 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16258 * a JSON object for an UpdateManager bound view).
16260 prepareData : function(data, index, record)
16262 this.fireEvent("preparedata", this, data, index, record);
16266 onUpdate : function(ds, record){
16267 // Roo.log('on update');
16268 this.clearSelections();
16269 var index = this.store.indexOf(record);
16270 var n = this.nodes[index];
16271 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16272 n.parentNode.removeChild(n);
16273 this.updateIndexes(index, index);
16279 onAdd : function(ds, records, index)
16281 //Roo.log(['on Add', ds, records, index] );
16282 this.clearSelections();
16283 if(this.nodes.length == 0){
16287 var n = this.nodes[index];
16288 for(var i = 0, len = records.length; i < len; i++){
16289 var d = this.prepareData(records[i].data, i, records[i]);
16291 this.tpl.insertBefore(n, d);
16294 this.tpl.append(this.el, d);
16297 this.updateIndexes(index);
16300 onRemove : function(ds, record, index){
16301 // Roo.log('onRemove');
16302 this.clearSelections();
16303 var el = this.dataName ?
16304 this.el.child('.roo-tpl-' + this.dataName) :
16307 el.dom.removeChild(this.nodes[index]);
16308 this.updateIndexes(index);
16312 * Refresh an individual node.
16313 * @param {Number} index
16315 refreshNode : function(index){
16316 this.onUpdate(this.store, this.store.getAt(index));
16319 updateIndexes : function(startIndex, endIndex){
16320 var ns = this.nodes;
16321 startIndex = startIndex || 0;
16322 endIndex = endIndex || ns.length - 1;
16323 for(var i = startIndex; i <= endIndex; i++){
16324 ns[i].nodeIndex = i;
16329 * Changes the data store this view uses and refresh the view.
16330 * @param {Store} store
16332 setStore : function(store, initial){
16333 if(!initial && this.store){
16334 this.store.un("datachanged", this.refresh);
16335 this.store.un("add", this.onAdd);
16336 this.store.un("remove", this.onRemove);
16337 this.store.un("update", this.onUpdate);
16338 this.store.un("clear", this.refresh);
16339 this.store.un("beforeload", this.onBeforeLoad);
16340 this.store.un("load", this.onLoad);
16341 this.store.un("loadexception", this.onLoad);
16345 store.on("datachanged", this.refresh, this);
16346 store.on("add", this.onAdd, this);
16347 store.on("remove", this.onRemove, this);
16348 store.on("update", this.onUpdate, this);
16349 store.on("clear", this.refresh, this);
16350 store.on("beforeload", this.onBeforeLoad, this);
16351 store.on("load", this.onLoad, this);
16352 store.on("loadexception", this.onLoad, this);
16360 * onbeforeLoad - masks the loading area.
16363 onBeforeLoad : function(store,opts)
16365 //Roo.log('onBeforeLoad');
16367 this.el.update("");
16369 this.el.mask(this.mask ? this.mask : "Loading" );
16371 onLoad : function ()
16378 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16379 * @param {HTMLElement} node
16380 * @return {HTMLElement} The template node
16382 findItemFromChild : function(node){
16383 var el = this.dataName ?
16384 this.el.child('.roo-tpl-' + this.dataName,true) :
16387 if(!node || node.parentNode == el){
16390 var p = node.parentNode;
16391 while(p && p != el){
16392 if(p.parentNode == el){
16401 onClick : function(e){
16402 var item = this.findItemFromChild(e.getTarget());
16404 var index = this.indexOf(item);
16405 if(this.onItemClick(item, index, e) !== false){
16406 this.fireEvent("click", this, index, item, e);
16409 this.clearSelections();
16414 onContextMenu : function(e){
16415 var item = this.findItemFromChild(e.getTarget());
16417 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16422 onDblClick : function(e){
16423 var item = this.findItemFromChild(e.getTarget());
16425 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16429 onItemClick : function(item, index, e)
16431 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16434 if (this.toggleSelect) {
16435 var m = this.isSelected(item) ? 'unselect' : 'select';
16438 _t[m](item, true, false);
16441 if(this.multiSelect || this.singleSelect){
16442 if(this.multiSelect && e.shiftKey && this.lastSelection){
16443 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16445 this.select(item, this.multiSelect && e.ctrlKey);
16446 this.lastSelection = item;
16449 if(!this.tickable){
16450 e.preventDefault();
16458 * Get the number of selected nodes.
16461 getSelectionCount : function(){
16462 return this.selections.length;
16466 * Get the currently selected nodes.
16467 * @return {Array} An array of HTMLElements
16469 getSelectedNodes : function(){
16470 return this.selections;
16474 * Get the indexes of the selected nodes.
16477 getSelectedIndexes : function(){
16478 var indexes = [], s = this.selections;
16479 for(var i = 0, len = s.length; i < len; i++){
16480 indexes.push(s[i].nodeIndex);
16486 * Clear all selections
16487 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16489 clearSelections : function(suppressEvent){
16490 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16491 this.cmp.elements = this.selections;
16492 this.cmp.removeClass(this.selectedClass);
16493 this.selections = [];
16494 if(!suppressEvent){
16495 this.fireEvent("selectionchange", this, this.selections);
16501 * Returns true if the passed node is selected
16502 * @param {HTMLElement/Number} node The node or node index
16503 * @return {Boolean}
16505 isSelected : function(node){
16506 var s = this.selections;
16510 node = this.getNode(node);
16511 return s.indexOf(node) !== -1;
16516 * @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
16517 * @param {Boolean} keepExisting (optional) true to keep existing selections
16518 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16520 select : function(nodeInfo, keepExisting, suppressEvent){
16521 if(nodeInfo instanceof Array){
16523 this.clearSelections(true);
16525 for(var i = 0, len = nodeInfo.length; i < len; i++){
16526 this.select(nodeInfo[i], true, true);
16530 var node = this.getNode(nodeInfo);
16531 if(!node || this.isSelected(node)){
16532 return; // already selected.
16535 this.clearSelections(true);
16538 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16539 Roo.fly(node).addClass(this.selectedClass);
16540 this.selections.push(node);
16541 if(!suppressEvent){
16542 this.fireEvent("selectionchange", this, this.selections);
16550 * @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
16551 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16552 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16554 unselect : function(nodeInfo, keepExisting, suppressEvent)
16556 if(nodeInfo instanceof Array){
16557 Roo.each(this.selections, function(s) {
16558 this.unselect(s, nodeInfo);
16562 var node = this.getNode(nodeInfo);
16563 if(!node || !this.isSelected(node)){
16564 //Roo.log("not selected");
16565 return; // not selected.
16569 Roo.each(this.selections, function(s) {
16571 Roo.fly(node).removeClass(this.selectedClass);
16578 this.selections= ns;
16579 this.fireEvent("selectionchange", this, this.selections);
16583 * Gets a template node.
16584 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16585 * @return {HTMLElement} The node or null if it wasn't found
16587 getNode : function(nodeInfo){
16588 if(typeof nodeInfo == "string"){
16589 return document.getElementById(nodeInfo);
16590 }else if(typeof nodeInfo == "number"){
16591 return this.nodes[nodeInfo];
16597 * Gets a range template nodes.
16598 * @param {Number} startIndex
16599 * @param {Number} endIndex
16600 * @return {Array} An array of nodes
16602 getNodes : function(start, end){
16603 var ns = this.nodes;
16604 start = start || 0;
16605 end = typeof end == "undefined" ? ns.length - 1 : end;
16608 for(var i = start; i <= end; i++){
16612 for(var i = start; i >= end; i--){
16620 * Finds the index of the passed node
16621 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16622 * @return {Number} The index of the node or -1
16624 indexOf : function(node){
16625 node = this.getNode(node);
16626 if(typeof node.nodeIndex == "number"){
16627 return node.nodeIndex;
16629 var ns = this.nodes;
16630 for(var i = 0, len = ns.length; i < len; i++){
16641 * based on jquery fullcalendar
16645 Roo.bootstrap = Roo.bootstrap || {};
16647 * @class Roo.bootstrap.Calendar
16648 * @extends Roo.bootstrap.Component
16649 * Bootstrap Calendar class
16650 * @cfg {Boolean} loadMask (true|false) default false
16651 * @cfg {Object} header generate the user specific header of the calendar, default false
16654 * Create a new Container
16655 * @param {Object} config The config object
16660 Roo.bootstrap.Calendar = function(config){
16661 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16665 * Fires when a date is selected
16666 * @param {DatePicker} this
16667 * @param {Date} date The selected date
16671 * @event monthchange
16672 * Fires when the displayed month changes
16673 * @param {DatePicker} this
16674 * @param {Date} date The selected month
16676 'monthchange': true,
16678 * @event evententer
16679 * Fires when mouse over an event
16680 * @param {Calendar} this
16681 * @param {event} Event
16683 'evententer': true,
16685 * @event eventleave
16686 * Fires when the mouse leaves an
16687 * @param {Calendar} this
16690 'eventleave': true,
16692 * @event eventclick
16693 * Fires when the mouse click an
16694 * @param {Calendar} this
16703 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16706 * @cfg {Number} startDay
16707 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16715 getAutoCreate : function(){
16718 var fc_button = function(name, corner, style, content ) {
16719 return Roo.apply({},{
16721 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16723 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16726 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16737 style : 'width:100%',
16744 cls : 'fc-header-left',
16746 fc_button('prev', 'left', 'arrow', '‹' ),
16747 fc_button('next', 'right', 'arrow', '›' ),
16748 { tag: 'span', cls: 'fc-header-space' },
16749 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16757 cls : 'fc-header-center',
16761 cls: 'fc-header-title',
16764 html : 'month / year'
16772 cls : 'fc-header-right',
16774 /* fc_button('month', 'left', '', 'month' ),
16775 fc_button('week', '', '', 'week' ),
16776 fc_button('day', 'right', '', 'day' )
16788 header = this.header;
16791 var cal_heads = function() {
16793 // fixme - handle this.
16795 for (var i =0; i < Date.dayNames.length; i++) {
16796 var d = Date.dayNames[i];
16799 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16800 html : d.substring(0,3)
16804 ret[0].cls += ' fc-first';
16805 ret[6].cls += ' fc-last';
16808 var cal_cell = function(n) {
16811 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16816 cls: 'fc-day-number',
16820 cls: 'fc-day-content',
16824 style: 'position: relative;' // height: 17px;
16836 var cal_rows = function() {
16839 for (var r = 0; r < 6; r++) {
16846 for (var i =0; i < Date.dayNames.length; i++) {
16847 var d = Date.dayNames[i];
16848 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16851 row.cn[0].cls+=' fc-first';
16852 row.cn[0].cn[0].style = 'min-height:90px';
16853 row.cn[6].cls+=' fc-last';
16857 ret[0].cls += ' fc-first';
16858 ret[4].cls += ' fc-prev-last';
16859 ret[5].cls += ' fc-last';
16866 cls: 'fc-border-separate',
16867 style : 'width:100%',
16875 cls : 'fc-first fc-last',
16893 cls : 'fc-content',
16894 style : "position: relative;",
16897 cls : 'fc-view fc-view-month fc-grid',
16898 style : 'position: relative',
16899 unselectable : 'on',
16902 cls : 'fc-event-container',
16903 style : 'position:absolute;z-index:8;top:0;left:0;'
16921 initEvents : function()
16924 throw "can not find store for calendar";
16930 style: "text-align:center",
16934 style: "background-color:white;width:50%;margin:250 auto",
16938 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16949 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16951 var size = this.el.select('.fc-content', true).first().getSize();
16952 this.maskEl.setSize(size.width, size.height);
16953 this.maskEl.enableDisplayMode("block");
16954 if(!this.loadMask){
16955 this.maskEl.hide();
16958 this.store = Roo.factory(this.store, Roo.data);
16959 this.store.on('load', this.onLoad, this);
16960 this.store.on('beforeload', this.onBeforeLoad, this);
16964 this.cells = this.el.select('.fc-day',true);
16965 //Roo.log(this.cells);
16966 this.textNodes = this.el.query('.fc-day-number');
16967 this.cells.addClassOnOver('fc-state-hover');
16969 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16970 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16971 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16972 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16974 this.on('monthchange', this.onMonthChange, this);
16976 this.update(new Date().clearTime());
16979 resize : function() {
16980 var sz = this.el.getSize();
16982 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16983 this.el.select('.fc-day-content div',true).setHeight(34);
16988 showPrevMonth : function(e){
16989 this.update(this.activeDate.add("mo", -1));
16991 showToday : function(e){
16992 this.update(new Date().clearTime());
16995 showNextMonth : function(e){
16996 this.update(this.activeDate.add("mo", 1));
17000 showPrevYear : function(){
17001 this.update(this.activeDate.add("y", -1));
17005 showNextYear : function(){
17006 this.update(this.activeDate.add("y", 1));
17011 update : function(date)
17013 var vd = this.activeDate;
17014 this.activeDate = date;
17015 // if(vd && this.el){
17016 // var t = date.getTime();
17017 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17018 // Roo.log('using add remove');
17020 // this.fireEvent('monthchange', this, date);
17022 // this.cells.removeClass("fc-state-highlight");
17023 // this.cells.each(function(c){
17024 // if(c.dateValue == t){
17025 // c.addClass("fc-state-highlight");
17026 // setTimeout(function(){
17027 // try{c.dom.firstChild.focus();}catch(e){}
17037 var days = date.getDaysInMonth();
17039 var firstOfMonth = date.getFirstDateOfMonth();
17040 var startingPos = firstOfMonth.getDay()-this.startDay;
17042 if(startingPos < this.startDay){
17046 var pm = date.add(Date.MONTH, -1);
17047 var prevStart = pm.getDaysInMonth()-startingPos;
17049 this.cells = this.el.select('.fc-day',true);
17050 this.textNodes = this.el.query('.fc-day-number');
17051 this.cells.addClassOnOver('fc-state-hover');
17053 var cells = this.cells.elements;
17054 var textEls = this.textNodes;
17056 Roo.each(cells, function(cell){
17057 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17060 days += startingPos;
17062 // convert everything to numbers so it's fast
17063 var day = 86400000;
17064 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17067 //Roo.log(prevStart);
17069 var today = new Date().clearTime().getTime();
17070 var sel = date.clearTime().getTime();
17071 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17072 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17073 var ddMatch = this.disabledDatesRE;
17074 var ddText = this.disabledDatesText;
17075 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17076 var ddaysText = this.disabledDaysText;
17077 var format = this.format;
17079 var setCellClass = function(cal, cell){
17083 //Roo.log('set Cell Class');
17085 var t = d.getTime();
17089 cell.dateValue = t;
17091 cell.className += " fc-today";
17092 cell.className += " fc-state-highlight";
17093 cell.title = cal.todayText;
17096 // disable highlight in other month..
17097 //cell.className += " fc-state-highlight";
17102 cell.className = " fc-state-disabled";
17103 cell.title = cal.minText;
17107 cell.className = " fc-state-disabled";
17108 cell.title = cal.maxText;
17112 if(ddays.indexOf(d.getDay()) != -1){
17113 cell.title = ddaysText;
17114 cell.className = " fc-state-disabled";
17117 if(ddMatch && format){
17118 var fvalue = d.dateFormat(format);
17119 if(ddMatch.test(fvalue)){
17120 cell.title = ddText.replace("%0", fvalue);
17121 cell.className = " fc-state-disabled";
17125 if (!cell.initialClassName) {
17126 cell.initialClassName = cell.dom.className;
17129 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17134 for(; i < startingPos; i++) {
17135 textEls[i].innerHTML = (++prevStart);
17136 d.setDate(d.getDate()+1);
17138 cells[i].className = "fc-past fc-other-month";
17139 setCellClass(this, cells[i]);
17144 for(; i < days; i++){
17145 intDay = i - startingPos + 1;
17146 textEls[i].innerHTML = (intDay);
17147 d.setDate(d.getDate()+1);
17149 cells[i].className = ''; // "x-date-active";
17150 setCellClass(this, cells[i]);
17154 for(; i < 42; i++) {
17155 textEls[i].innerHTML = (++extraDays);
17156 d.setDate(d.getDate()+1);
17158 cells[i].className = "fc-future fc-other-month";
17159 setCellClass(this, cells[i]);
17162 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17164 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17166 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17167 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17169 if(totalRows != 6){
17170 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17171 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17174 this.fireEvent('monthchange', this, date);
17178 if(!this.internalRender){
17179 var main = this.el.dom.firstChild;
17180 var w = main.offsetWidth;
17181 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17182 Roo.fly(main).setWidth(w);
17183 this.internalRender = true;
17184 // opera does not respect the auto grow header center column
17185 // then, after it gets a width opera refuses to recalculate
17186 // without a second pass
17187 if(Roo.isOpera && !this.secondPass){
17188 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17189 this.secondPass = true;
17190 this.update.defer(10, this, [date]);
17197 findCell : function(dt) {
17198 dt = dt.clearTime().getTime();
17200 this.cells.each(function(c){
17201 //Roo.log("check " +c.dateValue + '?=' + dt);
17202 if(c.dateValue == dt){
17212 findCells : function(ev) {
17213 var s = ev.start.clone().clearTime().getTime();
17215 var e= ev.end.clone().clearTime().getTime();
17218 this.cells.each(function(c){
17219 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17221 if(c.dateValue > e){
17224 if(c.dateValue < s){
17233 // findBestRow: function(cells)
17237 // for (var i =0 ; i < cells.length;i++) {
17238 // ret = Math.max(cells[i].rows || 0,ret);
17245 addItem : function(ev)
17247 // look for vertical location slot in
17248 var cells = this.findCells(ev);
17250 // ev.row = this.findBestRow(cells);
17252 // work out the location.
17256 for(var i =0; i < cells.length; i++) {
17258 cells[i].row = cells[0].row;
17261 cells[i].row = cells[i].row + 1;
17271 if (crow.start.getY() == cells[i].getY()) {
17273 crow.end = cells[i];
17290 cells[0].events.push(ev);
17292 this.calevents.push(ev);
17295 clearEvents: function() {
17297 if(!this.calevents){
17301 Roo.each(this.cells.elements, function(c){
17307 Roo.each(this.calevents, function(e) {
17308 Roo.each(e.els, function(el) {
17309 el.un('mouseenter' ,this.onEventEnter, this);
17310 el.un('mouseleave' ,this.onEventLeave, this);
17315 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17321 renderEvents: function()
17325 this.cells.each(function(c) {
17334 if(c.row != c.events.length){
17335 r = 4 - (4 - (c.row - c.events.length));
17338 c.events = ev.slice(0, r);
17339 c.more = ev.slice(r);
17341 if(c.more.length && c.more.length == 1){
17342 c.events.push(c.more.pop());
17345 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17349 this.cells.each(function(c) {
17351 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17354 for (var e = 0; e < c.events.length; e++){
17355 var ev = c.events[e];
17356 var rows = ev.rows;
17358 for(var i = 0; i < rows.length; i++) {
17360 // how many rows should it span..
17363 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17364 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17366 unselectable : "on",
17369 cls: 'fc-event-inner',
17373 // cls: 'fc-event-time',
17374 // html : cells.length > 1 ? '' : ev.time
17378 cls: 'fc-event-title',
17379 html : String.format('{0}', ev.title)
17386 cls: 'ui-resizable-handle ui-resizable-e',
17387 html : '  '
17394 cfg.cls += ' fc-event-start';
17396 if ((i+1) == rows.length) {
17397 cfg.cls += ' fc-event-end';
17400 var ctr = _this.el.select('.fc-event-container',true).first();
17401 var cg = ctr.createChild(cfg);
17403 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17404 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17406 var r = (c.more.length) ? 1 : 0;
17407 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17408 cg.setWidth(ebox.right - sbox.x -2);
17410 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17411 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17412 cg.on('click', _this.onEventClick, _this, ev);
17423 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17424 style : 'position: absolute',
17425 unselectable : "on",
17428 cls: 'fc-event-inner',
17432 cls: 'fc-event-title',
17440 cls: 'ui-resizable-handle ui-resizable-e',
17441 html : '  '
17447 var ctr = _this.el.select('.fc-event-container',true).first();
17448 var cg = ctr.createChild(cfg);
17450 var sbox = c.select('.fc-day-content',true).first().getBox();
17451 var ebox = c.select('.fc-day-content',true).first().getBox();
17453 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17454 cg.setWidth(ebox.right - sbox.x -2);
17456 cg.on('click', _this.onMoreEventClick, _this, c.more);
17466 onEventEnter: function (e, el,event,d) {
17467 this.fireEvent('evententer', this, el, event);
17470 onEventLeave: function (e, el,event,d) {
17471 this.fireEvent('eventleave', this, el, event);
17474 onEventClick: function (e, el,event,d) {
17475 this.fireEvent('eventclick', this, el, event);
17478 onMonthChange: function () {
17482 onMoreEventClick: function(e, el, more)
17486 this.calpopover.placement = 'right';
17487 this.calpopover.setTitle('More');
17489 this.calpopover.setContent('');
17491 var ctr = this.calpopover.el.select('.popover-content', true).first();
17493 Roo.each(more, function(m){
17495 cls : 'fc-event-hori fc-event-draggable',
17498 var cg = ctr.createChild(cfg);
17500 cg.on('click', _this.onEventClick, _this, m);
17503 this.calpopover.show(el);
17508 onLoad: function ()
17510 this.calevents = [];
17513 if(this.store.getCount() > 0){
17514 this.store.data.each(function(d){
17517 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17518 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17519 time : d.data.start_time,
17520 title : d.data.title,
17521 description : d.data.description,
17522 venue : d.data.venue
17527 this.renderEvents();
17529 if(this.calevents.length && this.loadMask){
17530 this.maskEl.hide();
17534 onBeforeLoad: function()
17536 this.clearEvents();
17538 this.maskEl.show();
17552 * @class Roo.bootstrap.Popover
17553 * @extends Roo.bootstrap.Component
17554 * Bootstrap Popover class
17555 * @cfg {String} html contents of the popover (or false to use children..)
17556 * @cfg {String} title of popover (or false to hide)
17557 * @cfg {String} placement how it is placed
17558 * @cfg {String} trigger click || hover (or false to trigger manually)
17559 * @cfg {String} over what (parent or false to trigger manually.)
17560 * @cfg {Number} delay - delay before showing
17563 * Create a new Popover
17564 * @param {Object} config The config object
17567 Roo.bootstrap.Popover = function(config){
17568 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17574 * After the popover show
17576 * @param {Roo.bootstrap.Popover} this
17581 * After the popover hide
17583 * @param {Roo.bootstrap.Popover} this
17589 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17591 title: 'Fill in a title',
17594 placement : 'right',
17595 trigger : 'hover', // hover
17601 can_build_overlaid : false,
17603 getChildContainer : function()
17605 return this.el.select('.popover-content',true).first();
17608 getAutoCreate : function(){
17611 cls : 'popover roo-dynamic',
17612 style: 'display:block',
17618 cls : 'popover-inner',
17622 cls: 'popover-title',
17626 cls : 'popover-content',
17637 setTitle: function(str)
17640 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17642 setContent: function(str)
17645 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17647 // as it get's added to the bottom of the page.
17648 onRender : function(ct, position)
17650 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17652 var cfg = Roo.apply({}, this.getAutoCreate());
17656 cfg.cls += ' ' + this.cls;
17659 cfg.style = this.style;
17661 //Roo.log("adding to ");
17662 this.el = Roo.get(document.body).createChild(cfg, position);
17663 // Roo.log(this.el);
17668 initEvents : function()
17670 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17671 this.el.enableDisplayMode('block');
17673 if (this.over === false) {
17676 if (this.triggers === false) {
17679 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17680 var triggers = this.trigger ? this.trigger.split(' ') : [];
17681 Roo.each(triggers, function(trigger) {
17683 if (trigger == 'click') {
17684 on_el.on('click', this.toggle, this);
17685 } else if (trigger != 'manual') {
17686 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17687 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17689 on_el.on(eventIn ,this.enter, this);
17690 on_el.on(eventOut, this.leave, this);
17701 toggle : function () {
17702 this.hoverState == 'in' ? this.leave() : this.enter();
17705 enter : function () {
17707 clearTimeout(this.timeout);
17709 this.hoverState = 'in';
17711 if (!this.delay || !this.delay.show) {
17716 this.timeout = setTimeout(function () {
17717 if (_t.hoverState == 'in') {
17720 }, this.delay.show)
17723 leave : function() {
17724 clearTimeout(this.timeout);
17726 this.hoverState = 'out';
17728 if (!this.delay || !this.delay.hide) {
17733 this.timeout = setTimeout(function () {
17734 if (_t.hoverState == 'out') {
17737 }, this.delay.hide)
17740 show : function (on_el)
17743 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17747 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17748 if (this.html !== false) {
17749 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17751 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17752 if (!this.title.length) {
17753 this.el.select('.popover-title',true).hide();
17756 var placement = typeof this.placement == 'function' ?
17757 this.placement.call(this, this.el, on_el) :
17760 var autoToken = /\s?auto?\s?/i;
17761 var autoPlace = autoToken.test(placement);
17763 placement = placement.replace(autoToken, '') || 'top';
17767 //this.el.setXY([0,0]);
17769 this.el.dom.style.display='block';
17770 this.el.addClass(placement);
17772 //this.el.appendTo(on_el);
17774 var p = this.getPosition();
17775 var box = this.el.getBox();
17780 var align = Roo.bootstrap.Popover.alignment[placement];
17783 this.el.alignTo(on_el, align[0],align[1]);
17784 //var arrow = this.el.select('.arrow',true).first();
17785 //arrow.set(align[2],
17787 this.el.addClass('in');
17790 if (this.el.hasClass('fade')) {
17794 this.hoverState = 'in';
17796 this.fireEvent('show', this);
17801 this.el.setXY([0,0]);
17802 this.el.removeClass('in');
17804 this.hoverState = null;
17806 this.fireEvent('hide', this);
17811 Roo.bootstrap.Popover.alignment = {
17812 'left' : ['r-l', [-10,0], 'right'],
17813 'right' : ['l-r', [10,0], 'left'],
17814 'bottom' : ['t-b', [0,10], 'top'],
17815 'top' : [ 'b-t', [0,-10], 'bottom']
17826 * @class Roo.bootstrap.Progress
17827 * @extends Roo.bootstrap.Component
17828 * Bootstrap Progress class
17829 * @cfg {Boolean} striped striped of the progress bar
17830 * @cfg {Boolean} active animated of the progress bar
17834 * Create a new Progress
17835 * @param {Object} config The config object
17838 Roo.bootstrap.Progress = function(config){
17839 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17842 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17847 getAutoCreate : function(){
17855 cfg.cls += ' progress-striped';
17859 cfg.cls += ' active';
17878 * @class Roo.bootstrap.ProgressBar
17879 * @extends Roo.bootstrap.Component
17880 * Bootstrap ProgressBar class
17881 * @cfg {Number} aria_valuenow aria-value now
17882 * @cfg {Number} aria_valuemin aria-value min
17883 * @cfg {Number} aria_valuemax aria-value max
17884 * @cfg {String} label label for the progress bar
17885 * @cfg {String} panel (success | info | warning | danger )
17886 * @cfg {String} role role of the progress bar
17887 * @cfg {String} sr_only text
17891 * Create a new ProgressBar
17892 * @param {Object} config The config object
17895 Roo.bootstrap.ProgressBar = function(config){
17896 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17899 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17903 aria_valuemax : 100,
17909 getAutoCreate : function()
17914 cls: 'progress-bar',
17915 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17927 cfg.role = this.role;
17930 if(this.aria_valuenow){
17931 cfg['aria-valuenow'] = this.aria_valuenow;
17934 if(this.aria_valuemin){
17935 cfg['aria-valuemin'] = this.aria_valuemin;
17938 if(this.aria_valuemax){
17939 cfg['aria-valuemax'] = this.aria_valuemax;
17942 if(this.label && !this.sr_only){
17943 cfg.html = this.label;
17947 cfg.cls += ' progress-bar-' + this.panel;
17953 update : function(aria_valuenow)
17955 this.aria_valuenow = aria_valuenow;
17957 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17972 * @class Roo.bootstrap.TabGroup
17973 * @extends Roo.bootstrap.Column
17974 * Bootstrap Column class
17975 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17976 * @cfg {Boolean} carousel true to make the group behave like a carousel
17977 * @cfg {Boolean} bullets show bullets for the panels
17978 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17979 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17980 * @cfg {Boolean} showarrow (true|false) show arrow default true
17983 * Create a new TabGroup
17984 * @param {Object} config The config object
17987 Roo.bootstrap.TabGroup = function(config){
17988 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17990 this.navId = Roo.id();
17993 Roo.bootstrap.TabGroup.register(this);
17997 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18000 transition : false,
18005 slideOnTouch : false,
18008 getAutoCreate : function()
18010 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18012 cfg.cls += ' tab-content';
18014 if (this.carousel) {
18015 cfg.cls += ' carousel slide';
18018 cls : 'carousel-inner',
18022 if(this.bullets && !Roo.isTouch){
18025 cls : 'carousel-bullets',
18029 if(this.bullets_cls){
18030 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18037 cfg.cn[0].cn.push(bullets);
18040 if(this.showarrow){
18041 cfg.cn[0].cn.push({
18043 class : 'carousel-arrow',
18047 class : 'carousel-prev',
18051 class : 'fa fa-chevron-left'
18057 class : 'carousel-next',
18061 class : 'fa fa-chevron-right'
18074 initEvents: function()
18076 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18077 // this.el.on("touchstart", this.onTouchStart, this);
18080 if(this.autoslide){
18083 this.slideFn = window.setInterval(function() {
18084 _this.showPanelNext();
18088 if(this.showarrow){
18089 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18090 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18096 // onTouchStart : function(e, el, o)
18098 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18102 // this.showPanelNext();
18106 getChildContainer : function()
18108 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18112 * register a Navigation item
18113 * @param {Roo.bootstrap.NavItem} the navitem to add
18115 register : function(item)
18117 this.tabs.push( item);
18118 item.navId = this.navId; // not really needed..
18123 getActivePanel : function()
18126 Roo.each(this.tabs, function(t) {
18136 getPanelByName : function(n)
18139 Roo.each(this.tabs, function(t) {
18140 if (t.tabId == n) {
18148 indexOfPanel : function(p)
18151 Roo.each(this.tabs, function(t,i) {
18152 if (t.tabId == p.tabId) {
18161 * show a specific panel
18162 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18163 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18165 showPanel : function (pan)
18167 if(this.transition || typeof(pan) == 'undefined'){
18168 Roo.log("waiting for the transitionend");
18172 if (typeof(pan) == 'number') {
18173 pan = this.tabs[pan];
18176 if (typeof(pan) == 'string') {
18177 pan = this.getPanelByName(pan);
18180 var cur = this.getActivePanel();
18183 Roo.log('pan or acitve pan is undefined');
18187 if (pan.tabId == this.getActivePanel().tabId) {
18191 if (false === cur.fireEvent('beforedeactivate')) {
18195 if(this.bullets > 0 && !Roo.isTouch){
18196 this.setActiveBullet(this.indexOfPanel(pan));
18199 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18201 this.transition = true;
18202 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18203 var lr = dir == 'next' ? 'left' : 'right';
18204 pan.el.addClass(dir); // or prev
18205 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18206 cur.el.addClass(lr); // or right
18207 pan.el.addClass(lr);
18210 cur.el.on('transitionend', function() {
18211 Roo.log("trans end?");
18213 pan.el.removeClass([lr,dir]);
18214 pan.setActive(true);
18216 cur.el.removeClass([lr]);
18217 cur.setActive(false);
18219 _this.transition = false;
18221 }, this, { single: true } );
18226 cur.setActive(false);
18227 pan.setActive(true);
18232 showPanelNext : function()
18234 var i = this.indexOfPanel(this.getActivePanel());
18236 if (i >= this.tabs.length - 1 && !this.autoslide) {
18240 if (i >= this.tabs.length - 1 && this.autoslide) {
18244 this.showPanel(this.tabs[i+1]);
18247 showPanelPrev : function()
18249 var i = this.indexOfPanel(this.getActivePanel());
18251 if (i < 1 && !this.autoslide) {
18255 if (i < 1 && this.autoslide) {
18256 i = this.tabs.length;
18259 this.showPanel(this.tabs[i-1]);
18263 addBullet: function()
18265 if(!this.bullets || Roo.isTouch){
18268 var ctr = this.el.select('.carousel-bullets',true).first();
18269 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18270 var bullet = ctr.createChild({
18271 cls : 'bullet bullet-' + i
18272 },ctr.dom.lastChild);
18277 bullet.on('click', (function(e, el, o, ii, t){
18279 e.preventDefault();
18281 this.showPanel(ii);
18283 if(this.autoslide && this.slideFn){
18284 clearInterval(this.slideFn);
18285 this.slideFn = window.setInterval(function() {
18286 _this.showPanelNext();
18290 }).createDelegate(this, [i, bullet], true));
18295 setActiveBullet : function(i)
18301 Roo.each(this.el.select('.bullet', true).elements, function(el){
18302 el.removeClass('selected');
18305 var bullet = this.el.select('.bullet-' + i, true).first();
18311 bullet.addClass('selected');
18322 Roo.apply(Roo.bootstrap.TabGroup, {
18326 * register a Navigation Group
18327 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18329 register : function(navgrp)
18331 this.groups[navgrp.navId] = navgrp;
18335 * fetch a Navigation Group based on the navigation ID
18336 * if one does not exist , it will get created.
18337 * @param {string} the navgroup to add
18338 * @returns {Roo.bootstrap.NavGroup} the navgroup
18340 get: function(navId) {
18341 if (typeof(this.groups[navId]) == 'undefined') {
18342 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18344 return this.groups[navId] ;
18359 * @class Roo.bootstrap.TabPanel
18360 * @extends Roo.bootstrap.Component
18361 * Bootstrap TabPanel class
18362 * @cfg {Boolean} active panel active
18363 * @cfg {String} html panel content
18364 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18365 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18366 * @cfg {String} href click to link..
18370 * Create a new TabPanel
18371 * @param {Object} config The config object
18374 Roo.bootstrap.TabPanel = function(config){
18375 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18379 * Fires when the active status changes
18380 * @param {Roo.bootstrap.TabPanel} this
18381 * @param {Boolean} state the new state
18386 * @event beforedeactivate
18387 * Fires before a tab is de-activated - can be used to do validation on a form.
18388 * @param {Roo.bootstrap.TabPanel} this
18389 * @return {Boolean} false if there is an error
18392 'beforedeactivate': true
18395 this.tabId = this.tabId || Roo.id();
18399 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18407 getAutoCreate : function(){
18410 // item is needed for carousel - not sure if it has any effect otherwise
18411 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18412 html: this.html || ''
18416 cfg.cls += ' active';
18420 cfg.tabId = this.tabId;
18427 initEvents: function()
18429 var p = this.parent();
18431 this.navId = this.navId || p.navId;
18433 if (typeof(this.navId) != 'undefined') {
18434 // not really needed.. but just in case.. parent should be a NavGroup.
18435 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18439 var i = tg.tabs.length - 1;
18441 if(this.active && tg.bullets > 0 && i < tg.bullets){
18442 tg.setActiveBullet(i);
18446 this.el.on('click', this.onClick, this);
18449 this.el.on("touchstart", this.onTouchStart, this);
18450 this.el.on("touchmove", this.onTouchMove, this);
18451 this.el.on("touchend", this.onTouchEnd, this);
18456 onRender : function(ct, position)
18458 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18461 setActive : function(state)
18463 Roo.log("panel - set active " + this.tabId + "=" + state);
18465 this.active = state;
18467 this.el.removeClass('active');
18469 } else if (!this.el.hasClass('active')) {
18470 this.el.addClass('active');
18473 this.fireEvent('changed', this, state);
18476 onClick : function(e)
18478 e.preventDefault();
18480 if(!this.href.length){
18484 window.location.href = this.href;
18493 onTouchStart : function(e)
18495 this.swiping = false;
18497 this.startX = e.browserEvent.touches[0].clientX;
18498 this.startY = e.browserEvent.touches[0].clientY;
18501 onTouchMove : function(e)
18503 this.swiping = true;
18505 this.endX = e.browserEvent.touches[0].clientX;
18506 this.endY = e.browserEvent.touches[0].clientY;
18509 onTouchEnd : function(e)
18516 var tabGroup = this.parent();
18518 if(this.endX > this.startX){ // swiping right
18519 tabGroup.showPanelPrev();
18523 if(this.startX > this.endX){ // swiping left
18524 tabGroup.showPanelNext();
18543 * @class Roo.bootstrap.DateField
18544 * @extends Roo.bootstrap.Input
18545 * Bootstrap DateField class
18546 * @cfg {Number} weekStart default 0
18547 * @cfg {String} viewMode default empty, (months|years)
18548 * @cfg {String} minViewMode default empty, (months|years)
18549 * @cfg {Number} startDate default -Infinity
18550 * @cfg {Number} endDate default Infinity
18551 * @cfg {Boolean} todayHighlight default false
18552 * @cfg {Boolean} todayBtn default false
18553 * @cfg {Boolean} calendarWeeks default false
18554 * @cfg {Object} daysOfWeekDisabled default empty
18555 * @cfg {Boolean} singleMode default false (true | false)
18557 * @cfg {Boolean} keyboardNavigation default true
18558 * @cfg {String} language default en
18561 * Create a new DateField
18562 * @param {Object} config The config object
18565 Roo.bootstrap.DateField = function(config){
18566 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18570 * Fires when this field show.
18571 * @param {Roo.bootstrap.DateField} this
18572 * @param {Mixed} date The date value
18577 * Fires when this field hide.
18578 * @param {Roo.bootstrap.DateField} this
18579 * @param {Mixed} date The date value
18584 * Fires when select a date.
18585 * @param {Roo.bootstrap.DateField} this
18586 * @param {Mixed} date The date value
18590 * @event beforeselect
18591 * Fires when before select a date.
18592 * @param {Roo.bootstrap.DateField} this
18593 * @param {Mixed} date The date value
18595 beforeselect : true
18599 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18602 * @cfg {String} format
18603 * The default date format string which can be overriden for localization support. The format must be
18604 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18608 * @cfg {String} altFormats
18609 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18610 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18612 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18620 todayHighlight : false,
18626 keyboardNavigation: true,
18628 calendarWeeks: false,
18630 startDate: -Infinity,
18634 daysOfWeekDisabled: [],
18638 singleMode : false,
18640 UTCDate: function()
18642 return new Date(Date.UTC.apply(Date, arguments));
18645 UTCToday: function()
18647 var today = new Date();
18648 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18651 getDate: function() {
18652 var d = this.getUTCDate();
18653 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18656 getUTCDate: function() {
18660 setDate: function(d) {
18661 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18664 setUTCDate: function(d) {
18666 this.setValue(this.formatDate(this.date));
18669 onRender: function(ct, position)
18672 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18674 this.language = this.language || 'en';
18675 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18676 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18678 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18679 this.format = this.format || 'm/d/y';
18680 this.isInline = false;
18681 this.isInput = true;
18682 this.component = this.el.select('.add-on', true).first() || false;
18683 this.component = (this.component && this.component.length === 0) ? false : this.component;
18684 this.hasInput = this.component && this.inputEl().length;
18686 if (typeof(this.minViewMode === 'string')) {
18687 switch (this.minViewMode) {
18689 this.minViewMode = 1;
18692 this.minViewMode = 2;
18695 this.minViewMode = 0;
18700 if (typeof(this.viewMode === 'string')) {
18701 switch (this.viewMode) {
18714 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18716 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18718 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18720 this.picker().on('mousedown', this.onMousedown, this);
18721 this.picker().on('click', this.onClick, this);
18723 this.picker().addClass('datepicker-dropdown');
18725 this.startViewMode = this.viewMode;
18727 if(this.singleMode){
18728 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18729 v.setVisibilityMode(Roo.Element.DISPLAY);
18733 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18734 v.setStyle('width', '189px');
18738 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18739 if(!this.calendarWeeks){
18744 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18745 v.attr('colspan', function(i, val){
18746 return parseInt(val) + 1;
18751 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18753 this.setStartDate(this.startDate);
18754 this.setEndDate(this.endDate);
18756 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18763 if(this.isInline) {
18768 picker : function()
18770 return this.pickerEl;
18771 // return this.el.select('.datepicker', true).first();
18774 fillDow: function()
18776 var dowCnt = this.weekStart;
18785 if(this.calendarWeeks){
18793 while (dowCnt < this.weekStart + 7) {
18797 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18801 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18804 fillMonths: function()
18807 var months = this.picker().select('>.datepicker-months td', true).first();
18809 months.dom.innerHTML = '';
18815 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18818 months.createChild(month);
18825 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;
18827 if (this.date < this.startDate) {
18828 this.viewDate = new Date(this.startDate);
18829 } else if (this.date > this.endDate) {
18830 this.viewDate = new Date(this.endDate);
18832 this.viewDate = new Date(this.date);
18840 var d = new Date(this.viewDate),
18841 year = d.getUTCFullYear(),
18842 month = d.getUTCMonth(),
18843 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18844 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18845 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18846 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18847 currentDate = this.date && this.date.valueOf(),
18848 today = this.UTCToday();
18850 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18852 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18854 // this.picker.select('>tfoot th.today').
18855 // .text(dates[this.language].today)
18856 // .toggle(this.todayBtn !== false);
18858 this.updateNavArrows();
18861 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18863 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18865 prevMonth.setUTCDate(day);
18867 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18869 var nextMonth = new Date(prevMonth);
18871 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18873 nextMonth = nextMonth.valueOf();
18875 var fillMonths = false;
18877 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18879 while(prevMonth.valueOf() <= nextMonth) {
18882 if (prevMonth.getUTCDay() === this.weekStart) {
18884 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18892 if(this.calendarWeeks){
18893 // ISO 8601: First week contains first thursday.
18894 // ISO also states week starts on Monday, but we can be more abstract here.
18896 // Start of current week: based on weekstart/current date
18897 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18898 // Thursday of this week
18899 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18900 // First Thursday of year, year from thursday
18901 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18902 // Calendar week: ms between thursdays, div ms per day, div 7 days
18903 calWeek = (th - yth) / 864e5 / 7 + 1;
18905 fillMonths.cn.push({
18913 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18915 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18918 if (this.todayHighlight &&
18919 prevMonth.getUTCFullYear() == today.getFullYear() &&
18920 prevMonth.getUTCMonth() == today.getMonth() &&
18921 prevMonth.getUTCDate() == today.getDate()) {
18922 clsName += ' today';
18925 if (currentDate && prevMonth.valueOf() === currentDate) {
18926 clsName += ' active';
18929 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18930 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18931 clsName += ' disabled';
18934 fillMonths.cn.push({
18936 cls: 'day ' + clsName,
18937 html: prevMonth.getDate()
18940 prevMonth.setDate(prevMonth.getDate()+1);
18943 var currentYear = this.date && this.date.getUTCFullYear();
18944 var currentMonth = this.date && this.date.getUTCMonth();
18946 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18948 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18949 v.removeClass('active');
18951 if(currentYear === year && k === currentMonth){
18952 v.addClass('active');
18955 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18956 v.addClass('disabled');
18962 year = parseInt(year/10, 10) * 10;
18964 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18966 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18969 for (var i = -1; i < 11; i++) {
18970 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18972 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18980 showMode: function(dir)
18983 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18986 Roo.each(this.picker().select('>div',true).elements, function(v){
18987 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18990 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18995 if(this.isInline) {
18999 this.picker().removeClass(['bottom', 'top']);
19001 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19003 * place to the top of element!
19007 this.picker().addClass('top');
19008 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19013 this.picker().addClass('bottom');
19015 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19018 parseDate : function(value)
19020 if(!value || value instanceof Date){
19023 var v = Date.parseDate(value, this.format);
19024 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19025 v = Date.parseDate(value, 'Y-m-d');
19027 if(!v && this.altFormats){
19028 if(!this.altFormatsArray){
19029 this.altFormatsArray = this.altFormats.split("|");
19031 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19032 v = Date.parseDate(value, this.altFormatsArray[i]);
19038 formatDate : function(date, fmt)
19040 return (!date || !(date instanceof Date)) ?
19041 date : date.dateFormat(fmt || this.format);
19044 onFocus : function()
19046 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19050 onBlur : function()
19052 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19054 var d = this.inputEl().getValue();
19061 showPopup : function()
19063 this.picker().show();
19067 this.fireEvent('showpopup', this, this.date);
19070 hidePopup : function()
19072 if(this.isInline) {
19075 this.picker().hide();
19076 this.viewMode = this.startViewMode;
19079 this.fireEvent('hidepopup', this, this.date);
19083 onMousedown: function(e)
19085 e.stopPropagation();
19086 e.preventDefault();
19091 Roo.bootstrap.DateField.superclass.keyup.call(this);
19095 setValue: function(v)
19097 if(this.fireEvent('beforeselect', this, v) !== false){
19098 var d = new Date(this.parseDate(v) ).clearTime();
19100 if(isNaN(d.getTime())){
19101 this.date = this.viewDate = '';
19102 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19106 v = this.formatDate(d);
19108 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19110 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19114 this.fireEvent('select', this, this.date);
19118 getValue: function()
19120 return this.formatDate(this.date);
19123 fireKey: function(e)
19125 if (!this.picker().isVisible()){
19126 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19132 var dateChanged = false,
19134 newDate, newViewDate;
19139 e.preventDefault();
19143 if (!this.keyboardNavigation) {
19146 dir = e.keyCode == 37 ? -1 : 1;
19149 newDate = this.moveYear(this.date, dir);
19150 newViewDate = this.moveYear(this.viewDate, dir);
19151 } else if (e.shiftKey){
19152 newDate = this.moveMonth(this.date, dir);
19153 newViewDate = this.moveMonth(this.viewDate, dir);
19155 newDate = new Date(this.date);
19156 newDate.setUTCDate(this.date.getUTCDate() + dir);
19157 newViewDate = new Date(this.viewDate);
19158 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19160 if (this.dateWithinRange(newDate)){
19161 this.date = newDate;
19162 this.viewDate = newViewDate;
19163 this.setValue(this.formatDate(this.date));
19165 e.preventDefault();
19166 dateChanged = true;
19171 if (!this.keyboardNavigation) {
19174 dir = e.keyCode == 38 ? -1 : 1;
19176 newDate = this.moveYear(this.date, dir);
19177 newViewDate = this.moveYear(this.viewDate, dir);
19178 } else if (e.shiftKey){
19179 newDate = this.moveMonth(this.date, dir);
19180 newViewDate = this.moveMonth(this.viewDate, dir);
19182 newDate = new Date(this.date);
19183 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19184 newViewDate = new Date(this.viewDate);
19185 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19187 if (this.dateWithinRange(newDate)){
19188 this.date = newDate;
19189 this.viewDate = newViewDate;
19190 this.setValue(this.formatDate(this.date));
19192 e.preventDefault();
19193 dateChanged = true;
19197 this.setValue(this.formatDate(this.date));
19199 e.preventDefault();
19202 this.setValue(this.formatDate(this.date));
19216 onClick: function(e)
19218 e.stopPropagation();
19219 e.preventDefault();
19221 var target = e.getTarget();
19223 if(target.nodeName.toLowerCase() === 'i'){
19224 target = Roo.get(target).dom.parentNode;
19227 var nodeName = target.nodeName;
19228 var className = target.className;
19229 var html = target.innerHTML;
19230 //Roo.log(nodeName);
19232 switch(nodeName.toLowerCase()) {
19234 switch(className) {
19240 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19241 switch(this.viewMode){
19243 this.viewDate = this.moveMonth(this.viewDate, dir);
19247 this.viewDate = this.moveYear(this.viewDate, dir);
19253 var date = new Date();
19254 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19256 this.setValue(this.formatDate(this.date));
19263 if (className.indexOf('disabled') < 0) {
19264 this.viewDate.setUTCDate(1);
19265 if (className.indexOf('month') > -1) {
19266 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19268 var year = parseInt(html, 10) || 0;
19269 this.viewDate.setUTCFullYear(year);
19273 if(this.singleMode){
19274 this.setValue(this.formatDate(this.viewDate));
19285 //Roo.log(className);
19286 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19287 var day = parseInt(html, 10) || 1;
19288 var year = this.viewDate.getUTCFullYear(),
19289 month = this.viewDate.getUTCMonth();
19291 if (className.indexOf('old') > -1) {
19298 } else if (className.indexOf('new') > -1) {
19306 //Roo.log([year,month,day]);
19307 this.date = this.UTCDate(year, month, day,0,0,0,0);
19308 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19310 //Roo.log(this.formatDate(this.date));
19311 this.setValue(this.formatDate(this.date));
19318 setStartDate: function(startDate)
19320 this.startDate = startDate || -Infinity;
19321 if (this.startDate !== -Infinity) {
19322 this.startDate = this.parseDate(this.startDate);
19325 this.updateNavArrows();
19328 setEndDate: function(endDate)
19330 this.endDate = endDate || Infinity;
19331 if (this.endDate !== Infinity) {
19332 this.endDate = this.parseDate(this.endDate);
19335 this.updateNavArrows();
19338 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19340 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19341 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19342 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19344 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19345 return parseInt(d, 10);
19348 this.updateNavArrows();
19351 updateNavArrows: function()
19353 if(this.singleMode){
19357 var d = new Date(this.viewDate),
19358 year = d.getUTCFullYear(),
19359 month = d.getUTCMonth();
19361 Roo.each(this.picker().select('.prev', true).elements, function(v){
19363 switch (this.viewMode) {
19366 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19372 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19379 Roo.each(this.picker().select('.next', true).elements, function(v){
19381 switch (this.viewMode) {
19384 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19390 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19398 moveMonth: function(date, dir)
19403 var new_date = new Date(date.valueOf()),
19404 day = new_date.getUTCDate(),
19405 month = new_date.getUTCMonth(),
19406 mag = Math.abs(dir),
19408 dir = dir > 0 ? 1 : -1;
19411 // If going back one month, make sure month is not current month
19412 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19414 return new_date.getUTCMonth() == month;
19416 // If going forward one month, make sure month is as expected
19417 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19419 return new_date.getUTCMonth() != new_month;
19421 new_month = month + dir;
19422 new_date.setUTCMonth(new_month);
19423 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19424 if (new_month < 0 || new_month > 11) {
19425 new_month = (new_month + 12) % 12;
19428 // For magnitudes >1, move one month at a time...
19429 for (var i=0; i<mag; i++) {
19430 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19431 new_date = this.moveMonth(new_date, dir);
19433 // ...then reset the day, keeping it in the new month
19434 new_month = new_date.getUTCMonth();
19435 new_date.setUTCDate(day);
19437 return new_month != new_date.getUTCMonth();
19440 // Common date-resetting loop -- if date is beyond end of month, make it
19443 new_date.setUTCDate(--day);
19444 new_date.setUTCMonth(new_month);
19449 moveYear: function(date, dir)
19451 return this.moveMonth(date, dir*12);
19454 dateWithinRange: function(date)
19456 return date >= this.startDate && date <= this.endDate;
19462 this.picker().remove();
19465 validateValue : function(value)
19467 if(this.getVisibilityEl().hasClass('hidden')){
19471 if(value.length < 1) {
19472 if(this.allowBlank){
19478 if(value.length < this.minLength){
19481 if(value.length > this.maxLength){
19485 var vt = Roo.form.VTypes;
19486 if(!vt[this.vtype](value, this)){
19490 if(typeof this.validator == "function"){
19491 var msg = this.validator(value);
19497 if(this.regex && !this.regex.test(value)){
19501 if(typeof(this.parseDate(value)) == 'undefined'){
19505 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19509 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19519 this.date = this.viewDate = '';
19521 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19526 Roo.apply(Roo.bootstrap.DateField, {
19537 html: '<i class="fa fa-arrow-left"/>'
19547 html: '<i class="fa fa-arrow-right"/>'
19589 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19590 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19591 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19592 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19593 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19606 navFnc: 'FullYear',
19611 navFnc: 'FullYear',
19616 Roo.apply(Roo.bootstrap.DateField, {
19620 cls: 'datepicker dropdown-menu roo-dynamic',
19624 cls: 'datepicker-days',
19628 cls: 'table-condensed',
19630 Roo.bootstrap.DateField.head,
19634 Roo.bootstrap.DateField.footer
19641 cls: 'datepicker-months',
19645 cls: 'table-condensed',
19647 Roo.bootstrap.DateField.head,
19648 Roo.bootstrap.DateField.content,
19649 Roo.bootstrap.DateField.footer
19656 cls: 'datepicker-years',
19660 cls: 'table-condensed',
19662 Roo.bootstrap.DateField.head,
19663 Roo.bootstrap.DateField.content,
19664 Roo.bootstrap.DateField.footer
19683 * @class Roo.bootstrap.TimeField
19684 * @extends Roo.bootstrap.Input
19685 * Bootstrap DateField class
19689 * Create a new TimeField
19690 * @param {Object} config The config object
19693 Roo.bootstrap.TimeField = function(config){
19694 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19698 * Fires when this field show.
19699 * @param {Roo.bootstrap.DateField} thisthis
19700 * @param {Mixed} date The date value
19705 * Fires when this field hide.
19706 * @param {Roo.bootstrap.DateField} this
19707 * @param {Mixed} date The date value
19712 * Fires when select a date.
19713 * @param {Roo.bootstrap.DateField} this
19714 * @param {Mixed} date The date value
19720 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19723 * @cfg {String} format
19724 * The default time format string which can be overriden for localization support. The format must be
19725 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19729 onRender: function(ct, position)
19732 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19734 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19736 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19738 this.pop = this.picker().select('>.datepicker-time',true).first();
19739 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19741 this.picker().on('mousedown', this.onMousedown, this);
19742 this.picker().on('click', this.onClick, this);
19744 this.picker().addClass('datepicker-dropdown');
19749 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19750 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19751 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19752 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19753 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19754 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19758 fireKey: function(e){
19759 if (!this.picker().isVisible()){
19760 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19766 e.preventDefault();
19774 this.onTogglePeriod();
19777 this.onIncrementMinutes();
19780 this.onDecrementMinutes();
19789 onClick: function(e) {
19790 e.stopPropagation();
19791 e.preventDefault();
19794 picker : function()
19796 return this.el.select('.datepicker', true).first();
19799 fillTime: function()
19801 var time = this.pop.select('tbody', true).first();
19803 time.dom.innerHTML = '';
19818 cls: 'hours-up glyphicon glyphicon-chevron-up'
19838 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19859 cls: 'timepicker-hour',
19874 cls: 'timepicker-minute',
19889 cls: 'btn btn-primary period',
19911 cls: 'hours-down glyphicon glyphicon-chevron-down'
19931 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19949 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19956 var hours = this.time.getHours();
19957 var minutes = this.time.getMinutes();
19970 hours = hours - 12;
19974 hours = '0' + hours;
19978 minutes = '0' + minutes;
19981 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19982 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19983 this.pop.select('button', true).first().dom.innerHTML = period;
19989 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19991 var cls = ['bottom'];
19993 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20000 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20005 this.picker().addClass(cls.join('-'));
20009 Roo.each(cls, function(c){
20011 _this.picker().setTop(_this.inputEl().getHeight());
20015 _this.picker().setTop(0 - _this.picker().getHeight());
20020 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20024 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20031 onFocus : function()
20033 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20037 onBlur : function()
20039 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20045 this.picker().show();
20050 this.fireEvent('show', this, this.date);
20055 this.picker().hide();
20058 this.fireEvent('hide', this, this.date);
20061 setTime : function()
20064 this.setValue(this.time.format(this.format));
20066 this.fireEvent('select', this, this.date);
20071 onMousedown: function(e){
20072 e.stopPropagation();
20073 e.preventDefault();
20076 onIncrementHours: function()
20078 Roo.log('onIncrementHours');
20079 this.time = this.time.add(Date.HOUR, 1);
20084 onDecrementHours: function()
20086 Roo.log('onDecrementHours');
20087 this.time = this.time.add(Date.HOUR, -1);
20091 onIncrementMinutes: function()
20093 Roo.log('onIncrementMinutes');
20094 this.time = this.time.add(Date.MINUTE, 1);
20098 onDecrementMinutes: function()
20100 Roo.log('onDecrementMinutes');
20101 this.time = this.time.add(Date.MINUTE, -1);
20105 onTogglePeriod: function()
20107 Roo.log('onTogglePeriod');
20108 this.time = this.time.add(Date.HOUR, 12);
20115 Roo.apply(Roo.bootstrap.TimeField, {
20145 cls: 'btn btn-info ok',
20157 Roo.apply(Roo.bootstrap.TimeField, {
20161 cls: 'datepicker dropdown-menu',
20165 cls: 'datepicker-time',
20169 cls: 'table-condensed',
20171 Roo.bootstrap.TimeField.content,
20172 Roo.bootstrap.TimeField.footer
20191 * @class Roo.bootstrap.MonthField
20192 * @extends Roo.bootstrap.Input
20193 * Bootstrap MonthField class
20195 * @cfg {String} language default en
20198 * Create a new MonthField
20199 * @param {Object} config The config object
20202 Roo.bootstrap.MonthField = function(config){
20203 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20208 * Fires when this field show.
20209 * @param {Roo.bootstrap.MonthField} this
20210 * @param {Mixed} date The date value
20215 * Fires when this field hide.
20216 * @param {Roo.bootstrap.MonthField} this
20217 * @param {Mixed} date The date value
20222 * Fires when select a date.
20223 * @param {Roo.bootstrap.MonthField} this
20224 * @param {String} oldvalue The old value
20225 * @param {String} newvalue The new value
20231 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20233 onRender: function(ct, position)
20236 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20238 this.language = this.language || 'en';
20239 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20240 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20242 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20243 this.isInline = false;
20244 this.isInput = true;
20245 this.component = this.el.select('.add-on', true).first() || false;
20246 this.component = (this.component && this.component.length === 0) ? false : this.component;
20247 this.hasInput = this.component && this.inputEL().length;
20249 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20251 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20253 this.picker().on('mousedown', this.onMousedown, this);
20254 this.picker().on('click', this.onClick, this);
20256 this.picker().addClass('datepicker-dropdown');
20258 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20259 v.setStyle('width', '189px');
20266 if(this.isInline) {
20272 setValue: function(v, suppressEvent)
20274 var o = this.getValue();
20276 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20280 if(suppressEvent !== true){
20281 this.fireEvent('select', this, o, v);
20286 getValue: function()
20291 onClick: function(e)
20293 e.stopPropagation();
20294 e.preventDefault();
20296 var target = e.getTarget();
20298 if(target.nodeName.toLowerCase() === 'i'){
20299 target = Roo.get(target).dom.parentNode;
20302 var nodeName = target.nodeName;
20303 var className = target.className;
20304 var html = target.innerHTML;
20306 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20310 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20312 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20318 picker : function()
20320 return this.pickerEl;
20323 fillMonths: function()
20326 var months = this.picker().select('>.datepicker-months td', true).first();
20328 months.dom.innerHTML = '';
20334 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20337 months.createChild(month);
20346 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20347 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20350 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20351 e.removeClass('active');
20353 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20354 e.addClass('active');
20361 if(this.isInline) {
20365 this.picker().removeClass(['bottom', 'top']);
20367 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20369 * place to the top of element!
20373 this.picker().addClass('top');
20374 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20379 this.picker().addClass('bottom');
20381 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20384 onFocus : function()
20386 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20390 onBlur : function()
20392 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20394 var d = this.inputEl().getValue();
20403 this.picker().show();
20404 this.picker().select('>.datepicker-months', true).first().show();
20408 this.fireEvent('show', this, this.date);
20413 if(this.isInline) {
20416 this.picker().hide();
20417 this.fireEvent('hide', this, this.date);
20421 onMousedown: function(e)
20423 e.stopPropagation();
20424 e.preventDefault();
20429 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20433 fireKey: function(e)
20435 if (!this.picker().isVisible()){
20436 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20447 e.preventDefault();
20451 dir = e.keyCode == 37 ? -1 : 1;
20453 this.vIndex = this.vIndex + dir;
20455 if(this.vIndex < 0){
20459 if(this.vIndex > 11){
20463 if(isNaN(this.vIndex)){
20467 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20473 dir = e.keyCode == 38 ? -1 : 1;
20475 this.vIndex = this.vIndex + dir * 4;
20477 if(this.vIndex < 0){
20481 if(this.vIndex > 11){
20485 if(isNaN(this.vIndex)){
20489 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20494 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20495 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20499 e.preventDefault();
20502 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20503 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20519 this.picker().remove();
20524 Roo.apply(Roo.bootstrap.MonthField, {
20543 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20544 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20549 Roo.apply(Roo.bootstrap.MonthField, {
20553 cls: 'datepicker dropdown-menu roo-dynamic',
20557 cls: 'datepicker-months',
20561 cls: 'table-condensed',
20563 Roo.bootstrap.DateField.content
20583 * @class Roo.bootstrap.CheckBox
20584 * @extends Roo.bootstrap.Input
20585 * Bootstrap CheckBox class
20587 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20588 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20589 * @cfg {String} boxLabel The text that appears beside the checkbox
20590 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20591 * @cfg {Boolean} checked initnal the element
20592 * @cfg {Boolean} inline inline the element (default false)
20593 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20594 * @cfg {String} tooltip label tooltip
20597 * Create a new CheckBox
20598 * @param {Object} config The config object
20601 Roo.bootstrap.CheckBox = function(config){
20602 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20607 * Fires when the element is checked or unchecked.
20608 * @param {Roo.bootstrap.CheckBox} this This input
20609 * @param {Boolean} checked The new checked value
20614 * Fires when the element is click.
20615 * @param {Roo.bootstrap.CheckBox} this This input
20622 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20624 inputType: 'checkbox',
20633 getAutoCreate : function()
20635 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20641 cfg.cls = 'form-group ' + this.inputType; //input-group
20644 cfg.cls += ' ' + this.inputType + '-inline';
20650 type : this.inputType,
20651 value : this.inputValue,
20652 cls : 'roo-' + this.inputType, //'form-box',
20653 placeholder : this.placeholder || ''
20657 if(this.inputType != 'radio'){
20661 cls : 'roo-hidden-value',
20662 value : this.checked ? this.inputValue : this.valueOff
20667 if (this.weight) { // Validity check?
20668 cfg.cls += " " + this.inputType + "-" + this.weight;
20671 if (this.disabled) {
20672 input.disabled=true;
20676 input.checked = this.checked;
20681 input.name = this.name;
20683 if(this.inputType != 'radio'){
20684 hidden.name = this.name;
20685 input.name = '_hidden_' + this.name;
20690 input.cls += ' input-' + this.size;
20695 ['xs','sm','md','lg'].map(function(size){
20696 if (settings[size]) {
20697 cfg.cls += ' col-' + size + '-' + settings[size];
20701 var inputblock = input;
20703 if (this.before || this.after) {
20706 cls : 'input-group',
20711 inputblock.cn.push({
20713 cls : 'input-group-addon',
20718 inputblock.cn.push(input);
20720 if(this.inputType != 'radio'){
20721 inputblock.cn.push(hidden);
20725 inputblock.cn.push({
20727 cls : 'input-group-addon',
20734 if (align ==='left' && this.fieldLabel.length) {
20735 // Roo.log("left and has label");
20740 cls : 'control-label',
20741 html : this.fieldLabel
20751 if(this.labelWidth > 12){
20752 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20755 if(this.labelWidth < 13 && this.labelmd == 0){
20756 this.labelmd = this.labelWidth;
20759 if(this.labellg > 0){
20760 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20761 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20764 if(this.labelmd > 0){
20765 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20766 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20769 if(this.labelsm > 0){
20770 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20771 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20774 if(this.labelxs > 0){
20775 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20776 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20779 } else if ( this.fieldLabel.length) {
20780 // Roo.log(" label");
20784 tag: this.boxLabel ? 'span' : 'label',
20786 cls: 'control-label box-input-label',
20787 //cls : 'input-group-addon',
20788 html : this.fieldLabel
20797 // Roo.log(" no label && no align");
20798 cfg.cn = [ inputblock ] ;
20804 var boxLabelCfg = {
20806 //'for': id, // box label is handled by onclick - so no for...
20808 html: this.boxLabel
20812 boxLabelCfg.tooltip = this.tooltip;
20815 cfg.cn.push(boxLabelCfg);
20818 if(this.inputType != 'radio'){
20819 cfg.cn.push(hidden);
20827 * return the real input element.
20829 inputEl: function ()
20831 return this.el.select('input.roo-' + this.inputType,true).first();
20833 hiddenEl: function ()
20835 return this.el.select('input.roo-hidden-value',true).first();
20838 labelEl: function()
20840 return this.el.select('label.control-label',true).first();
20842 /* depricated... */
20846 return this.labelEl();
20849 boxLabelEl: function()
20851 return this.el.select('label.box-label',true).first();
20854 initEvents : function()
20856 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20858 this.inputEl().on('click', this.onClick, this);
20860 if (this.boxLabel) {
20861 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20864 this.startValue = this.getValue();
20867 Roo.bootstrap.CheckBox.register(this);
20871 onClick : function(e)
20873 if(this.fireEvent('click', this, e) !== false){
20874 this.setChecked(!this.checked);
20879 setChecked : function(state,suppressEvent)
20881 this.startValue = this.getValue();
20883 if(this.inputType == 'radio'){
20885 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20886 e.dom.checked = false;
20889 this.inputEl().dom.checked = true;
20891 this.inputEl().dom.value = this.inputValue;
20893 if(suppressEvent !== true){
20894 this.fireEvent('check', this, true);
20902 this.checked = state;
20904 this.inputEl().dom.checked = state;
20907 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20909 if(suppressEvent !== true){
20910 this.fireEvent('check', this, state);
20916 getValue : function()
20918 if(this.inputType == 'radio'){
20919 return this.getGroupValue();
20922 return this.hiddenEl().dom.value;
20926 getGroupValue : function()
20928 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20932 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20935 setValue : function(v,suppressEvent)
20937 if(this.inputType == 'radio'){
20938 this.setGroupValue(v, suppressEvent);
20942 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20947 setGroupValue : function(v, suppressEvent)
20949 this.startValue = this.getValue();
20951 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20952 e.dom.checked = false;
20954 if(e.dom.value == v){
20955 e.dom.checked = true;
20959 if(suppressEvent !== true){
20960 this.fireEvent('check', this, true);
20968 validate : function()
20970 if(this.getVisibilityEl().hasClass('hidden')){
20976 (this.inputType == 'radio' && this.validateRadio()) ||
20977 (this.inputType == 'checkbox' && this.validateCheckbox())
20983 this.markInvalid();
20987 validateRadio : function()
20989 if(this.getVisibilityEl().hasClass('hidden')){
20993 if(this.allowBlank){
20999 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21000 if(!e.dom.checked){
21012 validateCheckbox : function()
21015 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21016 //return (this.getValue() == this.inputValue) ? true : false;
21019 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21027 for(var i in group){
21028 if(group[i].el.isVisible(true)){
21036 for(var i in group){
21041 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21048 * Mark this field as valid
21050 markValid : function()
21054 this.fireEvent('valid', this);
21056 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21059 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21066 if(this.inputType == 'radio'){
21067 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21068 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21069 e.findParent('.form-group', false, true).addClass(_this.validClass);
21076 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21077 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21081 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21087 for(var i in group){
21088 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21089 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21094 * Mark this field as invalid
21095 * @param {String} msg The validation message
21097 markInvalid : function(msg)
21099 if(this.allowBlank){
21105 this.fireEvent('invalid', this, msg);
21107 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21110 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21114 label.markInvalid();
21117 if(this.inputType == 'radio'){
21118 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21119 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21120 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21127 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21128 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21132 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21138 for(var i in group){
21139 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21140 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21145 clearInvalid : function()
21147 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21149 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21151 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21153 if (label && label.iconEl) {
21154 label.iconEl.removeClass(label.validClass);
21155 label.iconEl.removeClass(label.invalidClass);
21159 disable : function()
21161 if(this.inputType != 'radio'){
21162 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21169 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21170 _this.getActionEl().addClass(this.disabledClass);
21171 e.dom.disabled = true;
21175 this.disabled = true;
21176 this.fireEvent("disable", this);
21180 enable : function()
21182 if(this.inputType != 'radio'){
21183 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21190 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21191 _this.getActionEl().removeClass(this.disabledClass);
21192 e.dom.disabled = false;
21196 this.disabled = false;
21197 this.fireEvent("enable", this);
21201 setBoxLabel : function(v)
21206 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21212 Roo.apply(Roo.bootstrap.CheckBox, {
21217 * register a CheckBox Group
21218 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21220 register : function(checkbox)
21222 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21223 this.groups[checkbox.groupId] = {};
21226 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21230 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21234 * fetch a CheckBox Group based on the group ID
21235 * @param {string} the group ID
21236 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21238 get: function(groupId) {
21239 if (typeof(this.groups[groupId]) == 'undefined') {
21243 return this.groups[groupId] ;
21256 * @class Roo.bootstrap.Radio
21257 * @extends Roo.bootstrap.Component
21258 * Bootstrap Radio class
21259 * @cfg {String} boxLabel - the label associated
21260 * @cfg {String} value - the value of radio
21263 * Create a new Radio
21264 * @param {Object} config The config object
21266 Roo.bootstrap.Radio = function(config){
21267 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21271 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21277 getAutoCreate : function()
21281 cls : 'form-group radio',
21286 html : this.boxLabel
21294 initEvents : function()
21296 this.parent().register(this);
21298 this.el.on('click', this.onClick, this);
21302 onClick : function(e)
21304 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21305 this.setChecked(true);
21309 setChecked : function(state, suppressEvent)
21311 this.parent().setValue(this.value, suppressEvent);
21315 setBoxLabel : function(v)
21320 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21335 * @class Roo.bootstrap.SecurePass
21336 * @extends Roo.bootstrap.Input
21337 * Bootstrap SecurePass class
21341 * Create a new SecurePass
21342 * @param {Object} config The config object
21345 Roo.bootstrap.SecurePass = function (config) {
21346 // these go here, so the translation tool can replace them..
21348 PwdEmpty: "Please type a password, and then retype it to confirm.",
21349 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21350 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21351 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21352 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21353 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21354 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21355 TooWeak: "Your password is Too Weak."
21357 this.meterLabel = "Password strength:";
21358 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21359 this.meterClass = [
21360 "roo-password-meter-tooweak",
21361 "roo-password-meter-weak",
21362 "roo-password-meter-medium",
21363 "roo-password-meter-strong",
21364 "roo-password-meter-grey"
21369 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21372 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21374 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21376 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21377 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21378 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21379 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21380 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21381 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21382 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21392 * @cfg {String/Object} Label for the strength meter (defaults to
21393 * 'Password strength:')
21398 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21399 * ['Weak', 'Medium', 'Strong'])
21402 pwdStrengths: false,
21415 initEvents: function ()
21417 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21419 if (this.el.is('input[type=password]') && Roo.isSafari) {
21420 this.el.on('keydown', this.SafariOnKeyDown, this);
21423 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21426 onRender: function (ct, position)
21428 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21429 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21430 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21432 this.trigger.createChild({
21437 cls: 'roo-password-meter-grey col-xs-12',
21440 //width: this.meterWidth + 'px'
21444 cls: 'roo-password-meter-text'
21450 if (this.hideTrigger) {
21451 this.trigger.setDisplayed(false);
21453 this.setSize(this.width || '', this.height || '');
21456 onDestroy: function ()
21458 if (this.trigger) {
21459 this.trigger.removeAllListeners();
21460 this.trigger.remove();
21463 this.wrap.remove();
21465 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21468 checkStrength: function ()
21470 var pwd = this.inputEl().getValue();
21471 if (pwd == this._lastPwd) {
21476 if (this.ClientSideStrongPassword(pwd)) {
21478 } else if (this.ClientSideMediumPassword(pwd)) {
21480 } else if (this.ClientSideWeakPassword(pwd)) {
21486 Roo.log('strength1: ' + strength);
21488 //var pm = this.trigger.child('div/div/div').dom;
21489 var pm = this.trigger.child('div/div');
21490 pm.removeClass(this.meterClass);
21491 pm.addClass(this.meterClass[strength]);
21494 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21496 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21498 this._lastPwd = pwd;
21502 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21504 this._lastPwd = '';
21506 var pm = this.trigger.child('div/div');
21507 pm.removeClass(this.meterClass);
21508 pm.addClass('roo-password-meter-grey');
21511 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21514 this.inputEl().dom.type='password';
21517 validateValue: function (value)
21520 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21523 if (value.length == 0) {
21524 if (this.allowBlank) {
21525 this.clearInvalid();
21529 this.markInvalid(this.errors.PwdEmpty);
21530 this.errorMsg = this.errors.PwdEmpty;
21538 if ('[\x21-\x7e]*'.match(value)) {
21539 this.markInvalid(this.errors.PwdBadChar);
21540 this.errorMsg = this.errors.PwdBadChar;
21543 if (value.length < 6) {
21544 this.markInvalid(this.errors.PwdShort);
21545 this.errorMsg = this.errors.PwdShort;
21548 if (value.length > 16) {
21549 this.markInvalid(this.errors.PwdLong);
21550 this.errorMsg = this.errors.PwdLong;
21554 if (this.ClientSideStrongPassword(value)) {
21556 } else if (this.ClientSideMediumPassword(value)) {
21558 } else if (this.ClientSideWeakPassword(value)) {
21565 if (strength < 2) {
21566 //this.markInvalid(this.errors.TooWeak);
21567 this.errorMsg = this.errors.TooWeak;
21572 console.log('strength2: ' + strength);
21574 //var pm = this.trigger.child('div/div/div').dom;
21576 var pm = this.trigger.child('div/div');
21577 pm.removeClass(this.meterClass);
21578 pm.addClass(this.meterClass[strength]);
21580 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21582 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21584 this.errorMsg = '';
21588 CharacterSetChecks: function (type)
21591 this.fResult = false;
21594 isctype: function (character, type)
21597 case this.kCapitalLetter:
21598 if (character >= 'A' && character <= 'Z') {
21603 case this.kSmallLetter:
21604 if (character >= 'a' && character <= 'z') {
21610 if (character >= '0' && character <= '9') {
21615 case this.kPunctuation:
21616 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21627 IsLongEnough: function (pwd, size)
21629 return !(pwd == null || isNaN(size) || pwd.length < size);
21632 SpansEnoughCharacterSets: function (word, nb)
21634 if (!this.IsLongEnough(word, nb))
21639 var characterSetChecks = new Array(
21640 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21641 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21644 for (var index = 0; index < word.length; ++index) {
21645 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21646 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21647 characterSetChecks[nCharSet].fResult = true;
21654 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21655 if (characterSetChecks[nCharSet].fResult) {
21660 if (nCharSets < nb) {
21666 ClientSideStrongPassword: function (pwd)
21668 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21671 ClientSideMediumPassword: function (pwd)
21673 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21676 ClientSideWeakPassword: function (pwd)
21678 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21681 })//<script type="text/javascript">
21684 * Based Ext JS Library 1.1.1
21685 * Copyright(c) 2006-2007, Ext JS, LLC.
21691 * @class Roo.HtmlEditorCore
21692 * @extends Roo.Component
21693 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21695 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21698 Roo.HtmlEditorCore = function(config){
21701 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21706 * @event initialize
21707 * Fires when the editor is fully initialized (including the iframe)
21708 * @param {Roo.HtmlEditorCore} this
21713 * Fires when the editor is first receives the focus. Any insertion must wait
21714 * until after this event.
21715 * @param {Roo.HtmlEditorCore} this
21719 * @event beforesync
21720 * Fires before the textarea is updated with content from the editor iframe. Return false
21721 * to cancel the sync.
21722 * @param {Roo.HtmlEditorCore} this
21723 * @param {String} html
21727 * @event beforepush
21728 * Fires before the iframe editor is updated with content from the textarea. Return false
21729 * to cancel the push.
21730 * @param {Roo.HtmlEditorCore} this
21731 * @param {String} html
21736 * Fires when the textarea is updated with content from the editor iframe.
21737 * @param {Roo.HtmlEditorCore} this
21738 * @param {String} html
21743 * Fires when the iframe editor is updated with content from the textarea.
21744 * @param {Roo.HtmlEditorCore} this
21745 * @param {String} html
21750 * @event editorevent
21751 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21752 * @param {Roo.HtmlEditorCore} this
21758 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21760 // defaults : white / black...
21761 this.applyBlacklists();
21768 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21772 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21778 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21783 * @cfg {Number} height (in pixels)
21787 * @cfg {Number} width (in pixels)
21792 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21795 stylesheets: false,
21800 // private properties
21801 validationEvent : false,
21803 initialized : false,
21805 sourceEditMode : false,
21806 onFocus : Roo.emptyFn,
21808 hideMode:'offsets',
21812 // blacklist + whitelisted elements..
21819 * Protected method that will not generally be called directly. It
21820 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21821 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21823 getDocMarkup : function(){
21827 // inherit styels from page...??
21828 if (this.stylesheets === false) {
21830 Roo.get(document.head).select('style').each(function(node) {
21831 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21834 Roo.get(document.head).select('link').each(function(node) {
21835 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21838 } else if (!this.stylesheets.length) {
21840 st = '<style type="text/css">' +
21841 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21844 st = '<style type="text/css">' +
21849 st += '<style type="text/css">' +
21850 'IMG { cursor: pointer } ' +
21853 var cls = 'roo-htmleditor-body';
21855 if(this.bodyCls.length){
21856 cls += ' ' + this.bodyCls;
21859 return '<html><head>' + st +
21860 //<style type="text/css">' +
21861 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21863 ' </head><body class="' + cls + '"></body></html>';
21867 onRender : function(ct, position)
21870 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21871 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21874 this.el.dom.style.border = '0 none';
21875 this.el.dom.setAttribute('tabIndex', -1);
21876 this.el.addClass('x-hidden hide');
21880 if(Roo.isIE){ // fix IE 1px bogus margin
21881 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21885 this.frameId = Roo.id();
21889 var iframe = this.owner.wrap.createChild({
21891 cls: 'form-control', // bootstrap..
21893 name: this.frameId,
21894 frameBorder : 'no',
21895 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21900 this.iframe = iframe.dom;
21902 this.assignDocWin();
21904 this.doc.designMode = 'on';
21907 this.doc.write(this.getDocMarkup());
21911 var task = { // must defer to wait for browser to be ready
21913 //console.log("run task?" + this.doc.readyState);
21914 this.assignDocWin();
21915 if(this.doc.body || this.doc.readyState == 'complete'){
21917 this.doc.designMode="on";
21921 Roo.TaskMgr.stop(task);
21922 this.initEditor.defer(10, this);
21929 Roo.TaskMgr.start(task);
21934 onResize : function(w, h)
21936 Roo.log('resize: ' +w + ',' + h );
21937 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21941 if(typeof w == 'number'){
21943 this.iframe.style.width = w + 'px';
21945 if(typeof h == 'number'){
21947 this.iframe.style.height = h + 'px';
21949 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21956 * Toggles the editor between standard and source edit mode.
21957 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21959 toggleSourceEdit : function(sourceEditMode){
21961 this.sourceEditMode = sourceEditMode === true;
21963 if(this.sourceEditMode){
21965 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21968 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21969 //this.iframe.className = '';
21972 //this.setSize(this.owner.wrap.getSize());
21973 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21980 * Protected method that will not generally be called directly. If you need/want
21981 * custom HTML cleanup, this is the method you should override.
21982 * @param {String} html The HTML to be cleaned
21983 * return {String} The cleaned HTML
21985 cleanHtml : function(html){
21986 html = String(html);
21987 if(html.length > 5){
21988 if(Roo.isSafari){ // strip safari nonsense
21989 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21992 if(html == ' '){
21999 * HTML Editor -> Textarea
22000 * Protected method that will not generally be called directly. Syncs the contents
22001 * of the editor iframe with the textarea.
22003 syncValue : function(){
22004 if(this.initialized){
22005 var bd = (this.doc.body || this.doc.documentElement);
22006 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22007 var html = bd.innerHTML;
22009 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22010 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22012 html = '<div style="'+m[0]+'">' + html + '</div>';
22015 html = this.cleanHtml(html);
22016 // fix up the special chars.. normaly like back quotes in word...
22017 // however we do not want to do this with chinese..
22018 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22019 var cc = b.charCodeAt();
22021 (cc >= 0x4E00 && cc < 0xA000 ) ||
22022 (cc >= 0x3400 && cc < 0x4E00 ) ||
22023 (cc >= 0xf900 && cc < 0xfb00 )
22029 if(this.owner.fireEvent('beforesync', this, html) !== false){
22030 this.el.dom.value = html;
22031 this.owner.fireEvent('sync', this, html);
22037 * Protected method that will not generally be called directly. Pushes the value of the textarea
22038 * into the iframe editor.
22040 pushValue : function(){
22041 if(this.initialized){
22042 var v = this.el.dom.value.trim();
22044 // if(v.length < 1){
22048 if(this.owner.fireEvent('beforepush', this, v) !== false){
22049 var d = (this.doc.body || this.doc.documentElement);
22051 this.cleanUpPaste();
22052 this.el.dom.value = d.innerHTML;
22053 this.owner.fireEvent('push', this, v);
22059 deferFocus : function(){
22060 this.focus.defer(10, this);
22064 focus : function(){
22065 if(this.win && !this.sourceEditMode){
22072 assignDocWin: function()
22074 var iframe = this.iframe;
22077 this.doc = iframe.contentWindow.document;
22078 this.win = iframe.contentWindow;
22080 // if (!Roo.get(this.frameId)) {
22083 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22084 // this.win = Roo.get(this.frameId).dom.contentWindow;
22086 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22090 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22091 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22096 initEditor : function(){
22097 //console.log("INIT EDITOR");
22098 this.assignDocWin();
22102 this.doc.designMode="on";
22104 this.doc.write(this.getDocMarkup());
22107 var dbody = (this.doc.body || this.doc.documentElement);
22108 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22109 // this copies styles from the containing element into thsi one..
22110 // not sure why we need all of this..
22111 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22113 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22114 //ss['background-attachment'] = 'fixed'; // w3c
22115 dbody.bgProperties = 'fixed'; // ie
22116 //Roo.DomHelper.applyStyles(dbody, ss);
22117 Roo.EventManager.on(this.doc, {
22118 //'mousedown': this.onEditorEvent,
22119 'mouseup': this.onEditorEvent,
22120 'dblclick': this.onEditorEvent,
22121 'click': this.onEditorEvent,
22122 'keyup': this.onEditorEvent,
22127 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22129 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22130 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22132 this.initialized = true;
22134 this.owner.fireEvent('initialize', this);
22139 onDestroy : function(){
22145 //for (var i =0; i < this.toolbars.length;i++) {
22146 // // fixme - ask toolbars for heights?
22147 // this.toolbars[i].onDestroy();
22150 //this.wrap.dom.innerHTML = '';
22151 //this.wrap.remove();
22156 onFirstFocus : function(){
22158 this.assignDocWin();
22161 this.activated = true;
22164 if(Roo.isGecko){ // prevent silly gecko errors
22166 var s = this.win.getSelection();
22167 if(!s.focusNode || s.focusNode.nodeType != 3){
22168 var r = s.getRangeAt(0);
22169 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22174 this.execCmd('useCSS', true);
22175 this.execCmd('styleWithCSS', false);
22178 this.owner.fireEvent('activate', this);
22182 adjustFont: function(btn){
22183 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22184 //if(Roo.isSafari){ // safari
22187 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22188 if(Roo.isSafari){ // safari
22189 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22190 v = (v < 10) ? 10 : v;
22191 v = (v > 48) ? 48 : v;
22192 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22197 v = Math.max(1, v+adjust);
22199 this.execCmd('FontSize', v );
22202 onEditorEvent : function(e)
22204 this.owner.fireEvent('editorevent', this, e);
22205 // this.updateToolbar();
22206 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22209 insertTag : function(tg)
22211 // could be a bit smarter... -> wrap the current selected tRoo..
22212 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22214 range = this.createRange(this.getSelection());
22215 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22216 wrappingNode.appendChild(range.extractContents());
22217 range.insertNode(wrappingNode);
22224 this.execCmd("formatblock", tg);
22228 insertText : function(txt)
22232 var range = this.createRange();
22233 range.deleteContents();
22234 //alert(Sender.getAttribute('label'));
22236 range.insertNode(this.doc.createTextNode(txt));
22242 * Executes a Midas editor command on the editor document and performs necessary focus and
22243 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22244 * @param {String} cmd The Midas command
22245 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22247 relayCmd : function(cmd, value){
22249 this.execCmd(cmd, value);
22250 this.owner.fireEvent('editorevent', this);
22251 //this.updateToolbar();
22252 this.owner.deferFocus();
22256 * Executes a Midas editor command directly on the editor document.
22257 * For visual commands, you should use {@link #relayCmd} instead.
22258 * <b>This should only be called after the editor is initialized.</b>
22259 * @param {String} cmd The Midas command
22260 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22262 execCmd : function(cmd, value){
22263 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22270 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22272 * @param {String} text | dom node..
22274 insertAtCursor : function(text)
22277 if(!this.activated){
22283 var r = this.doc.selection.createRange();
22294 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22298 // from jquery ui (MIT licenced)
22300 var win = this.win;
22302 if (win.getSelection && win.getSelection().getRangeAt) {
22303 range = win.getSelection().getRangeAt(0);
22304 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22305 range.insertNode(node);
22306 } else if (win.document.selection && win.document.selection.createRange) {
22307 // no firefox support
22308 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22309 win.document.selection.createRange().pasteHTML(txt);
22311 // no firefox support
22312 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22313 this.execCmd('InsertHTML', txt);
22322 mozKeyPress : function(e){
22324 var c = e.getCharCode(), cmd;
22327 c = String.fromCharCode(c).toLowerCase();
22341 this.cleanUpPaste.defer(100, this);
22349 e.preventDefault();
22357 fixKeys : function(){ // load time branching for fastest keydown performance
22359 return function(e){
22360 var k = e.getKey(), r;
22363 r = this.doc.selection.createRange();
22366 r.pasteHTML('    ');
22373 r = this.doc.selection.createRange();
22375 var target = r.parentElement();
22376 if(!target || target.tagName.toLowerCase() != 'li'){
22378 r.pasteHTML('<br />');
22384 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22385 this.cleanUpPaste.defer(100, this);
22391 }else if(Roo.isOpera){
22392 return function(e){
22393 var k = e.getKey();
22397 this.execCmd('InsertHTML','    ');
22400 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22401 this.cleanUpPaste.defer(100, this);
22406 }else if(Roo.isSafari){
22407 return function(e){
22408 var k = e.getKey();
22412 this.execCmd('InsertText','\t');
22416 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22417 this.cleanUpPaste.defer(100, this);
22425 getAllAncestors: function()
22427 var p = this.getSelectedNode();
22430 a.push(p); // push blank onto stack..
22431 p = this.getParentElement();
22435 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22439 a.push(this.doc.body);
22443 lastSelNode : false,
22446 getSelection : function()
22448 this.assignDocWin();
22449 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22452 getSelectedNode: function()
22454 // this may only work on Gecko!!!
22456 // should we cache this!!!!
22461 var range = this.createRange(this.getSelection()).cloneRange();
22464 var parent = range.parentElement();
22466 var testRange = range.duplicate();
22467 testRange.moveToElementText(parent);
22468 if (testRange.inRange(range)) {
22471 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22474 parent = parent.parentElement;
22479 // is ancestor a text element.
22480 var ac = range.commonAncestorContainer;
22481 if (ac.nodeType == 3) {
22482 ac = ac.parentNode;
22485 var ar = ac.childNodes;
22488 var other_nodes = [];
22489 var has_other_nodes = false;
22490 for (var i=0;i<ar.length;i++) {
22491 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22494 // fullly contained node.
22496 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22501 // probably selected..
22502 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22503 other_nodes.push(ar[i]);
22507 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22512 has_other_nodes = true;
22514 if (!nodes.length && other_nodes.length) {
22515 nodes= other_nodes;
22517 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22523 createRange: function(sel)
22525 // this has strange effects when using with
22526 // top toolbar - not sure if it's a great idea.
22527 //this.editor.contentWindow.focus();
22528 if (typeof sel != "undefined") {
22530 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22532 return this.doc.createRange();
22535 return this.doc.createRange();
22538 getParentElement: function()
22541 this.assignDocWin();
22542 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22544 var range = this.createRange(sel);
22547 var p = range.commonAncestorContainer;
22548 while (p.nodeType == 3) { // text node
22559 * Range intersection.. the hard stuff...
22563 * [ -- selected range --- ]
22567 * if end is before start or hits it. fail.
22568 * if start is after end or hits it fail.
22570 * if either hits (but other is outside. - then it's not
22576 // @see http://www.thismuchiknow.co.uk/?p=64.
22577 rangeIntersectsNode : function(range, node)
22579 var nodeRange = node.ownerDocument.createRange();
22581 nodeRange.selectNode(node);
22583 nodeRange.selectNodeContents(node);
22586 var rangeStartRange = range.cloneRange();
22587 rangeStartRange.collapse(true);
22589 var rangeEndRange = range.cloneRange();
22590 rangeEndRange.collapse(false);
22592 var nodeStartRange = nodeRange.cloneRange();
22593 nodeStartRange.collapse(true);
22595 var nodeEndRange = nodeRange.cloneRange();
22596 nodeEndRange.collapse(false);
22598 return rangeStartRange.compareBoundaryPoints(
22599 Range.START_TO_START, nodeEndRange) == -1 &&
22600 rangeEndRange.compareBoundaryPoints(
22601 Range.START_TO_START, nodeStartRange) == 1;
22605 rangeCompareNode : function(range, node)
22607 var nodeRange = node.ownerDocument.createRange();
22609 nodeRange.selectNode(node);
22611 nodeRange.selectNodeContents(node);
22615 range.collapse(true);
22617 nodeRange.collapse(true);
22619 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22620 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22622 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22624 var nodeIsBefore = ss == 1;
22625 var nodeIsAfter = ee == -1;
22627 if (nodeIsBefore && nodeIsAfter) {
22630 if (!nodeIsBefore && nodeIsAfter) {
22631 return 1; //right trailed.
22634 if (nodeIsBefore && !nodeIsAfter) {
22635 return 2; // left trailed.
22641 // private? - in a new class?
22642 cleanUpPaste : function()
22644 // cleans up the whole document..
22645 Roo.log('cleanuppaste');
22647 this.cleanUpChildren(this.doc.body);
22648 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22649 if (clean != this.doc.body.innerHTML) {
22650 this.doc.body.innerHTML = clean;
22655 cleanWordChars : function(input) {// change the chars to hex code
22656 var he = Roo.HtmlEditorCore;
22658 var output = input;
22659 Roo.each(he.swapCodes, function(sw) {
22660 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22662 output = output.replace(swapper, sw[1]);
22669 cleanUpChildren : function (n)
22671 if (!n.childNodes.length) {
22674 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22675 this.cleanUpChild(n.childNodes[i]);
22682 cleanUpChild : function (node)
22685 //console.log(node);
22686 if (node.nodeName == "#text") {
22687 // clean up silly Windows -- stuff?
22690 if (node.nodeName == "#comment") {
22691 node.parentNode.removeChild(node);
22692 // clean up silly Windows -- stuff?
22695 var lcname = node.tagName.toLowerCase();
22696 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22697 // whitelist of tags..
22699 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22701 node.parentNode.removeChild(node);
22706 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22708 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22709 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22711 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22712 // remove_keep_children = true;
22715 if (remove_keep_children) {
22716 this.cleanUpChildren(node);
22717 // inserts everything just before this node...
22718 while (node.childNodes.length) {
22719 var cn = node.childNodes[0];
22720 node.removeChild(cn);
22721 node.parentNode.insertBefore(cn, node);
22723 node.parentNode.removeChild(node);
22727 if (!node.attributes || !node.attributes.length) {
22728 this.cleanUpChildren(node);
22732 function cleanAttr(n,v)
22735 if (v.match(/^\./) || v.match(/^\//)) {
22738 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22741 if (v.match(/^#/)) {
22744 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22745 node.removeAttribute(n);
22749 var cwhite = this.cwhite;
22750 var cblack = this.cblack;
22752 function cleanStyle(n,v)
22754 if (v.match(/expression/)) { //XSS?? should we even bother..
22755 node.removeAttribute(n);
22759 var parts = v.split(/;/);
22762 Roo.each(parts, function(p) {
22763 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22767 var l = p.split(':').shift().replace(/\s+/g,'');
22768 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22770 if ( cwhite.length && cblack.indexOf(l) > -1) {
22771 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22772 //node.removeAttribute(n);
22776 // only allow 'c whitelisted system attributes'
22777 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22778 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22779 //node.removeAttribute(n);
22789 if (clean.length) {
22790 node.setAttribute(n, clean.join(';'));
22792 node.removeAttribute(n);
22798 for (var i = node.attributes.length-1; i > -1 ; i--) {
22799 var a = node.attributes[i];
22802 if (a.name.toLowerCase().substr(0,2)=='on') {
22803 node.removeAttribute(a.name);
22806 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22807 node.removeAttribute(a.name);
22810 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22811 cleanAttr(a.name,a.value); // fixme..
22814 if (a.name == 'style') {
22815 cleanStyle(a.name,a.value);
22818 /// clean up MS crap..
22819 // tecnically this should be a list of valid class'es..
22822 if (a.name == 'class') {
22823 if (a.value.match(/^Mso/)) {
22824 node.className = '';
22827 if (a.value.match(/^body$/)) {
22828 node.className = '';
22839 this.cleanUpChildren(node);
22845 * Clean up MS wordisms...
22847 cleanWord : function(node)
22852 this.cleanWord(this.doc.body);
22855 if (node.nodeName == "#text") {
22856 // clean up silly Windows -- stuff?
22859 if (node.nodeName == "#comment") {
22860 node.parentNode.removeChild(node);
22861 // clean up silly Windows -- stuff?
22865 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22866 node.parentNode.removeChild(node);
22870 // remove - but keep children..
22871 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22872 while (node.childNodes.length) {
22873 var cn = node.childNodes[0];
22874 node.removeChild(cn);
22875 node.parentNode.insertBefore(cn, node);
22877 node.parentNode.removeChild(node);
22878 this.iterateChildren(node, this.cleanWord);
22882 if (node.className.length) {
22884 var cn = node.className.split(/\W+/);
22886 Roo.each(cn, function(cls) {
22887 if (cls.match(/Mso[a-zA-Z]+/)) {
22892 node.className = cna.length ? cna.join(' ') : '';
22894 node.removeAttribute("class");
22898 if (node.hasAttribute("lang")) {
22899 node.removeAttribute("lang");
22902 if (node.hasAttribute("style")) {
22904 var styles = node.getAttribute("style").split(";");
22906 Roo.each(styles, function(s) {
22907 if (!s.match(/:/)) {
22910 var kv = s.split(":");
22911 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22914 // what ever is left... we allow.
22917 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22918 if (!nstyle.length) {
22919 node.removeAttribute('style');
22922 this.iterateChildren(node, this.cleanWord);
22928 * iterateChildren of a Node, calling fn each time, using this as the scole..
22929 * @param {DomNode} node node to iterate children of.
22930 * @param {Function} fn method of this class to call on each item.
22932 iterateChildren : function(node, fn)
22934 if (!node.childNodes.length) {
22937 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22938 fn.call(this, node.childNodes[i])
22944 * cleanTableWidths.
22946 * Quite often pasting from word etc.. results in tables with column and widths.
22947 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22950 cleanTableWidths : function(node)
22955 this.cleanTableWidths(this.doc.body);
22960 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22963 Roo.log(node.tagName);
22964 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22965 this.iterateChildren(node, this.cleanTableWidths);
22968 if (node.hasAttribute('width')) {
22969 node.removeAttribute('width');
22973 if (node.hasAttribute("style")) {
22976 var styles = node.getAttribute("style").split(";");
22978 Roo.each(styles, function(s) {
22979 if (!s.match(/:/)) {
22982 var kv = s.split(":");
22983 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22986 // what ever is left... we allow.
22989 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22990 if (!nstyle.length) {
22991 node.removeAttribute('style');
22995 this.iterateChildren(node, this.cleanTableWidths);
23003 domToHTML : function(currentElement, depth, nopadtext) {
23005 depth = depth || 0;
23006 nopadtext = nopadtext || false;
23008 if (!currentElement) {
23009 return this.domToHTML(this.doc.body);
23012 //Roo.log(currentElement);
23014 var allText = false;
23015 var nodeName = currentElement.nodeName;
23016 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23018 if (nodeName == '#text') {
23020 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23025 if (nodeName != 'BODY') {
23028 // Prints the node tagName, such as <A>, <IMG>, etc
23031 for(i = 0; i < currentElement.attributes.length;i++) {
23033 var aname = currentElement.attributes.item(i).name;
23034 if (!currentElement.attributes.item(i).value.length) {
23037 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23040 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23049 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23052 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23057 // Traverse the tree
23059 var currentElementChild = currentElement.childNodes.item(i);
23060 var allText = true;
23061 var innerHTML = '';
23063 while (currentElementChild) {
23064 // Formatting code (indent the tree so it looks nice on the screen)
23065 var nopad = nopadtext;
23066 if (lastnode == 'SPAN') {
23070 if (currentElementChild.nodeName == '#text') {
23071 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23072 toadd = nopadtext ? toadd : toadd.trim();
23073 if (!nopad && toadd.length > 80) {
23074 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23076 innerHTML += toadd;
23079 currentElementChild = currentElement.childNodes.item(i);
23085 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23087 // Recursively traverse the tree structure of the child node
23088 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23089 lastnode = currentElementChild.nodeName;
23091 currentElementChild=currentElement.childNodes.item(i);
23097 // The remaining code is mostly for formatting the tree
23098 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23103 ret+= "</"+tagName+">";
23109 applyBlacklists : function()
23111 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23112 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23116 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23117 if (b.indexOf(tag) > -1) {
23120 this.white.push(tag);
23124 Roo.each(w, function(tag) {
23125 if (b.indexOf(tag) > -1) {
23128 if (this.white.indexOf(tag) > -1) {
23131 this.white.push(tag);
23136 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23137 if (w.indexOf(tag) > -1) {
23140 this.black.push(tag);
23144 Roo.each(b, function(tag) {
23145 if (w.indexOf(tag) > -1) {
23148 if (this.black.indexOf(tag) > -1) {
23151 this.black.push(tag);
23156 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23157 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23161 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23162 if (b.indexOf(tag) > -1) {
23165 this.cwhite.push(tag);
23169 Roo.each(w, function(tag) {
23170 if (b.indexOf(tag) > -1) {
23173 if (this.cwhite.indexOf(tag) > -1) {
23176 this.cwhite.push(tag);
23181 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23182 if (w.indexOf(tag) > -1) {
23185 this.cblack.push(tag);
23189 Roo.each(b, function(tag) {
23190 if (w.indexOf(tag) > -1) {
23193 if (this.cblack.indexOf(tag) > -1) {
23196 this.cblack.push(tag);
23201 setStylesheets : function(stylesheets)
23203 if(typeof(stylesheets) == 'string'){
23204 Roo.get(this.iframe.contentDocument.head).createChild({
23206 rel : 'stylesheet',
23215 Roo.each(stylesheets, function(s) {
23220 Roo.get(_this.iframe.contentDocument.head).createChild({
23222 rel : 'stylesheet',
23231 removeStylesheets : function()
23235 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23240 setStyle : function(style)
23242 Roo.get(this.iframe.contentDocument.head).createChild({
23251 // hide stuff that is not compatible
23265 * @event specialkey
23269 * @cfg {String} fieldClass @hide
23272 * @cfg {String} focusClass @hide
23275 * @cfg {String} autoCreate @hide
23278 * @cfg {String} inputType @hide
23281 * @cfg {String} invalidClass @hide
23284 * @cfg {String} invalidText @hide
23287 * @cfg {String} msgFx @hide
23290 * @cfg {String} validateOnBlur @hide
23294 Roo.HtmlEditorCore.white = [
23295 'area', 'br', 'img', 'input', 'hr', 'wbr',
23297 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23298 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23299 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23300 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23301 'table', 'ul', 'xmp',
23303 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23306 'dir', 'menu', 'ol', 'ul', 'dl',
23312 Roo.HtmlEditorCore.black = [
23313 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23315 'base', 'basefont', 'bgsound', 'blink', 'body',
23316 'frame', 'frameset', 'head', 'html', 'ilayer',
23317 'iframe', 'layer', 'link', 'meta', 'object',
23318 'script', 'style' ,'title', 'xml' // clean later..
23320 Roo.HtmlEditorCore.clean = [
23321 'script', 'style', 'title', 'xml'
23323 Roo.HtmlEditorCore.remove = [
23328 Roo.HtmlEditorCore.ablack = [
23332 Roo.HtmlEditorCore.aclean = [
23333 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23337 Roo.HtmlEditorCore.pwhite= [
23338 'http', 'https', 'mailto'
23341 // white listed style attributes.
23342 Roo.HtmlEditorCore.cwhite= [
23343 // 'text-align', /// default is to allow most things..
23349 // black listed style attributes.
23350 Roo.HtmlEditorCore.cblack= [
23351 // 'font-size' -- this can be set by the project
23355 Roo.HtmlEditorCore.swapCodes =[
23374 * @class Roo.bootstrap.HtmlEditor
23375 * @extends Roo.bootstrap.TextArea
23376 * Bootstrap HtmlEditor class
23379 * Create a new HtmlEditor
23380 * @param {Object} config The config object
23383 Roo.bootstrap.HtmlEditor = function(config){
23384 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23385 if (!this.toolbars) {
23386 this.toolbars = [];
23389 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23392 * @event initialize
23393 * Fires when the editor is fully initialized (including the iframe)
23394 * @param {HtmlEditor} this
23399 * Fires when the editor is first receives the focus. Any insertion must wait
23400 * until after this event.
23401 * @param {HtmlEditor} this
23405 * @event beforesync
23406 * Fires before the textarea is updated with content from the editor iframe. Return false
23407 * to cancel the sync.
23408 * @param {HtmlEditor} this
23409 * @param {String} html
23413 * @event beforepush
23414 * Fires before the iframe editor is updated with content from the textarea. Return false
23415 * to cancel the push.
23416 * @param {HtmlEditor} this
23417 * @param {String} html
23422 * Fires when the textarea is updated with content from the editor iframe.
23423 * @param {HtmlEditor} this
23424 * @param {String} html
23429 * Fires when the iframe editor is updated with content from the textarea.
23430 * @param {HtmlEditor} this
23431 * @param {String} html
23435 * @event editmodechange
23436 * Fires when the editor switches edit modes
23437 * @param {HtmlEditor} this
23438 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23440 editmodechange: true,
23442 * @event editorevent
23443 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23444 * @param {HtmlEditor} this
23448 * @event firstfocus
23449 * Fires when on first focus - needed by toolbars..
23450 * @param {HtmlEditor} this
23455 * Auto save the htmlEditor value as a file into Events
23456 * @param {HtmlEditor} this
23460 * @event savedpreview
23461 * preview the saved version of htmlEditor
23462 * @param {HtmlEditor} this
23469 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23473 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23478 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23483 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23488 * @cfg {Number} height (in pixels)
23492 * @cfg {Number} width (in pixels)
23497 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23500 stylesheets: false,
23505 // private properties
23506 validationEvent : false,
23508 initialized : false,
23511 onFocus : Roo.emptyFn,
23513 hideMode:'offsets',
23515 tbContainer : false,
23519 toolbarContainer :function() {
23520 return this.wrap.select('.x-html-editor-tb',true).first();
23524 * Protected method that will not generally be called directly. It
23525 * is called when the editor creates its toolbar. Override this method if you need to
23526 * add custom toolbar buttons.
23527 * @param {HtmlEditor} editor
23529 createToolbar : function(){
23530 Roo.log('renewing');
23531 Roo.log("create toolbars");
23533 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23534 this.toolbars[0].render(this.toolbarContainer());
23538 // if (!editor.toolbars || !editor.toolbars.length) {
23539 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23542 // for (var i =0 ; i < editor.toolbars.length;i++) {
23543 // editor.toolbars[i] = Roo.factory(
23544 // typeof(editor.toolbars[i]) == 'string' ?
23545 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23546 // Roo.bootstrap.HtmlEditor);
23547 // editor.toolbars[i].init(editor);
23553 onRender : function(ct, position)
23555 // Roo.log("Call onRender: " + this.xtype);
23557 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23559 this.wrap = this.inputEl().wrap({
23560 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23563 this.editorcore.onRender(ct, position);
23565 if (this.resizable) {
23566 this.resizeEl = new Roo.Resizable(this.wrap, {
23570 minHeight : this.height,
23571 height: this.height,
23572 handles : this.resizable,
23575 resize : function(r, w, h) {
23576 _t.onResize(w,h); // -something
23582 this.createToolbar(this);
23585 if(!this.width && this.resizable){
23586 this.setSize(this.wrap.getSize());
23588 if (this.resizeEl) {
23589 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23590 // should trigger onReize..
23596 onResize : function(w, h)
23598 Roo.log('resize: ' +w + ',' + h );
23599 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23603 if(this.inputEl() ){
23604 if(typeof w == 'number'){
23605 var aw = w - this.wrap.getFrameWidth('lr');
23606 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23609 if(typeof h == 'number'){
23610 var tbh = -11; // fixme it needs to tool bar size!
23611 for (var i =0; i < this.toolbars.length;i++) {
23612 // fixme - ask toolbars for heights?
23613 tbh += this.toolbars[i].el.getHeight();
23614 //if (this.toolbars[i].footer) {
23615 // tbh += this.toolbars[i].footer.el.getHeight();
23623 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23624 ah -= 5; // knock a few pixes off for look..
23625 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23629 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23630 this.editorcore.onResize(ew,eh);
23635 * Toggles the editor between standard and source edit mode.
23636 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23638 toggleSourceEdit : function(sourceEditMode)
23640 this.editorcore.toggleSourceEdit(sourceEditMode);
23642 if(this.editorcore.sourceEditMode){
23643 Roo.log('editor - showing textarea');
23646 // Roo.log(this.syncValue());
23648 this.inputEl().removeClass(['hide', 'x-hidden']);
23649 this.inputEl().dom.removeAttribute('tabIndex');
23650 this.inputEl().focus();
23652 Roo.log('editor - hiding textarea');
23654 // Roo.log(this.pushValue());
23657 this.inputEl().addClass(['hide', 'x-hidden']);
23658 this.inputEl().dom.setAttribute('tabIndex', -1);
23659 //this.deferFocus();
23662 if(this.resizable){
23663 this.setSize(this.wrap.getSize());
23666 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23669 // private (for BoxComponent)
23670 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23672 // private (for BoxComponent)
23673 getResizeEl : function(){
23677 // private (for BoxComponent)
23678 getPositionEl : function(){
23683 initEvents : function(){
23684 this.originalValue = this.getValue();
23688 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23691 // markInvalid : Roo.emptyFn,
23693 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23696 // clearInvalid : Roo.emptyFn,
23698 setValue : function(v){
23699 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23700 this.editorcore.pushValue();
23705 deferFocus : function(){
23706 this.focus.defer(10, this);
23710 focus : function(){
23711 this.editorcore.focus();
23717 onDestroy : function(){
23723 for (var i =0; i < this.toolbars.length;i++) {
23724 // fixme - ask toolbars for heights?
23725 this.toolbars[i].onDestroy();
23728 this.wrap.dom.innerHTML = '';
23729 this.wrap.remove();
23734 onFirstFocus : function(){
23735 //Roo.log("onFirstFocus");
23736 this.editorcore.onFirstFocus();
23737 for (var i =0; i < this.toolbars.length;i++) {
23738 this.toolbars[i].onFirstFocus();
23744 syncValue : function()
23746 this.editorcore.syncValue();
23749 pushValue : function()
23751 this.editorcore.pushValue();
23755 // hide stuff that is not compatible
23769 * @event specialkey
23773 * @cfg {String} fieldClass @hide
23776 * @cfg {String} focusClass @hide
23779 * @cfg {String} autoCreate @hide
23782 * @cfg {String} inputType @hide
23785 * @cfg {String} invalidClass @hide
23788 * @cfg {String} invalidText @hide
23791 * @cfg {String} msgFx @hide
23794 * @cfg {String} validateOnBlur @hide
23803 Roo.namespace('Roo.bootstrap.htmleditor');
23805 * @class Roo.bootstrap.HtmlEditorToolbar1
23810 new Roo.bootstrap.HtmlEditor({
23813 new Roo.bootstrap.HtmlEditorToolbar1({
23814 disable : { fonts: 1 , format: 1, ..., ... , ...],
23820 * @cfg {Object} disable List of elements to disable..
23821 * @cfg {Array} btns List of additional buttons.
23825 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23828 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23831 Roo.apply(this, config);
23833 // default disabled, based on 'good practice'..
23834 this.disable = this.disable || {};
23835 Roo.applyIf(this.disable, {
23838 specialElements : true
23840 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23842 this.editor = config.editor;
23843 this.editorcore = config.editor.editorcore;
23845 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23847 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23848 // dont call parent... till later.
23850 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23855 editorcore : false,
23860 "h1","h2","h3","h4","h5","h6",
23862 "abbr", "acronym", "address", "cite", "samp", "var",
23866 onRender : function(ct, position)
23868 // Roo.log("Call onRender: " + this.xtype);
23870 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23872 this.el.dom.style.marginBottom = '0';
23874 var editorcore = this.editorcore;
23875 var editor= this.editor;
23878 var btn = function(id,cmd , toggle, handler, html){
23880 var event = toggle ? 'toggle' : 'click';
23885 xns: Roo.bootstrap,
23888 enableToggle:toggle !== false,
23890 pressed : toggle ? false : null,
23893 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23894 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23900 // var cb_box = function...
23905 xns: Roo.bootstrap,
23906 glyphicon : 'font',
23910 xns: Roo.bootstrap,
23914 Roo.each(this.formats, function(f) {
23915 style.menu.items.push({
23917 xns: Roo.bootstrap,
23918 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23923 editorcore.insertTag(this.tagname);
23930 children.push(style);
23932 btn('bold',false,true);
23933 btn('italic',false,true);
23934 btn('align-left', 'justifyleft',true);
23935 btn('align-center', 'justifycenter',true);
23936 btn('align-right' , 'justifyright',true);
23937 btn('link', false, false, function(btn) {
23938 //Roo.log("create link?");
23939 var url = prompt(this.createLinkText, this.defaultLinkValue);
23940 if(url && url != 'http:/'+'/'){
23941 this.editorcore.relayCmd('createlink', url);
23944 btn('list','insertunorderedlist',true);
23945 btn('pencil', false,true, function(btn){
23947 this.toggleSourceEdit(btn.pressed);
23950 if (this.editor.btns.length > 0) {
23951 for (var i = 0; i<this.editor.btns.length; i++) {
23952 children.push(this.editor.btns[i]);
23960 xns: Roo.bootstrap,
23965 xns: Roo.bootstrap,
23970 cog.menu.items.push({
23972 xns: Roo.bootstrap,
23973 html : Clean styles,
23978 editorcore.insertTag(this.tagname);
23987 this.xtype = 'NavSimplebar';
23989 for(var i=0;i< children.length;i++) {
23991 this.buttons.add(this.addxtypeChild(children[i]));
23995 editor.on('editorevent', this.updateToolbar, this);
23997 onBtnClick : function(id)
23999 this.editorcore.relayCmd(id);
24000 this.editorcore.focus();
24004 * Protected method that will not generally be called directly. It triggers
24005 * a toolbar update by reading the markup state of the current selection in the editor.
24007 updateToolbar: function(){
24009 if(!this.editorcore.activated){
24010 this.editor.onFirstFocus(); // is this neeed?
24014 var btns = this.buttons;
24015 var doc = this.editorcore.doc;
24016 btns.get('bold').setActive(doc.queryCommandState('bold'));
24017 btns.get('italic').setActive(doc.queryCommandState('italic'));
24018 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24020 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24021 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24022 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24024 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24025 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24028 var ans = this.editorcore.getAllAncestors();
24029 if (this.formatCombo) {
24032 var store = this.formatCombo.store;
24033 this.formatCombo.setValue("");
24034 for (var i =0; i < ans.length;i++) {
24035 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24037 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24045 // hides menus... - so this cant be on a menu...
24046 Roo.bootstrap.MenuMgr.hideAll();
24048 Roo.bootstrap.MenuMgr.hideAll();
24049 //this.editorsyncValue();
24051 onFirstFocus: function() {
24052 this.buttons.each(function(item){
24056 toggleSourceEdit : function(sourceEditMode){
24059 if(sourceEditMode){
24060 Roo.log("disabling buttons");
24061 this.buttons.each( function(item){
24062 if(item.cmd != 'pencil'){
24068 Roo.log("enabling buttons");
24069 if(this.editorcore.initialized){
24070 this.buttons.each( function(item){
24076 Roo.log("calling toggole on editor");
24077 // tell the editor that it's been pressed..
24078 this.editor.toggleSourceEdit(sourceEditMode);
24088 * @class Roo.bootstrap.Table.AbstractSelectionModel
24089 * @extends Roo.util.Observable
24090 * Abstract base class for grid SelectionModels. It provides the interface that should be
24091 * implemented by descendant classes. This class should not be directly instantiated.
24094 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24095 this.locked = false;
24096 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24100 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24101 /** @ignore Called by the grid automatically. Do not call directly. */
24102 init : function(grid){
24108 * Locks the selections.
24111 this.locked = true;
24115 * Unlocks the selections.
24117 unlock : function(){
24118 this.locked = false;
24122 * Returns true if the selections are locked.
24123 * @return {Boolean}
24125 isLocked : function(){
24126 return this.locked;
24130 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24131 * @class Roo.bootstrap.Table.RowSelectionModel
24132 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24133 * It supports multiple selections and keyboard selection/navigation.
24135 * @param {Object} config
24138 Roo.bootstrap.Table.RowSelectionModel = function(config){
24139 Roo.apply(this, config);
24140 this.selections = new Roo.util.MixedCollection(false, function(o){
24145 this.lastActive = false;
24149 * @event selectionchange
24150 * Fires when the selection changes
24151 * @param {SelectionModel} this
24153 "selectionchange" : true,
24155 * @event afterselectionchange
24156 * Fires after the selection changes (eg. by key press or clicking)
24157 * @param {SelectionModel} this
24159 "afterselectionchange" : true,
24161 * @event beforerowselect
24162 * Fires when a row is selected being selected, return false to cancel.
24163 * @param {SelectionModel} this
24164 * @param {Number} rowIndex The selected index
24165 * @param {Boolean} keepExisting False if other selections will be cleared
24167 "beforerowselect" : true,
24170 * Fires when a row is selected.
24171 * @param {SelectionModel} this
24172 * @param {Number} rowIndex The selected index
24173 * @param {Roo.data.Record} r The record
24175 "rowselect" : true,
24177 * @event rowdeselect
24178 * Fires when a row is deselected.
24179 * @param {SelectionModel} this
24180 * @param {Number} rowIndex The selected index
24182 "rowdeselect" : true
24184 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24185 this.locked = false;
24188 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24190 * @cfg {Boolean} singleSelect
24191 * True to allow selection of only one row at a time (defaults to false)
24193 singleSelect : false,
24196 initEvents : function()
24199 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24200 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24201 //}else{ // allow click to work like normal
24202 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24204 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24205 this.grid.on("rowclick", this.handleMouseDown, this);
24207 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24208 "up" : function(e){
24210 this.selectPrevious(e.shiftKey);
24211 }else if(this.last !== false && this.lastActive !== false){
24212 var last = this.last;
24213 this.selectRange(this.last, this.lastActive-1);
24214 this.grid.getView().focusRow(this.lastActive);
24215 if(last !== false){
24219 this.selectFirstRow();
24221 this.fireEvent("afterselectionchange", this);
24223 "down" : function(e){
24225 this.selectNext(e.shiftKey);
24226 }else if(this.last !== false && this.lastActive !== false){
24227 var last = this.last;
24228 this.selectRange(this.last, this.lastActive+1);
24229 this.grid.getView().focusRow(this.lastActive);
24230 if(last !== false){
24234 this.selectFirstRow();
24236 this.fireEvent("afterselectionchange", this);
24240 this.grid.store.on('load', function(){
24241 this.selections.clear();
24244 var view = this.grid.view;
24245 view.on("refresh", this.onRefresh, this);
24246 view.on("rowupdated", this.onRowUpdated, this);
24247 view.on("rowremoved", this.onRemove, this);
24252 onRefresh : function()
24254 var ds = this.grid.store, i, v = this.grid.view;
24255 var s = this.selections;
24256 s.each(function(r){
24257 if((i = ds.indexOfId(r.id)) != -1){
24266 onRemove : function(v, index, r){
24267 this.selections.remove(r);
24271 onRowUpdated : function(v, index, r){
24272 if(this.isSelected(r)){
24273 v.onRowSelect(index);
24279 * @param {Array} records The records to select
24280 * @param {Boolean} keepExisting (optional) True to keep existing selections
24282 selectRecords : function(records, keepExisting)
24285 this.clearSelections();
24287 var ds = this.grid.store;
24288 for(var i = 0, len = records.length; i < len; i++){
24289 this.selectRow(ds.indexOf(records[i]), true);
24294 * Gets the number of selected rows.
24297 getCount : function(){
24298 return this.selections.length;
24302 * Selects the first row in the grid.
24304 selectFirstRow : function(){
24309 * Select the last row.
24310 * @param {Boolean} keepExisting (optional) True to keep existing selections
24312 selectLastRow : function(keepExisting){
24313 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24314 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24318 * Selects the row immediately following the last selected row.
24319 * @param {Boolean} keepExisting (optional) True to keep existing selections
24321 selectNext : function(keepExisting)
24323 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24324 this.selectRow(this.last+1, keepExisting);
24325 this.grid.getView().focusRow(this.last);
24330 * Selects the row that precedes the last selected row.
24331 * @param {Boolean} keepExisting (optional) True to keep existing selections
24333 selectPrevious : function(keepExisting){
24335 this.selectRow(this.last-1, keepExisting);
24336 this.grid.getView().focusRow(this.last);
24341 * Returns the selected records
24342 * @return {Array} Array of selected records
24344 getSelections : function(){
24345 return [].concat(this.selections.items);
24349 * Returns the first selected record.
24352 getSelected : function(){
24353 return this.selections.itemAt(0);
24358 * Clears all selections.
24360 clearSelections : function(fast)
24366 var ds = this.grid.store;
24367 var s = this.selections;
24368 s.each(function(r){
24369 this.deselectRow(ds.indexOfId(r.id));
24373 this.selections.clear();
24380 * Selects all rows.
24382 selectAll : function(){
24386 this.selections.clear();
24387 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24388 this.selectRow(i, true);
24393 * Returns True if there is a selection.
24394 * @return {Boolean}
24396 hasSelection : function(){
24397 return this.selections.length > 0;
24401 * Returns True if the specified row is selected.
24402 * @param {Number/Record} record The record or index of the record to check
24403 * @return {Boolean}
24405 isSelected : function(index){
24406 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24407 return (r && this.selections.key(r.id) ? true : false);
24411 * Returns True if the specified record id is selected.
24412 * @param {String} id The id of record to check
24413 * @return {Boolean}
24415 isIdSelected : function(id){
24416 return (this.selections.key(id) ? true : false);
24421 handleMouseDBClick : function(e, t){
24425 handleMouseDown : function(e, t)
24427 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24428 if(this.isLocked() || rowIndex < 0 ){
24431 if(e.shiftKey && this.last !== false){
24432 var last = this.last;
24433 this.selectRange(last, rowIndex, e.ctrlKey);
24434 this.last = last; // reset the last
24438 var isSelected = this.isSelected(rowIndex);
24439 //Roo.log("select row:" + rowIndex);
24441 this.deselectRow(rowIndex);
24443 this.selectRow(rowIndex, true);
24447 if(e.button !== 0 && isSelected){
24448 alert('rowIndex 2: ' + rowIndex);
24449 view.focusRow(rowIndex);
24450 }else if(e.ctrlKey && isSelected){
24451 this.deselectRow(rowIndex);
24452 }else if(!isSelected){
24453 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24454 view.focusRow(rowIndex);
24458 this.fireEvent("afterselectionchange", this);
24461 handleDragableRowClick : function(grid, rowIndex, e)
24463 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24464 this.selectRow(rowIndex, false);
24465 grid.view.focusRow(rowIndex);
24466 this.fireEvent("afterselectionchange", this);
24471 * Selects multiple rows.
24472 * @param {Array} rows Array of the indexes of the row to select
24473 * @param {Boolean} keepExisting (optional) True to keep existing selections
24475 selectRows : function(rows, keepExisting){
24477 this.clearSelections();
24479 for(var i = 0, len = rows.length; i < len; i++){
24480 this.selectRow(rows[i], true);
24485 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24486 * @param {Number} startRow The index of the first row in the range
24487 * @param {Number} endRow The index of the last row in the range
24488 * @param {Boolean} keepExisting (optional) True to retain existing selections
24490 selectRange : function(startRow, endRow, keepExisting){
24495 this.clearSelections();
24497 if(startRow <= endRow){
24498 for(var i = startRow; i <= endRow; i++){
24499 this.selectRow(i, true);
24502 for(var i = startRow; i >= endRow; i--){
24503 this.selectRow(i, true);
24509 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24510 * @param {Number} startRow The index of the first row in the range
24511 * @param {Number} endRow The index of the last row in the range
24513 deselectRange : function(startRow, endRow, preventViewNotify){
24517 for(var i = startRow; i <= endRow; i++){
24518 this.deselectRow(i, preventViewNotify);
24524 * @param {Number} row The index of the row to select
24525 * @param {Boolean} keepExisting (optional) True to keep existing selections
24527 selectRow : function(index, keepExisting, preventViewNotify)
24529 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24532 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24533 if(!keepExisting || this.singleSelect){
24534 this.clearSelections();
24537 var r = this.grid.store.getAt(index);
24538 //console.log('selectRow - record id :' + r.id);
24540 this.selections.add(r);
24541 this.last = this.lastActive = index;
24542 if(!preventViewNotify){
24543 var proxy = new Roo.Element(
24544 this.grid.getRowDom(index)
24546 proxy.addClass('bg-info info');
24548 this.fireEvent("rowselect", this, index, r);
24549 this.fireEvent("selectionchange", this);
24555 * @param {Number} row The index of the row to deselect
24557 deselectRow : function(index, preventViewNotify)
24562 if(this.last == index){
24565 if(this.lastActive == index){
24566 this.lastActive = false;
24569 var r = this.grid.store.getAt(index);
24574 this.selections.remove(r);
24575 //.console.log('deselectRow - record id :' + r.id);
24576 if(!preventViewNotify){
24578 var proxy = new Roo.Element(
24579 this.grid.getRowDom(index)
24581 proxy.removeClass('bg-info info');
24583 this.fireEvent("rowdeselect", this, index);
24584 this.fireEvent("selectionchange", this);
24588 restoreLast : function(){
24590 this.last = this._last;
24595 acceptsNav : function(row, col, cm){
24596 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24600 onEditorKey : function(field, e){
24601 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24606 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24608 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24610 }else if(k == e.ENTER && !e.ctrlKey){
24614 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24616 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24618 }else if(k == e.ESC){
24622 g.startEditing(newCell[0], newCell[1]);
24628 * Ext JS Library 1.1.1
24629 * Copyright(c) 2006-2007, Ext JS, LLC.
24631 * Originally Released Under LGPL - original licence link has changed is not relivant.
24634 * <script type="text/javascript">
24638 * @class Roo.bootstrap.PagingToolbar
24639 * @extends Roo.bootstrap.NavSimplebar
24640 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24642 * Create a new PagingToolbar
24643 * @param {Object} config The config object
24644 * @param {Roo.data.Store} store
24646 Roo.bootstrap.PagingToolbar = function(config)
24648 // old args format still supported... - xtype is prefered..
24649 // created from xtype...
24651 this.ds = config.dataSource;
24653 if (config.store && !this.ds) {
24654 this.store= Roo.factory(config.store, Roo.data);
24655 this.ds = this.store;
24656 this.ds.xmodule = this.xmodule || false;
24659 this.toolbarItems = [];
24660 if (config.items) {
24661 this.toolbarItems = config.items;
24664 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24669 this.bind(this.ds);
24672 if (Roo.bootstrap.version == 4) {
24673 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24675 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24680 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24682 * @cfg {Roo.data.Store} dataSource
24683 * The underlying data store providing the paged data
24686 * @cfg {String/HTMLElement/Element} container
24687 * container The id or element that will contain the toolbar
24690 * @cfg {Boolean} displayInfo
24691 * True to display the displayMsg (defaults to false)
24694 * @cfg {Number} pageSize
24695 * The number of records to display per page (defaults to 20)
24699 * @cfg {String} displayMsg
24700 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24702 displayMsg : 'Displaying {0} - {1} of {2}',
24704 * @cfg {String} emptyMsg
24705 * The message to display when no records are found (defaults to "No data to display")
24707 emptyMsg : 'No data to display',
24709 * Customizable piece of the default paging text (defaults to "Page")
24712 beforePageText : "Page",
24714 * Customizable piece of the default paging text (defaults to "of %0")
24717 afterPageText : "of {0}",
24719 * Customizable piece of the default paging text (defaults to "First Page")
24722 firstText : "First Page",
24724 * Customizable piece of the default paging text (defaults to "Previous Page")
24727 prevText : "Previous Page",
24729 * Customizable piece of the default paging text (defaults to "Next Page")
24732 nextText : "Next Page",
24734 * Customizable piece of the default paging text (defaults to "Last Page")
24737 lastText : "Last Page",
24739 * Customizable piece of the default paging text (defaults to "Refresh")
24742 refreshText : "Refresh",
24746 onRender : function(ct, position)
24748 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24749 this.navgroup.parentId = this.id;
24750 this.navgroup.onRender(this.el, null);
24751 // add the buttons to the navgroup
24753 if(this.displayInfo){
24754 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24755 this.displayEl = this.el.select('.x-paging-info', true).first();
24756 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24757 // this.displayEl = navel.el.select('span',true).first();
24763 Roo.each(_this.buttons, function(e){ // this might need to use render????
24764 Roo.factory(e).render(_this.el);
24768 Roo.each(_this.toolbarItems, function(e) {
24769 _this.navgroup.addItem(e);
24773 this.first = this.navgroup.addItem({
24774 tooltip: this.firstText,
24775 cls: "prev btn-outline-secondary",
24776 html : ' <i class="fa fa-step-backward"></i>',
24778 preventDefault: true,
24779 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24782 this.prev = this.navgroup.addItem({
24783 tooltip: this.prevText,
24784 cls: "prev btn-outline-secondary",
24785 html : ' <i class="fa fa-backward"></i>',
24787 preventDefault: true,
24788 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24790 //this.addSeparator();
24793 var field = this.navgroup.addItem( {
24795 cls : 'x-paging-position btn-outline-secondary',
24797 html : this.beforePageText +
24798 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24799 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24802 this.field = field.el.select('input', true).first();
24803 this.field.on("keydown", this.onPagingKeydown, this);
24804 this.field.on("focus", function(){this.dom.select();});
24807 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24808 //this.field.setHeight(18);
24809 //this.addSeparator();
24810 this.next = this.navgroup.addItem({
24811 tooltip: this.nextText,
24812 cls: "next btn-outline-secondary",
24813 html : ' <i class="fa fa-forward"></i>',
24815 preventDefault: true,
24816 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24818 this.last = this.navgroup.addItem({
24819 tooltip: this.lastText,
24820 html : ' <i class="fa fa-step-forward"></i>',
24821 cls: "next btn-outline-secondary",
24823 preventDefault: true,
24824 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24826 //this.addSeparator();
24827 this.loading = this.navgroup.addItem({
24828 tooltip: this.refreshText,
24829 icon: 'fa fa-refresh',
24830 preventDefault: true,
24831 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24837 updateInfo : function(){
24838 if(this.displayEl){
24839 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24840 var msg = count == 0 ?
24844 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24846 this.displayEl.update(msg);
24851 onLoad : function(ds, r, o)
24853 this.cursor = o.params.start ? o.params.start : 0;
24855 var d = this.getPageData(),
24860 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24861 this.field.dom.value = ap;
24862 this.first.setDisabled(ap == 1);
24863 this.prev.setDisabled(ap == 1);
24864 this.next.setDisabled(ap == ps);
24865 this.last.setDisabled(ap == ps);
24866 this.loading.enable();
24871 getPageData : function(){
24872 var total = this.ds.getTotalCount();
24875 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24876 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24881 onLoadError : function(){
24882 this.loading.enable();
24886 onPagingKeydown : function(e){
24887 var k = e.getKey();
24888 var d = this.getPageData();
24890 var v = this.field.dom.value, pageNum;
24891 if(!v || isNaN(pageNum = parseInt(v, 10))){
24892 this.field.dom.value = d.activePage;
24895 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24896 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24899 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))
24901 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24902 this.field.dom.value = pageNum;
24903 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24906 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24908 var v = this.field.dom.value, pageNum;
24909 var increment = (e.shiftKey) ? 10 : 1;
24910 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24913 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24914 this.field.dom.value = d.activePage;
24917 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24919 this.field.dom.value = parseInt(v, 10) + increment;
24920 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24921 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24928 beforeLoad : function(){
24930 this.loading.disable();
24935 onClick : function(which){
24944 ds.load({params:{start: 0, limit: this.pageSize}});
24947 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24950 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24953 var total = ds.getTotalCount();
24954 var extra = total % this.pageSize;
24955 var lastStart = extra ? (total - extra) : total-this.pageSize;
24956 ds.load({params:{start: lastStart, limit: this.pageSize}});
24959 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24965 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24966 * @param {Roo.data.Store} store The data store to unbind
24968 unbind : function(ds){
24969 ds.un("beforeload", this.beforeLoad, this);
24970 ds.un("load", this.onLoad, this);
24971 ds.un("loadexception", this.onLoadError, this);
24972 ds.un("remove", this.updateInfo, this);
24973 ds.un("add", this.updateInfo, this);
24974 this.ds = undefined;
24978 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24979 * @param {Roo.data.Store} store The data store to bind
24981 bind : function(ds){
24982 ds.on("beforeload", this.beforeLoad, this);
24983 ds.on("load", this.onLoad, this);
24984 ds.on("loadexception", this.onLoadError, this);
24985 ds.on("remove", this.updateInfo, this);
24986 ds.on("add", this.updateInfo, this);
24997 * @class Roo.bootstrap.MessageBar
24998 * @extends Roo.bootstrap.Component
24999 * Bootstrap MessageBar class
25000 * @cfg {String} html contents of the MessageBar
25001 * @cfg {String} weight (info | success | warning | danger) default info
25002 * @cfg {String} beforeClass insert the bar before the given class
25003 * @cfg {Boolean} closable (true | false) default false
25004 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25007 * Create a new Element
25008 * @param {Object} config The config object
25011 Roo.bootstrap.MessageBar = function(config){
25012 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25015 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25021 beforeClass: 'bootstrap-sticky-wrap',
25023 getAutoCreate : function(){
25027 cls: 'alert alert-dismissable alert-' + this.weight,
25032 html: this.html || ''
25038 cfg.cls += ' alert-messages-fixed';
25052 onRender : function(ct, position)
25054 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25057 var cfg = Roo.apply({}, this.getAutoCreate());
25061 cfg.cls += ' ' + this.cls;
25064 cfg.style = this.style;
25066 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25068 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25071 this.el.select('>button.close').on('click', this.hide, this);
25077 if (!this.rendered) {
25083 this.fireEvent('show', this);
25089 if (!this.rendered) {
25095 this.fireEvent('hide', this);
25098 update : function()
25100 // var e = this.el.dom.firstChild;
25102 // if(this.closable){
25103 // e = e.nextSibling;
25106 // e.data = this.html || '';
25108 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25124 * @class Roo.bootstrap.Graph
25125 * @extends Roo.bootstrap.Component
25126 * Bootstrap Graph class
25130 @cfg {String} graphtype bar | vbar | pie
25131 @cfg {number} g_x coodinator | centre x (pie)
25132 @cfg {number} g_y coodinator | centre y (pie)
25133 @cfg {number} g_r radius (pie)
25134 @cfg {number} g_height height of the chart (respected by all elements in the set)
25135 @cfg {number} g_width width of the chart (respected by all elements in the set)
25136 @cfg {Object} title The title of the chart
25139 -opts (object) options for the chart
25141 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25142 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25144 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.
25145 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25147 o stretch (boolean)
25149 -opts (object) options for the pie
25152 o startAngle (number)
25153 o endAngle (number)
25157 * Create a new Input
25158 * @param {Object} config The config object
25161 Roo.bootstrap.Graph = function(config){
25162 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25168 * The img click event for the img.
25169 * @param {Roo.EventObject} e
25175 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25186 //g_colors: this.colors,
25193 getAutoCreate : function(){
25204 onRender : function(ct,position){
25207 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25209 if (typeof(Raphael) == 'undefined') {
25210 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25214 this.raphael = Raphael(this.el.dom);
25216 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25217 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25218 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25219 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25221 r.text(160, 10, "Single Series Chart").attr(txtattr);
25222 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25223 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25224 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25226 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25227 r.barchart(330, 10, 300, 220, data1);
25228 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25229 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25232 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25233 // r.barchart(30, 30, 560, 250, xdata, {
25234 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25235 // axis : "0 0 1 1",
25236 // axisxlabels : xdata
25237 // //yvalues : cols,
25240 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25242 // this.load(null,xdata,{
25243 // axis : "0 0 1 1",
25244 // axisxlabels : xdata
25249 load : function(graphtype,xdata,opts)
25251 this.raphael.clear();
25253 graphtype = this.graphtype;
25258 var r = this.raphael,
25259 fin = function () {
25260 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25262 fout = function () {
25263 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25265 pfin = function() {
25266 this.sector.stop();
25267 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25270 this.label[0].stop();
25271 this.label[0].attr({ r: 7.5 });
25272 this.label[1].attr({ "font-weight": 800 });
25275 pfout = function() {
25276 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25279 this.label[0].animate({ r: 5 }, 500, "bounce");
25280 this.label[1].attr({ "font-weight": 400 });
25286 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25289 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25292 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25293 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25295 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25302 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25307 setTitle: function(o)
25312 initEvents: function() {
25315 this.el.on('click', this.onClick, this);
25319 onClick : function(e)
25321 Roo.log('img onclick');
25322 this.fireEvent('click', this, e);
25334 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25337 * @class Roo.bootstrap.dash.NumberBox
25338 * @extends Roo.bootstrap.Component
25339 * Bootstrap NumberBox class
25340 * @cfg {String} headline Box headline
25341 * @cfg {String} content Box content
25342 * @cfg {String} icon Box icon
25343 * @cfg {String} footer Footer text
25344 * @cfg {String} fhref Footer href
25347 * Create a new NumberBox
25348 * @param {Object} config The config object
25352 Roo.bootstrap.dash.NumberBox = function(config){
25353 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25357 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25366 getAutoCreate : function(){
25370 cls : 'small-box ',
25378 cls : 'roo-headline',
25379 html : this.headline
25383 cls : 'roo-content',
25384 html : this.content
25398 cls : 'ion ' + this.icon
25407 cls : 'small-box-footer',
25408 href : this.fhref || '#',
25412 cfg.cn.push(footer);
25419 onRender : function(ct,position){
25420 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25427 setHeadline: function (value)
25429 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25432 setFooter: function (value, href)
25434 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25437 this.el.select('a.small-box-footer',true).first().attr('href', href);
25442 setContent: function (value)
25444 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25447 initEvents: function()
25461 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25464 * @class Roo.bootstrap.dash.TabBox
25465 * @extends Roo.bootstrap.Component
25466 * Bootstrap TabBox class
25467 * @cfg {String} title Title of the TabBox
25468 * @cfg {String} icon Icon of the TabBox
25469 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25470 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25473 * Create a new TabBox
25474 * @param {Object} config The config object
25478 Roo.bootstrap.dash.TabBox = function(config){
25479 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25484 * When a pane is added
25485 * @param {Roo.bootstrap.dash.TabPane} pane
25489 * @event activatepane
25490 * When a pane is activated
25491 * @param {Roo.bootstrap.dash.TabPane} pane
25493 "activatepane" : true
25501 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25506 tabScrollable : false,
25508 getChildContainer : function()
25510 return this.el.select('.tab-content', true).first();
25513 getAutoCreate : function(){
25517 cls: 'pull-left header',
25525 cls: 'fa ' + this.icon
25531 cls: 'nav nav-tabs pull-right',
25537 if(this.tabScrollable){
25544 cls: 'nav nav-tabs pull-right',
25555 cls: 'nav-tabs-custom',
25560 cls: 'tab-content no-padding',
25568 initEvents : function()
25570 //Roo.log('add add pane handler');
25571 this.on('addpane', this.onAddPane, this);
25574 * Updates the box title
25575 * @param {String} html to set the title to.
25577 setTitle : function(value)
25579 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25581 onAddPane : function(pane)
25583 this.panes.push(pane);
25584 //Roo.log('addpane');
25586 // tabs are rendere left to right..
25587 if(!this.showtabs){
25591 var ctr = this.el.select('.nav-tabs', true).first();
25594 var existing = ctr.select('.nav-tab',true);
25595 var qty = existing.getCount();;
25598 var tab = ctr.createChild({
25600 cls : 'nav-tab' + (qty ? '' : ' active'),
25608 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25611 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25613 pane.el.addClass('active');
25618 onTabClick : function(ev,un,ob,pane)
25620 //Roo.log('tab - prev default');
25621 ev.preventDefault();
25624 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25625 pane.tab.addClass('active');
25626 //Roo.log(pane.title);
25627 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25628 // technically we should have a deactivate event.. but maybe add later.
25629 // and it should not de-activate the selected tab...
25630 this.fireEvent('activatepane', pane);
25631 pane.el.addClass('active');
25632 pane.fireEvent('activate');
25637 getActivePane : function()
25640 Roo.each(this.panes, function(p) {
25641 if(p.el.hasClass('active')){
25662 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25664 * @class Roo.bootstrap.TabPane
25665 * @extends Roo.bootstrap.Component
25666 * Bootstrap TabPane class
25667 * @cfg {Boolean} active (false | true) Default false
25668 * @cfg {String} title title of panel
25672 * Create a new TabPane
25673 * @param {Object} config The config object
25676 Roo.bootstrap.dash.TabPane = function(config){
25677 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25683 * When a pane is activated
25684 * @param {Roo.bootstrap.dash.TabPane} pane
25691 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25696 // the tabBox that this is attached to.
25699 getAutoCreate : function()
25707 cfg.cls += ' active';
25712 initEvents : function()
25714 //Roo.log('trigger add pane handler');
25715 this.parent().fireEvent('addpane', this)
25719 * Updates the tab title
25720 * @param {String} html to set the title to.
25722 setTitle: function(str)
25728 this.tab.select('a', true).first().dom.innerHTML = str;
25745 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25748 * @class Roo.bootstrap.menu.Menu
25749 * @extends Roo.bootstrap.Component
25750 * Bootstrap Menu class - container for Menu
25751 * @cfg {String} html Text of the menu
25752 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25753 * @cfg {String} icon Font awesome icon
25754 * @cfg {String} pos Menu align to (top | bottom) default bottom
25758 * Create a new Menu
25759 * @param {Object} config The config object
25763 Roo.bootstrap.menu.Menu = function(config){
25764 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25768 * @event beforeshow
25769 * Fires before this menu is displayed
25770 * @param {Roo.bootstrap.menu.Menu} this
25774 * @event beforehide
25775 * Fires before this menu is hidden
25776 * @param {Roo.bootstrap.menu.Menu} this
25781 * Fires after this menu is displayed
25782 * @param {Roo.bootstrap.menu.Menu} this
25787 * Fires after this menu is hidden
25788 * @param {Roo.bootstrap.menu.Menu} this
25793 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25794 * @param {Roo.bootstrap.menu.Menu} this
25795 * @param {Roo.EventObject} e
25802 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25806 weight : 'default',
25811 getChildContainer : function() {
25812 if(this.isSubMenu){
25816 return this.el.select('ul.dropdown-menu', true).first();
25819 getAutoCreate : function()
25824 cls : 'roo-menu-text',
25832 cls : 'fa ' + this.icon
25843 cls : 'dropdown-button btn btn-' + this.weight,
25848 cls : 'dropdown-toggle btn btn-' + this.weight,
25858 cls : 'dropdown-menu'
25864 if(this.pos == 'top'){
25865 cfg.cls += ' dropup';
25868 if(this.isSubMenu){
25871 cls : 'dropdown-menu'
25878 onRender : function(ct, position)
25880 this.isSubMenu = ct.hasClass('dropdown-submenu');
25882 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25885 initEvents : function()
25887 if(this.isSubMenu){
25891 this.hidden = true;
25893 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25894 this.triggerEl.on('click', this.onTriggerPress, this);
25896 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25897 this.buttonEl.on('click', this.onClick, this);
25903 if(this.isSubMenu){
25907 return this.el.select('ul.dropdown-menu', true).first();
25910 onClick : function(e)
25912 this.fireEvent("click", this, e);
25915 onTriggerPress : function(e)
25917 if (this.isVisible()) {
25924 isVisible : function(){
25925 return !this.hidden;
25930 this.fireEvent("beforeshow", this);
25932 this.hidden = false;
25933 this.el.addClass('open');
25935 Roo.get(document).on("mouseup", this.onMouseUp, this);
25937 this.fireEvent("show", this);
25944 this.fireEvent("beforehide", this);
25946 this.hidden = true;
25947 this.el.removeClass('open');
25949 Roo.get(document).un("mouseup", this.onMouseUp);
25951 this.fireEvent("hide", this);
25954 onMouseUp : function()
25968 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25971 * @class Roo.bootstrap.menu.Item
25972 * @extends Roo.bootstrap.Component
25973 * Bootstrap MenuItem class
25974 * @cfg {Boolean} submenu (true | false) default false
25975 * @cfg {String} html text of the item
25976 * @cfg {String} href the link
25977 * @cfg {Boolean} disable (true | false) default false
25978 * @cfg {Boolean} preventDefault (true | false) default true
25979 * @cfg {String} icon Font awesome icon
25980 * @cfg {String} pos Submenu align to (left | right) default right
25984 * Create a new Item
25985 * @param {Object} config The config object
25989 Roo.bootstrap.menu.Item = function(config){
25990 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25994 * Fires when the mouse is hovering over this menu
25995 * @param {Roo.bootstrap.menu.Item} this
25996 * @param {Roo.EventObject} e
26001 * Fires when the mouse exits this menu
26002 * @param {Roo.bootstrap.menu.Item} this
26003 * @param {Roo.EventObject} e
26009 * The raw click event for the entire grid.
26010 * @param {Roo.EventObject} e
26016 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26021 preventDefault: true,
26026 getAutoCreate : function()
26031 cls : 'roo-menu-item-text',
26039 cls : 'fa ' + this.icon
26048 href : this.href || '#',
26055 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26059 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26061 if(this.pos == 'left'){
26062 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26069 initEvents : function()
26071 this.el.on('mouseover', this.onMouseOver, this);
26072 this.el.on('mouseout', this.onMouseOut, this);
26074 this.el.select('a', true).first().on('click', this.onClick, this);
26078 onClick : function(e)
26080 if(this.preventDefault){
26081 e.preventDefault();
26084 this.fireEvent("click", this, e);
26087 onMouseOver : function(e)
26089 if(this.submenu && this.pos == 'left'){
26090 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26093 this.fireEvent("mouseover", this, e);
26096 onMouseOut : function(e)
26098 this.fireEvent("mouseout", this, e);
26110 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26113 * @class Roo.bootstrap.menu.Separator
26114 * @extends Roo.bootstrap.Component
26115 * Bootstrap Separator class
26118 * Create a new Separator
26119 * @param {Object} config The config object
26123 Roo.bootstrap.menu.Separator = function(config){
26124 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26127 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26129 getAutoCreate : function(){
26150 * @class Roo.bootstrap.Tooltip
26151 * Bootstrap Tooltip class
26152 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26153 * to determine which dom element triggers the tooltip.
26155 * It needs to add support for additional attributes like tooltip-position
26158 * Create a new Toolti
26159 * @param {Object} config The config object
26162 Roo.bootstrap.Tooltip = function(config){
26163 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26165 this.alignment = Roo.bootstrap.Tooltip.alignment;
26167 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26168 this.alignment = config.alignment;
26173 Roo.apply(Roo.bootstrap.Tooltip, {
26175 * @function init initialize tooltip monitoring.
26179 currentTip : false,
26180 currentRegion : false,
26186 Roo.get(document).on('mouseover', this.enter ,this);
26187 Roo.get(document).on('mouseout', this.leave, this);
26190 this.currentTip = new Roo.bootstrap.Tooltip();
26193 enter : function(ev)
26195 var dom = ev.getTarget();
26197 //Roo.log(['enter',dom]);
26198 var el = Roo.fly(dom);
26199 if (this.currentEl) {
26201 //Roo.log(this.currentEl);
26202 //Roo.log(this.currentEl.contains(dom));
26203 if (this.currentEl == el) {
26206 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26212 if (this.currentTip.el) {
26213 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26217 if(!el || el.dom == document){
26223 // you can not look for children, as if el is the body.. then everythign is the child..
26224 if (!el.attr('tooltip')) { //
26225 if (!el.select("[tooltip]").elements.length) {
26228 // is the mouse over this child...?
26229 bindEl = el.select("[tooltip]").first();
26230 var xy = ev.getXY();
26231 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26232 //Roo.log("not in region.");
26235 //Roo.log("child element over..");
26238 this.currentEl = bindEl;
26239 this.currentTip.bind(bindEl);
26240 this.currentRegion = Roo.lib.Region.getRegion(dom);
26241 this.currentTip.enter();
26244 leave : function(ev)
26246 var dom = ev.getTarget();
26247 //Roo.log(['leave',dom]);
26248 if (!this.currentEl) {
26253 if (dom != this.currentEl.dom) {
26256 var xy = ev.getXY();
26257 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26260 // only activate leave if mouse cursor is outside... bounding box..
26265 if (this.currentTip) {
26266 this.currentTip.leave();
26268 //Roo.log('clear currentEl');
26269 this.currentEl = false;
26274 'left' : ['r-l', [-2,0], 'right'],
26275 'right' : ['l-r', [2,0], 'left'],
26276 'bottom' : ['t-b', [0,2], 'top'],
26277 'top' : [ 'b-t', [0,-2], 'bottom']
26283 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26288 delay : null, // can be { show : 300 , hide: 500}
26292 hoverState : null, //???
26294 placement : 'bottom',
26298 getAutoCreate : function(){
26305 cls : 'tooltip-arrow'
26308 cls : 'tooltip-inner'
26315 bind : function(el)
26321 enter : function () {
26323 if (this.timeout != null) {
26324 clearTimeout(this.timeout);
26327 this.hoverState = 'in';
26328 //Roo.log("enter - show");
26329 if (!this.delay || !this.delay.show) {
26334 this.timeout = setTimeout(function () {
26335 if (_t.hoverState == 'in') {
26338 }, this.delay.show);
26342 clearTimeout(this.timeout);
26344 this.hoverState = 'out';
26345 if (!this.delay || !this.delay.hide) {
26351 this.timeout = setTimeout(function () {
26352 //Roo.log("leave - timeout");
26354 if (_t.hoverState == 'out') {
26356 Roo.bootstrap.Tooltip.currentEl = false;
26361 show : function (msg)
26364 this.render(document.body);
26367 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26369 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26371 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26373 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26375 var placement = typeof this.placement == 'function' ?
26376 this.placement.call(this, this.el, on_el) :
26379 var autoToken = /\s?auto?\s?/i;
26380 var autoPlace = autoToken.test(placement);
26382 placement = placement.replace(autoToken, '') || 'top';
26386 //this.el.setXY([0,0]);
26388 //this.el.dom.style.display='block';
26390 //this.el.appendTo(on_el);
26392 var p = this.getPosition();
26393 var box = this.el.getBox();
26399 var align = this.alignment[placement];
26401 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26403 if(placement == 'top' || placement == 'bottom'){
26405 placement = 'right';
26408 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26409 placement = 'left';
26412 var scroll = Roo.select('body', true).first().getScroll();
26414 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26418 align = this.alignment[placement];
26421 this.el.alignTo(this.bindEl, align[0],align[1]);
26422 //var arrow = this.el.select('.arrow',true).first();
26423 //arrow.set(align[2],
26425 this.el.addClass(placement);
26427 this.el.addClass('in fade');
26429 this.hoverState = null;
26431 if (this.el.hasClass('fade')) {
26442 //this.el.setXY([0,0]);
26443 this.el.removeClass('in');
26459 * @class Roo.bootstrap.LocationPicker
26460 * @extends Roo.bootstrap.Component
26461 * Bootstrap LocationPicker class
26462 * @cfg {Number} latitude Position when init default 0
26463 * @cfg {Number} longitude Position when init default 0
26464 * @cfg {Number} zoom default 15
26465 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26466 * @cfg {Boolean} mapTypeControl default false
26467 * @cfg {Boolean} disableDoubleClickZoom default false
26468 * @cfg {Boolean} scrollwheel default true
26469 * @cfg {Boolean} streetViewControl default false
26470 * @cfg {Number} radius default 0
26471 * @cfg {String} locationName
26472 * @cfg {Boolean} draggable default true
26473 * @cfg {Boolean} enableAutocomplete default false
26474 * @cfg {Boolean} enableReverseGeocode default true
26475 * @cfg {String} markerTitle
26478 * Create a new LocationPicker
26479 * @param {Object} config The config object
26483 Roo.bootstrap.LocationPicker = function(config){
26485 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26490 * Fires when the picker initialized.
26491 * @param {Roo.bootstrap.LocationPicker} this
26492 * @param {Google Location} location
26496 * @event positionchanged
26497 * Fires when the picker position changed.
26498 * @param {Roo.bootstrap.LocationPicker} this
26499 * @param {Google Location} location
26501 positionchanged : true,
26504 * Fires when the map resize.
26505 * @param {Roo.bootstrap.LocationPicker} this
26510 * Fires when the map show.
26511 * @param {Roo.bootstrap.LocationPicker} this
26516 * Fires when the map hide.
26517 * @param {Roo.bootstrap.LocationPicker} this
26522 * Fires when click the map.
26523 * @param {Roo.bootstrap.LocationPicker} this
26524 * @param {Map event} e
26528 * @event mapRightClick
26529 * Fires when right click the map.
26530 * @param {Roo.bootstrap.LocationPicker} this
26531 * @param {Map event} e
26533 mapRightClick : true,
26535 * @event markerClick
26536 * Fires when click the marker.
26537 * @param {Roo.bootstrap.LocationPicker} this
26538 * @param {Map event} e
26540 markerClick : true,
26542 * @event markerRightClick
26543 * Fires when right click the marker.
26544 * @param {Roo.bootstrap.LocationPicker} this
26545 * @param {Map event} e
26547 markerRightClick : true,
26549 * @event OverlayViewDraw
26550 * Fires when OverlayView Draw
26551 * @param {Roo.bootstrap.LocationPicker} this
26553 OverlayViewDraw : true,
26555 * @event OverlayViewOnAdd
26556 * Fires when OverlayView Draw
26557 * @param {Roo.bootstrap.LocationPicker} this
26559 OverlayViewOnAdd : true,
26561 * @event OverlayViewOnRemove
26562 * Fires when OverlayView Draw
26563 * @param {Roo.bootstrap.LocationPicker} this
26565 OverlayViewOnRemove : true,
26567 * @event OverlayViewShow
26568 * Fires when OverlayView Draw
26569 * @param {Roo.bootstrap.LocationPicker} this
26570 * @param {Pixel} cpx
26572 OverlayViewShow : true,
26574 * @event OverlayViewHide
26575 * Fires when OverlayView Draw
26576 * @param {Roo.bootstrap.LocationPicker} this
26578 OverlayViewHide : true,
26580 * @event loadexception
26581 * Fires when load google lib failed.
26582 * @param {Roo.bootstrap.LocationPicker} this
26584 loadexception : true
26589 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26591 gMapContext: false,
26597 mapTypeControl: false,
26598 disableDoubleClickZoom: false,
26600 streetViewControl: false,
26604 enableAutocomplete: false,
26605 enableReverseGeocode: true,
26608 getAutoCreate: function()
26613 cls: 'roo-location-picker'
26619 initEvents: function(ct, position)
26621 if(!this.el.getWidth() || this.isApplied()){
26625 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26630 initial: function()
26632 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26633 this.fireEvent('loadexception', this);
26637 if(!this.mapTypeId){
26638 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26641 this.gMapContext = this.GMapContext();
26643 this.initOverlayView();
26645 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26649 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26650 _this.setPosition(_this.gMapContext.marker.position);
26653 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26654 _this.fireEvent('mapClick', this, event);
26658 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26659 _this.fireEvent('mapRightClick', this, event);
26663 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26664 _this.fireEvent('markerClick', this, event);
26668 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26669 _this.fireEvent('markerRightClick', this, event);
26673 this.setPosition(this.gMapContext.location);
26675 this.fireEvent('initial', this, this.gMapContext.location);
26678 initOverlayView: function()
26682 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26686 _this.fireEvent('OverlayViewDraw', _this);
26691 _this.fireEvent('OverlayViewOnAdd', _this);
26694 onRemove: function()
26696 _this.fireEvent('OverlayViewOnRemove', _this);
26699 show: function(cpx)
26701 _this.fireEvent('OverlayViewShow', _this, cpx);
26706 _this.fireEvent('OverlayViewHide', _this);
26712 fromLatLngToContainerPixel: function(event)
26714 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26717 isApplied: function()
26719 return this.getGmapContext() == false ? false : true;
26722 getGmapContext: function()
26724 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26727 GMapContext: function()
26729 var position = new google.maps.LatLng(this.latitude, this.longitude);
26731 var _map = new google.maps.Map(this.el.dom, {
26734 mapTypeId: this.mapTypeId,
26735 mapTypeControl: this.mapTypeControl,
26736 disableDoubleClickZoom: this.disableDoubleClickZoom,
26737 scrollwheel: this.scrollwheel,
26738 streetViewControl: this.streetViewControl,
26739 locationName: this.locationName,
26740 draggable: this.draggable,
26741 enableAutocomplete: this.enableAutocomplete,
26742 enableReverseGeocode: this.enableReverseGeocode
26745 var _marker = new google.maps.Marker({
26746 position: position,
26748 title: this.markerTitle,
26749 draggable: this.draggable
26756 location: position,
26757 radius: this.radius,
26758 locationName: this.locationName,
26759 addressComponents: {
26760 formatted_address: null,
26761 addressLine1: null,
26762 addressLine2: null,
26764 streetNumber: null,
26768 stateOrProvince: null
26771 domContainer: this.el.dom,
26772 geodecoder: new google.maps.Geocoder()
26776 drawCircle: function(center, radius, options)
26778 if (this.gMapContext.circle != null) {
26779 this.gMapContext.circle.setMap(null);
26783 options = Roo.apply({}, options, {
26784 strokeColor: "#0000FF",
26785 strokeOpacity: .35,
26787 fillColor: "#0000FF",
26791 options.map = this.gMapContext.map;
26792 options.radius = radius;
26793 options.center = center;
26794 this.gMapContext.circle = new google.maps.Circle(options);
26795 return this.gMapContext.circle;
26801 setPosition: function(location)
26803 this.gMapContext.location = location;
26804 this.gMapContext.marker.setPosition(location);
26805 this.gMapContext.map.panTo(location);
26806 this.drawCircle(location, this.gMapContext.radius, {});
26810 if (this.gMapContext.settings.enableReverseGeocode) {
26811 this.gMapContext.geodecoder.geocode({
26812 latLng: this.gMapContext.location
26813 }, function(results, status) {
26815 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26816 _this.gMapContext.locationName = results[0].formatted_address;
26817 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26819 _this.fireEvent('positionchanged', this, location);
26826 this.fireEvent('positionchanged', this, location);
26831 google.maps.event.trigger(this.gMapContext.map, "resize");
26833 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26835 this.fireEvent('resize', this);
26838 setPositionByLatLng: function(latitude, longitude)
26840 this.setPosition(new google.maps.LatLng(latitude, longitude));
26843 getCurrentPosition: function()
26846 latitude: this.gMapContext.location.lat(),
26847 longitude: this.gMapContext.location.lng()
26851 getAddressName: function()
26853 return this.gMapContext.locationName;
26856 getAddressComponents: function()
26858 return this.gMapContext.addressComponents;
26861 address_component_from_google_geocode: function(address_components)
26865 for (var i = 0; i < address_components.length; i++) {
26866 var component = address_components[i];
26867 if (component.types.indexOf("postal_code") >= 0) {
26868 result.postalCode = component.short_name;
26869 } else if (component.types.indexOf("street_number") >= 0) {
26870 result.streetNumber = component.short_name;
26871 } else if (component.types.indexOf("route") >= 0) {
26872 result.streetName = component.short_name;
26873 } else if (component.types.indexOf("neighborhood") >= 0) {
26874 result.city = component.short_name;
26875 } else if (component.types.indexOf("locality") >= 0) {
26876 result.city = component.short_name;
26877 } else if (component.types.indexOf("sublocality") >= 0) {
26878 result.district = component.short_name;
26879 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26880 result.stateOrProvince = component.short_name;
26881 } else if (component.types.indexOf("country") >= 0) {
26882 result.country = component.short_name;
26886 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26887 result.addressLine2 = "";
26891 setZoomLevel: function(zoom)
26893 this.gMapContext.map.setZoom(zoom);
26906 this.fireEvent('show', this);
26917 this.fireEvent('hide', this);
26922 Roo.apply(Roo.bootstrap.LocationPicker, {
26924 OverlayView : function(map, options)
26926 options = options || {};
26940 * @class Roo.bootstrap.Alert
26941 * @extends Roo.bootstrap.Component
26942 * Bootstrap Alert class
26943 * @cfg {String} title The title of alert
26944 * @cfg {String} html The content of alert
26945 * @cfg {String} weight ( success | info | warning | danger )
26946 * @cfg {String} faicon font-awesomeicon
26949 * Create a new alert
26950 * @param {Object} config The config object
26954 Roo.bootstrap.Alert = function(config){
26955 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26959 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26966 getAutoCreate : function()
26975 cls : 'roo-alert-icon'
26980 cls : 'roo-alert-title',
26985 cls : 'roo-alert-text',
26992 cfg.cn[0].cls += ' fa ' + this.faicon;
26996 cfg.cls += ' alert-' + this.weight;
27002 initEvents: function()
27004 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27007 setTitle : function(str)
27009 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27012 setText : function(str)
27014 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27017 setWeight : function(weight)
27020 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27023 this.weight = weight;
27025 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27028 setIcon : function(icon)
27031 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27034 this.faicon = icon;
27036 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27057 * @class Roo.bootstrap.UploadCropbox
27058 * @extends Roo.bootstrap.Component
27059 * Bootstrap UploadCropbox class
27060 * @cfg {String} emptyText show when image has been loaded
27061 * @cfg {String} rotateNotify show when image too small to rotate
27062 * @cfg {Number} errorTimeout default 3000
27063 * @cfg {Number} minWidth default 300
27064 * @cfg {Number} minHeight default 300
27065 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27066 * @cfg {Boolean} isDocument (true|false) default false
27067 * @cfg {String} url action url
27068 * @cfg {String} paramName default 'imageUpload'
27069 * @cfg {String} method default POST
27070 * @cfg {Boolean} loadMask (true|false) default true
27071 * @cfg {Boolean} loadingText default 'Loading...'
27074 * Create a new UploadCropbox
27075 * @param {Object} config The config object
27078 Roo.bootstrap.UploadCropbox = function(config){
27079 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27083 * @event beforeselectfile
27084 * Fire before select file
27085 * @param {Roo.bootstrap.UploadCropbox} this
27087 "beforeselectfile" : true,
27090 * Fire after initEvent
27091 * @param {Roo.bootstrap.UploadCropbox} this
27096 * Fire after initEvent
27097 * @param {Roo.bootstrap.UploadCropbox} this
27098 * @param {String} data
27103 * Fire when preparing the file data
27104 * @param {Roo.bootstrap.UploadCropbox} this
27105 * @param {Object} file
27110 * Fire when get exception
27111 * @param {Roo.bootstrap.UploadCropbox} this
27112 * @param {XMLHttpRequest} xhr
27114 "exception" : true,
27116 * @event beforeloadcanvas
27117 * Fire before load the canvas
27118 * @param {Roo.bootstrap.UploadCropbox} this
27119 * @param {String} src
27121 "beforeloadcanvas" : true,
27124 * Fire when trash image
27125 * @param {Roo.bootstrap.UploadCropbox} this
27130 * Fire when download the image
27131 * @param {Roo.bootstrap.UploadCropbox} this
27135 * @event footerbuttonclick
27136 * Fire when footerbuttonclick
27137 * @param {Roo.bootstrap.UploadCropbox} this
27138 * @param {String} type
27140 "footerbuttonclick" : true,
27144 * @param {Roo.bootstrap.UploadCropbox} this
27149 * Fire when rotate the image
27150 * @param {Roo.bootstrap.UploadCropbox} this
27151 * @param {String} pos
27156 * Fire when inspect the file
27157 * @param {Roo.bootstrap.UploadCropbox} this
27158 * @param {Object} file
27163 * Fire when xhr upload the file
27164 * @param {Roo.bootstrap.UploadCropbox} this
27165 * @param {Object} data
27170 * Fire when arrange the file data
27171 * @param {Roo.bootstrap.UploadCropbox} this
27172 * @param {Object} formData
27177 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27180 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27182 emptyText : 'Click to upload image',
27183 rotateNotify : 'Image is too small to rotate',
27184 errorTimeout : 3000,
27198 cropType : 'image/jpeg',
27200 canvasLoaded : false,
27201 isDocument : false,
27203 paramName : 'imageUpload',
27205 loadingText : 'Loading...',
27208 getAutoCreate : function()
27212 cls : 'roo-upload-cropbox',
27216 cls : 'roo-upload-cropbox-selector',
27221 cls : 'roo-upload-cropbox-body',
27222 style : 'cursor:pointer',
27226 cls : 'roo-upload-cropbox-preview'
27230 cls : 'roo-upload-cropbox-thumb'
27234 cls : 'roo-upload-cropbox-empty-notify',
27235 html : this.emptyText
27239 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27240 html : this.rotateNotify
27246 cls : 'roo-upload-cropbox-footer',
27249 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27259 onRender : function(ct, position)
27261 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27263 if (this.buttons.length) {
27265 Roo.each(this.buttons, function(bb) {
27267 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27269 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27275 this.maskEl = this.el;
27279 initEvents : function()
27281 this.urlAPI = (window.createObjectURL && window) ||
27282 (window.URL && URL.revokeObjectURL && URL) ||
27283 (window.webkitURL && webkitURL);
27285 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27286 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27288 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27289 this.selectorEl.hide();
27291 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27292 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27294 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27295 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27296 this.thumbEl.hide();
27298 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27299 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27301 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27302 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27303 this.errorEl.hide();
27305 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27306 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27307 this.footerEl.hide();
27309 this.setThumbBoxSize();
27315 this.fireEvent('initial', this);
27322 window.addEventListener("resize", function() { _this.resize(); } );
27324 this.bodyEl.on('click', this.beforeSelectFile, this);
27327 this.bodyEl.on('touchstart', this.onTouchStart, this);
27328 this.bodyEl.on('touchmove', this.onTouchMove, this);
27329 this.bodyEl.on('touchend', this.onTouchEnd, this);
27333 this.bodyEl.on('mousedown', this.onMouseDown, this);
27334 this.bodyEl.on('mousemove', this.onMouseMove, this);
27335 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27336 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27337 Roo.get(document).on('mouseup', this.onMouseUp, this);
27340 this.selectorEl.on('change', this.onFileSelected, this);
27346 this.baseScale = 1;
27348 this.baseRotate = 1;
27349 this.dragable = false;
27350 this.pinching = false;
27353 this.cropData = false;
27354 this.notifyEl.dom.innerHTML = this.emptyText;
27356 this.selectorEl.dom.value = '';
27360 resize : function()
27362 if(this.fireEvent('resize', this) != false){
27363 this.setThumbBoxPosition();
27364 this.setCanvasPosition();
27368 onFooterButtonClick : function(e, el, o, type)
27371 case 'rotate-left' :
27372 this.onRotateLeft(e);
27374 case 'rotate-right' :
27375 this.onRotateRight(e);
27378 this.beforeSelectFile(e);
27393 this.fireEvent('footerbuttonclick', this, type);
27396 beforeSelectFile : function(e)
27398 e.preventDefault();
27400 if(this.fireEvent('beforeselectfile', this) != false){
27401 this.selectorEl.dom.click();
27405 onFileSelected : function(e)
27407 e.preventDefault();
27409 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27413 var file = this.selectorEl.dom.files[0];
27415 if(this.fireEvent('inspect', this, file) != false){
27416 this.prepare(file);
27421 trash : function(e)
27423 this.fireEvent('trash', this);
27426 download : function(e)
27428 this.fireEvent('download', this);
27431 loadCanvas : function(src)
27433 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27437 this.imageEl = document.createElement('img');
27441 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27443 this.imageEl.src = src;
27447 onLoadCanvas : function()
27449 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27450 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27452 this.bodyEl.un('click', this.beforeSelectFile, this);
27454 this.notifyEl.hide();
27455 this.thumbEl.show();
27456 this.footerEl.show();
27458 this.baseRotateLevel();
27460 if(this.isDocument){
27461 this.setThumbBoxSize();
27464 this.setThumbBoxPosition();
27466 this.baseScaleLevel();
27472 this.canvasLoaded = true;
27475 this.maskEl.unmask();
27480 setCanvasPosition : function()
27482 if(!this.canvasEl){
27486 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27487 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27489 this.previewEl.setLeft(pw);
27490 this.previewEl.setTop(ph);
27494 onMouseDown : function(e)
27498 this.dragable = true;
27499 this.pinching = false;
27501 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27502 this.dragable = false;
27506 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27507 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27511 onMouseMove : function(e)
27515 if(!this.canvasLoaded){
27519 if (!this.dragable){
27523 var minX = Math.ceil(this.thumbEl.getLeft(true));
27524 var minY = Math.ceil(this.thumbEl.getTop(true));
27526 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27527 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27529 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27530 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27532 x = x - this.mouseX;
27533 y = y - this.mouseY;
27535 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27536 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27538 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27539 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27541 this.previewEl.setLeft(bgX);
27542 this.previewEl.setTop(bgY);
27544 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27545 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27548 onMouseUp : function(e)
27552 this.dragable = false;
27555 onMouseWheel : function(e)
27559 this.startScale = this.scale;
27561 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27563 if(!this.zoomable()){
27564 this.scale = this.startScale;
27573 zoomable : function()
27575 var minScale = this.thumbEl.getWidth() / this.minWidth;
27577 if(this.minWidth < this.minHeight){
27578 minScale = this.thumbEl.getHeight() / this.minHeight;
27581 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27582 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27586 (this.rotate == 0 || this.rotate == 180) &&
27588 width > this.imageEl.OriginWidth ||
27589 height > this.imageEl.OriginHeight ||
27590 (width < this.minWidth && height < this.minHeight)
27598 (this.rotate == 90 || this.rotate == 270) &&
27600 width > this.imageEl.OriginWidth ||
27601 height > this.imageEl.OriginHeight ||
27602 (width < this.minHeight && height < this.minWidth)
27609 !this.isDocument &&
27610 (this.rotate == 0 || this.rotate == 180) &&
27612 width < this.minWidth ||
27613 width > this.imageEl.OriginWidth ||
27614 height < this.minHeight ||
27615 height > this.imageEl.OriginHeight
27622 !this.isDocument &&
27623 (this.rotate == 90 || this.rotate == 270) &&
27625 width < this.minHeight ||
27626 width > this.imageEl.OriginWidth ||
27627 height < this.minWidth ||
27628 height > this.imageEl.OriginHeight
27638 onRotateLeft : function(e)
27640 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27642 var minScale = this.thumbEl.getWidth() / this.minWidth;
27644 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27645 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27647 this.startScale = this.scale;
27649 while (this.getScaleLevel() < minScale){
27651 this.scale = this.scale + 1;
27653 if(!this.zoomable()){
27658 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27659 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27664 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27671 this.scale = this.startScale;
27673 this.onRotateFail();
27678 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27680 if(this.isDocument){
27681 this.setThumbBoxSize();
27682 this.setThumbBoxPosition();
27683 this.setCanvasPosition();
27688 this.fireEvent('rotate', this, 'left');
27692 onRotateRight : function(e)
27694 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27696 var minScale = this.thumbEl.getWidth() / this.minWidth;
27698 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27699 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27701 this.startScale = this.scale;
27703 while (this.getScaleLevel() < minScale){
27705 this.scale = this.scale + 1;
27707 if(!this.zoomable()){
27712 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27713 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27718 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27725 this.scale = this.startScale;
27727 this.onRotateFail();
27732 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27734 if(this.isDocument){
27735 this.setThumbBoxSize();
27736 this.setThumbBoxPosition();
27737 this.setCanvasPosition();
27742 this.fireEvent('rotate', this, 'right');
27745 onRotateFail : function()
27747 this.errorEl.show(true);
27751 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27756 this.previewEl.dom.innerHTML = '';
27758 var canvasEl = document.createElement("canvas");
27760 var contextEl = canvasEl.getContext("2d");
27762 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27763 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27764 var center = this.imageEl.OriginWidth / 2;
27766 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27767 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27768 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27769 center = this.imageEl.OriginHeight / 2;
27772 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27774 contextEl.translate(center, center);
27775 contextEl.rotate(this.rotate * Math.PI / 180);
27777 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27779 this.canvasEl = document.createElement("canvas");
27781 this.contextEl = this.canvasEl.getContext("2d");
27783 switch (this.rotate) {
27786 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27787 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27789 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27794 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27795 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27797 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27798 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27802 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27807 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27808 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27810 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27811 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27815 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27820 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27821 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27823 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27824 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27828 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27835 this.previewEl.appendChild(this.canvasEl);
27837 this.setCanvasPosition();
27842 if(!this.canvasLoaded){
27846 var imageCanvas = document.createElement("canvas");
27848 var imageContext = imageCanvas.getContext("2d");
27850 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27851 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27853 var center = imageCanvas.width / 2;
27855 imageContext.translate(center, center);
27857 imageContext.rotate(this.rotate * Math.PI / 180);
27859 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27861 var canvas = document.createElement("canvas");
27863 var context = canvas.getContext("2d");
27865 canvas.width = this.minWidth;
27866 canvas.height = this.minHeight;
27868 switch (this.rotate) {
27871 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27872 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27874 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27875 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27877 var targetWidth = this.minWidth - 2 * x;
27878 var targetHeight = this.minHeight - 2 * y;
27882 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27883 scale = targetWidth / width;
27886 if(x > 0 && y == 0){
27887 scale = targetHeight / height;
27890 if(x > 0 && y > 0){
27891 scale = targetWidth / width;
27893 if(width < height){
27894 scale = targetHeight / height;
27898 context.scale(scale, scale);
27900 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27901 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27903 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27904 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27906 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27911 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27912 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27914 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27915 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27917 var targetWidth = this.minWidth - 2 * x;
27918 var targetHeight = this.minHeight - 2 * y;
27922 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27923 scale = targetWidth / width;
27926 if(x > 0 && y == 0){
27927 scale = targetHeight / height;
27930 if(x > 0 && y > 0){
27931 scale = targetWidth / width;
27933 if(width < height){
27934 scale = targetHeight / height;
27938 context.scale(scale, scale);
27940 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27941 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27943 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27944 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27946 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27948 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27953 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27954 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27956 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27957 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27959 var targetWidth = this.minWidth - 2 * x;
27960 var targetHeight = this.minHeight - 2 * y;
27964 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27965 scale = targetWidth / width;
27968 if(x > 0 && y == 0){
27969 scale = targetHeight / height;
27972 if(x > 0 && y > 0){
27973 scale = targetWidth / width;
27975 if(width < height){
27976 scale = targetHeight / height;
27980 context.scale(scale, scale);
27982 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27983 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27985 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27986 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27988 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27989 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27991 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27996 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27997 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27999 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28000 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28002 var targetWidth = this.minWidth - 2 * x;
28003 var targetHeight = this.minHeight - 2 * y;
28007 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28008 scale = targetWidth / width;
28011 if(x > 0 && y == 0){
28012 scale = targetHeight / height;
28015 if(x > 0 && y > 0){
28016 scale = targetWidth / width;
28018 if(width < height){
28019 scale = targetHeight / height;
28023 context.scale(scale, scale);
28025 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28026 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28028 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28029 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28031 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28033 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28040 this.cropData = canvas.toDataURL(this.cropType);
28042 if(this.fireEvent('crop', this, this.cropData) !== false){
28043 this.process(this.file, this.cropData);
28050 setThumbBoxSize : function()
28054 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28055 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28056 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28058 this.minWidth = width;
28059 this.minHeight = height;
28061 if(this.rotate == 90 || this.rotate == 270){
28062 this.minWidth = height;
28063 this.minHeight = width;
28068 width = Math.ceil(this.minWidth * height / this.minHeight);
28070 if(this.minWidth > this.minHeight){
28072 height = Math.ceil(this.minHeight * width / this.minWidth);
28075 this.thumbEl.setStyle({
28076 width : width + 'px',
28077 height : height + 'px'
28084 setThumbBoxPosition : function()
28086 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28087 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28089 this.thumbEl.setLeft(x);
28090 this.thumbEl.setTop(y);
28094 baseRotateLevel : function()
28096 this.baseRotate = 1;
28099 typeof(this.exif) != 'undefined' &&
28100 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28101 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28103 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28106 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28110 baseScaleLevel : function()
28114 if(this.isDocument){
28116 if(this.baseRotate == 6 || this.baseRotate == 8){
28118 height = this.thumbEl.getHeight();
28119 this.baseScale = height / this.imageEl.OriginWidth;
28121 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28122 width = this.thumbEl.getWidth();
28123 this.baseScale = width / this.imageEl.OriginHeight;
28129 height = this.thumbEl.getHeight();
28130 this.baseScale = height / this.imageEl.OriginHeight;
28132 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28133 width = this.thumbEl.getWidth();
28134 this.baseScale = width / this.imageEl.OriginWidth;
28140 if(this.baseRotate == 6 || this.baseRotate == 8){
28142 width = this.thumbEl.getHeight();
28143 this.baseScale = width / this.imageEl.OriginHeight;
28145 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28146 height = this.thumbEl.getWidth();
28147 this.baseScale = height / this.imageEl.OriginHeight;
28150 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28151 height = this.thumbEl.getWidth();
28152 this.baseScale = height / this.imageEl.OriginHeight;
28154 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28155 width = this.thumbEl.getHeight();
28156 this.baseScale = width / this.imageEl.OriginWidth;
28163 width = this.thumbEl.getWidth();
28164 this.baseScale = width / this.imageEl.OriginWidth;
28166 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28167 height = this.thumbEl.getHeight();
28168 this.baseScale = height / this.imageEl.OriginHeight;
28171 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28173 height = this.thumbEl.getHeight();
28174 this.baseScale = height / this.imageEl.OriginHeight;
28176 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28177 width = this.thumbEl.getWidth();
28178 this.baseScale = width / this.imageEl.OriginWidth;
28186 getScaleLevel : function()
28188 return this.baseScale * Math.pow(1.1, this.scale);
28191 onTouchStart : function(e)
28193 if(!this.canvasLoaded){
28194 this.beforeSelectFile(e);
28198 var touches = e.browserEvent.touches;
28204 if(touches.length == 1){
28205 this.onMouseDown(e);
28209 if(touches.length != 2){
28215 for(var i = 0, finger; finger = touches[i]; i++){
28216 coords.push(finger.pageX, finger.pageY);
28219 var x = Math.pow(coords[0] - coords[2], 2);
28220 var y = Math.pow(coords[1] - coords[3], 2);
28222 this.startDistance = Math.sqrt(x + y);
28224 this.startScale = this.scale;
28226 this.pinching = true;
28227 this.dragable = false;
28231 onTouchMove : function(e)
28233 if(!this.pinching && !this.dragable){
28237 var touches = e.browserEvent.touches;
28244 this.onMouseMove(e);
28250 for(var i = 0, finger; finger = touches[i]; i++){
28251 coords.push(finger.pageX, finger.pageY);
28254 var x = Math.pow(coords[0] - coords[2], 2);
28255 var y = Math.pow(coords[1] - coords[3], 2);
28257 this.endDistance = Math.sqrt(x + y);
28259 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28261 if(!this.zoomable()){
28262 this.scale = this.startScale;
28270 onTouchEnd : function(e)
28272 this.pinching = false;
28273 this.dragable = false;
28277 process : function(file, crop)
28280 this.maskEl.mask(this.loadingText);
28283 this.xhr = new XMLHttpRequest();
28285 file.xhr = this.xhr;
28287 this.xhr.open(this.method, this.url, true);
28290 "Accept": "application/json",
28291 "Cache-Control": "no-cache",
28292 "X-Requested-With": "XMLHttpRequest"
28295 for (var headerName in headers) {
28296 var headerValue = headers[headerName];
28298 this.xhr.setRequestHeader(headerName, headerValue);
28304 this.xhr.onload = function()
28306 _this.xhrOnLoad(_this.xhr);
28309 this.xhr.onerror = function()
28311 _this.xhrOnError(_this.xhr);
28314 var formData = new FormData();
28316 formData.append('returnHTML', 'NO');
28319 formData.append('crop', crop);
28322 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28323 formData.append(this.paramName, file, file.name);
28326 if(typeof(file.filename) != 'undefined'){
28327 formData.append('filename', file.filename);
28330 if(typeof(file.mimetype) != 'undefined'){
28331 formData.append('mimetype', file.mimetype);
28334 if(this.fireEvent('arrange', this, formData) != false){
28335 this.xhr.send(formData);
28339 xhrOnLoad : function(xhr)
28342 this.maskEl.unmask();
28345 if (xhr.readyState !== 4) {
28346 this.fireEvent('exception', this, xhr);
28350 var response = Roo.decode(xhr.responseText);
28352 if(!response.success){
28353 this.fireEvent('exception', this, xhr);
28357 var response = Roo.decode(xhr.responseText);
28359 this.fireEvent('upload', this, response);
28363 xhrOnError : function()
28366 this.maskEl.unmask();
28369 Roo.log('xhr on error');
28371 var response = Roo.decode(xhr.responseText);
28377 prepare : function(file)
28380 this.maskEl.mask(this.loadingText);
28386 if(typeof(file) === 'string'){
28387 this.loadCanvas(file);
28391 if(!file || !this.urlAPI){
28396 this.cropType = file.type;
28400 if(this.fireEvent('prepare', this, this.file) != false){
28402 var reader = new FileReader();
28404 reader.onload = function (e) {
28405 if (e.target.error) {
28406 Roo.log(e.target.error);
28410 var buffer = e.target.result,
28411 dataView = new DataView(buffer),
28413 maxOffset = dataView.byteLength - 4,
28417 if (dataView.getUint16(0) === 0xffd8) {
28418 while (offset < maxOffset) {
28419 markerBytes = dataView.getUint16(offset);
28421 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28422 markerLength = dataView.getUint16(offset + 2) + 2;
28423 if (offset + markerLength > dataView.byteLength) {
28424 Roo.log('Invalid meta data: Invalid segment size.');
28428 if(markerBytes == 0xffe1){
28429 _this.parseExifData(
28436 offset += markerLength;
28446 var url = _this.urlAPI.createObjectURL(_this.file);
28448 _this.loadCanvas(url);
28453 reader.readAsArrayBuffer(this.file);
28459 parseExifData : function(dataView, offset, length)
28461 var tiffOffset = offset + 10,
28465 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28466 // No Exif data, might be XMP data instead
28470 // Check for the ASCII code for "Exif" (0x45786966):
28471 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28472 // No Exif data, might be XMP data instead
28475 if (tiffOffset + 8 > dataView.byteLength) {
28476 Roo.log('Invalid Exif data: Invalid segment size.');
28479 // Check for the two null bytes:
28480 if (dataView.getUint16(offset + 8) !== 0x0000) {
28481 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28484 // Check the byte alignment:
28485 switch (dataView.getUint16(tiffOffset)) {
28487 littleEndian = true;
28490 littleEndian = false;
28493 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28496 // Check for the TIFF tag marker (0x002A):
28497 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28498 Roo.log('Invalid Exif data: Missing TIFF marker.');
28501 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28502 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28504 this.parseExifTags(
28507 tiffOffset + dirOffset,
28512 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28517 if (dirOffset + 6 > dataView.byteLength) {
28518 Roo.log('Invalid Exif data: Invalid directory offset.');
28521 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28522 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28523 if (dirEndOffset + 4 > dataView.byteLength) {
28524 Roo.log('Invalid Exif data: Invalid directory size.');
28527 for (i = 0; i < tagsNumber; i += 1) {
28531 dirOffset + 2 + 12 * i, // tag offset
28535 // Return the offset to the next directory:
28536 return dataView.getUint32(dirEndOffset, littleEndian);
28539 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28541 var tag = dataView.getUint16(offset, littleEndian);
28543 this.exif[tag] = this.getExifValue(
28547 dataView.getUint16(offset + 2, littleEndian), // tag type
28548 dataView.getUint32(offset + 4, littleEndian), // tag length
28553 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28555 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28564 Roo.log('Invalid Exif data: Invalid tag type.');
28568 tagSize = tagType.size * length;
28569 // Determine if the value is contained in the dataOffset bytes,
28570 // or if the value at the dataOffset is a pointer to the actual data:
28571 dataOffset = tagSize > 4 ?
28572 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28573 if (dataOffset + tagSize > dataView.byteLength) {
28574 Roo.log('Invalid Exif data: Invalid data offset.');
28577 if (length === 1) {
28578 return tagType.getValue(dataView, dataOffset, littleEndian);
28581 for (i = 0; i < length; i += 1) {
28582 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28585 if (tagType.ascii) {
28587 // Concatenate the chars:
28588 for (i = 0; i < values.length; i += 1) {
28590 // Ignore the terminating NULL byte(s):
28591 if (c === '\u0000') {
28603 Roo.apply(Roo.bootstrap.UploadCropbox, {
28605 'Orientation': 0x0112
28609 1: 0, //'top-left',
28611 3: 180, //'bottom-right',
28612 // 4: 'bottom-left',
28614 6: 90, //'right-top',
28615 // 7: 'right-bottom',
28616 8: 270 //'left-bottom'
28620 // byte, 8-bit unsigned int:
28622 getValue: function (dataView, dataOffset) {
28623 return dataView.getUint8(dataOffset);
28627 // ascii, 8-bit byte:
28629 getValue: function (dataView, dataOffset) {
28630 return String.fromCharCode(dataView.getUint8(dataOffset));
28635 // short, 16 bit int:
28637 getValue: function (dataView, dataOffset, littleEndian) {
28638 return dataView.getUint16(dataOffset, littleEndian);
28642 // long, 32 bit int:
28644 getValue: function (dataView, dataOffset, littleEndian) {
28645 return dataView.getUint32(dataOffset, littleEndian);
28649 // rational = two long values, first is numerator, second is denominator:
28651 getValue: function (dataView, dataOffset, littleEndian) {
28652 return dataView.getUint32(dataOffset, littleEndian) /
28653 dataView.getUint32(dataOffset + 4, littleEndian);
28657 // slong, 32 bit signed int:
28659 getValue: function (dataView, dataOffset, littleEndian) {
28660 return dataView.getInt32(dataOffset, littleEndian);
28664 // srational, two slongs, first is numerator, second is denominator:
28666 getValue: function (dataView, dataOffset, littleEndian) {
28667 return dataView.getInt32(dataOffset, littleEndian) /
28668 dataView.getInt32(dataOffset + 4, littleEndian);
28678 cls : 'btn-group roo-upload-cropbox-rotate-left',
28679 action : 'rotate-left',
28683 cls : 'btn btn-default',
28684 html : '<i class="fa fa-undo"></i>'
28690 cls : 'btn-group roo-upload-cropbox-picture',
28691 action : 'picture',
28695 cls : 'btn btn-default',
28696 html : '<i class="fa fa-picture-o"></i>'
28702 cls : 'btn-group roo-upload-cropbox-rotate-right',
28703 action : 'rotate-right',
28707 cls : 'btn btn-default',
28708 html : '<i class="fa fa-repeat"></i>'
28716 cls : 'btn-group roo-upload-cropbox-rotate-left',
28717 action : 'rotate-left',
28721 cls : 'btn btn-default',
28722 html : '<i class="fa fa-undo"></i>'
28728 cls : 'btn-group roo-upload-cropbox-download',
28729 action : 'download',
28733 cls : 'btn btn-default',
28734 html : '<i class="fa fa-download"></i>'
28740 cls : 'btn-group roo-upload-cropbox-crop',
28745 cls : 'btn btn-default',
28746 html : '<i class="fa fa-crop"></i>'
28752 cls : 'btn-group roo-upload-cropbox-trash',
28757 cls : 'btn btn-default',
28758 html : '<i class="fa fa-trash"></i>'
28764 cls : 'btn-group roo-upload-cropbox-rotate-right',
28765 action : 'rotate-right',
28769 cls : 'btn btn-default',
28770 html : '<i class="fa fa-repeat"></i>'
28778 cls : 'btn-group roo-upload-cropbox-rotate-left',
28779 action : 'rotate-left',
28783 cls : 'btn btn-default',
28784 html : '<i class="fa fa-undo"></i>'
28790 cls : 'btn-group roo-upload-cropbox-rotate-right',
28791 action : 'rotate-right',
28795 cls : 'btn btn-default',
28796 html : '<i class="fa fa-repeat"></i>'
28809 * @class Roo.bootstrap.DocumentManager
28810 * @extends Roo.bootstrap.Component
28811 * Bootstrap DocumentManager class
28812 * @cfg {String} paramName default 'imageUpload'
28813 * @cfg {String} toolTipName default 'filename'
28814 * @cfg {String} method default POST
28815 * @cfg {String} url action url
28816 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28817 * @cfg {Boolean} multiple multiple upload default true
28818 * @cfg {Number} thumbSize default 300
28819 * @cfg {String} fieldLabel
28820 * @cfg {Number} labelWidth default 4
28821 * @cfg {String} labelAlign (left|top) default left
28822 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28823 * @cfg {Number} labellg set the width of label (1-12)
28824 * @cfg {Number} labelmd set the width of label (1-12)
28825 * @cfg {Number} labelsm set the width of label (1-12)
28826 * @cfg {Number} labelxs set the width of label (1-12)
28829 * Create a new DocumentManager
28830 * @param {Object} config The config object
28833 Roo.bootstrap.DocumentManager = function(config){
28834 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28837 this.delegates = [];
28842 * Fire when initial the DocumentManager
28843 * @param {Roo.bootstrap.DocumentManager} this
28848 * inspect selected file
28849 * @param {Roo.bootstrap.DocumentManager} this
28850 * @param {File} file
28855 * Fire when xhr load exception
28856 * @param {Roo.bootstrap.DocumentManager} this
28857 * @param {XMLHttpRequest} xhr
28859 "exception" : true,
28861 * @event afterupload
28862 * Fire when xhr load exception
28863 * @param {Roo.bootstrap.DocumentManager} this
28864 * @param {XMLHttpRequest} xhr
28866 "afterupload" : true,
28869 * prepare the form data
28870 * @param {Roo.bootstrap.DocumentManager} this
28871 * @param {Object} formData
28876 * Fire when remove the file
28877 * @param {Roo.bootstrap.DocumentManager} this
28878 * @param {Object} file
28883 * Fire after refresh the file
28884 * @param {Roo.bootstrap.DocumentManager} this
28889 * Fire after click the image
28890 * @param {Roo.bootstrap.DocumentManager} this
28891 * @param {Object} file
28896 * Fire when upload a image and editable set to true
28897 * @param {Roo.bootstrap.DocumentManager} this
28898 * @param {Object} file
28902 * @event beforeselectfile
28903 * Fire before select file
28904 * @param {Roo.bootstrap.DocumentManager} this
28906 "beforeselectfile" : true,
28909 * Fire before process file
28910 * @param {Roo.bootstrap.DocumentManager} this
28911 * @param {Object} file
28915 * @event previewrendered
28916 * Fire when preview rendered
28917 * @param {Roo.bootstrap.DocumentManager} this
28918 * @param {Object} file
28920 "previewrendered" : true,
28923 "previewResize" : true
28928 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28937 paramName : 'imageUpload',
28938 toolTipName : 'filename',
28941 labelAlign : 'left',
28951 getAutoCreate : function()
28953 var managerWidget = {
28955 cls : 'roo-document-manager',
28959 cls : 'roo-document-manager-selector',
28964 cls : 'roo-document-manager-uploader',
28968 cls : 'roo-document-manager-upload-btn',
28969 html : '<i class="fa fa-plus"></i>'
28980 cls : 'column col-md-12',
28985 if(this.fieldLabel.length){
28990 cls : 'column col-md-12',
28991 html : this.fieldLabel
28995 cls : 'column col-md-12',
29000 if(this.labelAlign == 'left'){
29005 html : this.fieldLabel
29014 if(this.labelWidth > 12){
29015 content[0].style = "width: " + this.labelWidth + 'px';
29018 if(this.labelWidth < 13 && this.labelmd == 0){
29019 this.labelmd = this.labelWidth;
29022 if(this.labellg > 0){
29023 content[0].cls += ' col-lg-' + this.labellg;
29024 content[1].cls += ' col-lg-' + (12 - this.labellg);
29027 if(this.labelmd > 0){
29028 content[0].cls += ' col-md-' + this.labelmd;
29029 content[1].cls += ' col-md-' + (12 - this.labelmd);
29032 if(this.labelsm > 0){
29033 content[0].cls += ' col-sm-' + this.labelsm;
29034 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29037 if(this.labelxs > 0){
29038 content[0].cls += ' col-xs-' + this.labelxs;
29039 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29047 cls : 'row clearfix',
29055 initEvents : function()
29057 this.managerEl = this.el.select('.roo-document-manager', true).first();
29058 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29060 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29061 this.selectorEl.hide();
29064 this.selectorEl.attr('multiple', 'multiple');
29067 this.selectorEl.on('change', this.onFileSelected, this);
29069 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29070 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29072 this.uploader.on('click', this.onUploaderClick, this);
29074 this.renderProgressDialog();
29078 window.addEventListener("resize", function() { _this.refresh(); } );
29080 this.fireEvent('initial', this);
29083 renderProgressDialog : function()
29087 this.progressDialog = new Roo.bootstrap.Modal({
29088 cls : 'roo-document-manager-progress-dialog',
29089 allow_close : false,
29099 btnclick : function() {
29100 _this.uploadCancel();
29106 this.progressDialog.render(Roo.get(document.body));
29108 this.progress = new Roo.bootstrap.Progress({
29109 cls : 'roo-document-manager-progress',
29114 this.progress.render(this.progressDialog.getChildContainer());
29116 this.progressBar = new Roo.bootstrap.ProgressBar({
29117 cls : 'roo-document-manager-progress-bar',
29120 aria_valuemax : 12,
29124 this.progressBar.render(this.progress.getChildContainer());
29127 onUploaderClick : function(e)
29129 e.preventDefault();
29131 if(this.fireEvent('beforeselectfile', this) != false){
29132 this.selectorEl.dom.click();
29137 onFileSelected : function(e)
29139 e.preventDefault();
29141 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29145 Roo.each(this.selectorEl.dom.files, function(file){
29146 if(this.fireEvent('inspect', this, file) != false){
29147 this.files.push(file);
29157 this.selectorEl.dom.value = '';
29159 if(!this.files || !this.files.length){
29163 if(this.boxes > 0 && this.files.length > this.boxes){
29164 this.files = this.files.slice(0, this.boxes);
29167 this.uploader.show();
29169 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29170 this.uploader.hide();
29179 Roo.each(this.files, function(file){
29181 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29182 var f = this.renderPreview(file);
29187 if(file.type.indexOf('image') != -1){
29188 this.delegates.push(
29190 _this.process(file);
29191 }).createDelegate(this)
29199 _this.process(file);
29200 }).createDelegate(this)
29205 this.files = files;
29207 this.delegates = this.delegates.concat(docs);
29209 if(!this.delegates.length){
29214 this.progressBar.aria_valuemax = this.delegates.length;
29221 arrange : function()
29223 if(!this.delegates.length){
29224 this.progressDialog.hide();
29229 var delegate = this.delegates.shift();
29231 this.progressDialog.show();
29233 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29235 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29240 refresh : function()
29242 this.uploader.show();
29244 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29245 this.uploader.hide();
29248 Roo.isTouch ? this.closable(false) : this.closable(true);
29250 this.fireEvent('refresh', this);
29253 onRemove : function(e, el, o)
29255 e.preventDefault();
29257 this.fireEvent('remove', this, o);
29261 remove : function(o)
29265 Roo.each(this.files, function(file){
29266 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29275 this.files = files;
29282 Roo.each(this.files, function(file){
29287 file.target.remove();
29296 onClick : function(e, el, o)
29298 e.preventDefault();
29300 this.fireEvent('click', this, o);
29304 closable : function(closable)
29306 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29308 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29320 xhrOnLoad : function(xhr)
29322 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29326 if (xhr.readyState !== 4) {
29328 this.fireEvent('exception', this, xhr);
29332 var response = Roo.decode(xhr.responseText);
29334 if(!response.success){
29336 this.fireEvent('exception', this, xhr);
29340 var file = this.renderPreview(response.data);
29342 this.files.push(file);
29346 this.fireEvent('afterupload', this, xhr);
29350 xhrOnError : function(xhr)
29352 Roo.log('xhr on error');
29354 var response = Roo.decode(xhr.responseText);
29361 process : function(file)
29363 if(this.fireEvent('process', this, file) !== false){
29364 if(this.editable && file.type.indexOf('image') != -1){
29365 this.fireEvent('edit', this, file);
29369 this.uploadStart(file, false);
29376 uploadStart : function(file, crop)
29378 this.xhr = new XMLHttpRequest();
29380 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29385 file.xhr = this.xhr;
29387 this.managerEl.createChild({
29389 cls : 'roo-document-manager-loading',
29393 tooltip : file.name,
29394 cls : 'roo-document-manager-thumb',
29395 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29401 this.xhr.open(this.method, this.url, true);
29404 "Accept": "application/json",
29405 "Cache-Control": "no-cache",
29406 "X-Requested-With": "XMLHttpRequest"
29409 for (var headerName in headers) {
29410 var headerValue = headers[headerName];
29412 this.xhr.setRequestHeader(headerName, headerValue);
29418 this.xhr.onload = function()
29420 _this.xhrOnLoad(_this.xhr);
29423 this.xhr.onerror = function()
29425 _this.xhrOnError(_this.xhr);
29428 var formData = new FormData();
29430 formData.append('returnHTML', 'NO');
29433 formData.append('crop', crop);
29436 formData.append(this.paramName, file, file.name);
29443 if(this.fireEvent('prepare', this, formData, options) != false){
29445 if(options.manually){
29449 this.xhr.send(formData);
29453 this.uploadCancel();
29456 uploadCancel : function()
29462 this.delegates = [];
29464 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29471 renderPreview : function(file)
29473 if(typeof(file.target) != 'undefined' && file.target){
29477 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29479 var previewEl = this.managerEl.createChild({
29481 cls : 'roo-document-manager-preview',
29485 tooltip : file[this.toolTipName],
29486 cls : 'roo-document-manager-thumb',
29487 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29492 html : '<i class="fa fa-times-circle"></i>'
29497 var close = previewEl.select('button.close', true).first();
29499 close.on('click', this.onRemove, this, file);
29501 file.target = previewEl;
29503 var image = previewEl.select('img', true).first();
29507 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29509 image.on('click', this.onClick, this, file);
29511 this.fireEvent('previewrendered', this, file);
29517 onPreviewLoad : function(file, image)
29519 if(typeof(file.target) == 'undefined' || !file.target){
29523 var width = image.dom.naturalWidth || image.dom.width;
29524 var height = image.dom.naturalHeight || image.dom.height;
29526 if(!this.previewResize) {
29530 if(width > height){
29531 file.target.addClass('wide');
29535 file.target.addClass('tall');
29540 uploadFromSource : function(file, crop)
29542 this.xhr = new XMLHttpRequest();
29544 this.managerEl.createChild({
29546 cls : 'roo-document-manager-loading',
29550 tooltip : file.name,
29551 cls : 'roo-document-manager-thumb',
29552 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29558 this.xhr.open(this.method, this.url, true);
29561 "Accept": "application/json",
29562 "Cache-Control": "no-cache",
29563 "X-Requested-With": "XMLHttpRequest"
29566 for (var headerName in headers) {
29567 var headerValue = headers[headerName];
29569 this.xhr.setRequestHeader(headerName, headerValue);
29575 this.xhr.onload = function()
29577 _this.xhrOnLoad(_this.xhr);
29580 this.xhr.onerror = function()
29582 _this.xhrOnError(_this.xhr);
29585 var formData = new FormData();
29587 formData.append('returnHTML', 'NO');
29589 formData.append('crop', crop);
29591 if(typeof(file.filename) != 'undefined'){
29592 formData.append('filename', file.filename);
29595 if(typeof(file.mimetype) != 'undefined'){
29596 formData.append('mimetype', file.mimetype);
29601 if(this.fireEvent('prepare', this, formData) != false){
29602 this.xhr.send(formData);
29612 * @class Roo.bootstrap.DocumentViewer
29613 * @extends Roo.bootstrap.Component
29614 * Bootstrap DocumentViewer class
29615 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29616 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29619 * Create a new DocumentViewer
29620 * @param {Object} config The config object
29623 Roo.bootstrap.DocumentViewer = function(config){
29624 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29629 * Fire after initEvent
29630 * @param {Roo.bootstrap.DocumentViewer} this
29636 * @param {Roo.bootstrap.DocumentViewer} this
29641 * Fire after download button
29642 * @param {Roo.bootstrap.DocumentViewer} this
29647 * Fire after trash button
29648 * @param {Roo.bootstrap.DocumentViewer} this
29655 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29657 showDownload : true,
29661 getAutoCreate : function()
29665 cls : 'roo-document-viewer',
29669 cls : 'roo-document-viewer-body',
29673 cls : 'roo-document-viewer-thumb',
29677 cls : 'roo-document-viewer-image'
29685 cls : 'roo-document-viewer-footer',
29688 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29692 cls : 'btn-group roo-document-viewer-download',
29696 cls : 'btn btn-default',
29697 html : '<i class="fa fa-download"></i>'
29703 cls : 'btn-group roo-document-viewer-trash',
29707 cls : 'btn btn-default',
29708 html : '<i class="fa fa-trash"></i>'
29721 initEvents : function()
29723 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29724 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29726 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29727 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29729 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29730 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29732 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29733 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29735 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29736 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29738 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29739 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29741 this.bodyEl.on('click', this.onClick, this);
29742 this.downloadBtn.on('click', this.onDownload, this);
29743 this.trashBtn.on('click', this.onTrash, this);
29745 this.downloadBtn.hide();
29746 this.trashBtn.hide();
29748 if(this.showDownload){
29749 this.downloadBtn.show();
29752 if(this.showTrash){
29753 this.trashBtn.show();
29756 if(!this.showDownload && !this.showTrash) {
29757 this.footerEl.hide();
29762 initial : function()
29764 this.fireEvent('initial', this);
29768 onClick : function(e)
29770 e.preventDefault();
29772 this.fireEvent('click', this);
29775 onDownload : function(e)
29777 e.preventDefault();
29779 this.fireEvent('download', this);
29782 onTrash : function(e)
29784 e.preventDefault();
29786 this.fireEvent('trash', this);
29798 * @class Roo.bootstrap.NavProgressBar
29799 * @extends Roo.bootstrap.Component
29800 * Bootstrap NavProgressBar class
29803 * Create a new nav progress bar
29804 * @param {Object} config The config object
29807 Roo.bootstrap.NavProgressBar = function(config){
29808 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29810 this.bullets = this.bullets || [];
29812 // Roo.bootstrap.NavProgressBar.register(this);
29816 * Fires when the active item changes
29817 * @param {Roo.bootstrap.NavProgressBar} this
29818 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29819 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29826 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29831 getAutoCreate : function()
29833 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29837 cls : 'roo-navigation-bar-group',
29841 cls : 'roo-navigation-top-bar'
29845 cls : 'roo-navigation-bullets-bar',
29849 cls : 'roo-navigation-bar'
29856 cls : 'roo-navigation-bottom-bar'
29866 initEvents: function()
29871 onRender : function(ct, position)
29873 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29875 if(this.bullets.length){
29876 Roo.each(this.bullets, function(b){
29885 addItem : function(cfg)
29887 var item = new Roo.bootstrap.NavProgressItem(cfg);
29889 item.parentId = this.id;
29890 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29893 var top = new Roo.bootstrap.Element({
29895 cls : 'roo-navigation-bar-text'
29898 var bottom = new Roo.bootstrap.Element({
29900 cls : 'roo-navigation-bar-text'
29903 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29904 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29906 var topText = new Roo.bootstrap.Element({
29908 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29911 var bottomText = new Roo.bootstrap.Element({
29913 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29916 topText.onRender(top.el, null);
29917 bottomText.onRender(bottom.el, null);
29920 item.bottomEl = bottom;
29923 this.barItems.push(item);
29928 getActive : function()
29930 var active = false;
29932 Roo.each(this.barItems, function(v){
29934 if (!v.isActive()) {
29946 setActiveItem : function(item)
29950 Roo.each(this.barItems, function(v){
29951 if (v.rid == item.rid) {
29955 if (v.isActive()) {
29956 v.setActive(false);
29961 item.setActive(true);
29963 this.fireEvent('changed', this, item, prev);
29966 getBarItem: function(rid)
29970 Roo.each(this.barItems, function(e) {
29971 if (e.rid != rid) {
29982 indexOfItem : function(item)
29986 Roo.each(this.barItems, function(v, i){
29988 if (v.rid != item.rid) {
29999 setActiveNext : function()
30001 var i = this.indexOfItem(this.getActive());
30003 if (i > this.barItems.length) {
30007 this.setActiveItem(this.barItems[i+1]);
30010 setActivePrev : function()
30012 var i = this.indexOfItem(this.getActive());
30018 this.setActiveItem(this.barItems[i-1]);
30021 format : function()
30023 if(!this.barItems.length){
30027 var width = 100 / this.barItems.length;
30029 Roo.each(this.barItems, function(i){
30030 i.el.setStyle('width', width + '%');
30031 i.topEl.el.setStyle('width', width + '%');
30032 i.bottomEl.el.setStyle('width', width + '%');
30041 * Nav Progress Item
30046 * @class Roo.bootstrap.NavProgressItem
30047 * @extends Roo.bootstrap.Component
30048 * Bootstrap NavProgressItem class
30049 * @cfg {String} rid the reference id
30050 * @cfg {Boolean} active (true|false) Is item active default false
30051 * @cfg {Boolean} disabled (true|false) Is item active default false
30052 * @cfg {String} html
30053 * @cfg {String} position (top|bottom) text position default bottom
30054 * @cfg {String} icon show icon instead of number
30057 * Create a new NavProgressItem
30058 * @param {Object} config The config object
30060 Roo.bootstrap.NavProgressItem = function(config){
30061 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30066 * The raw click event for the entire grid.
30067 * @param {Roo.bootstrap.NavProgressItem} this
30068 * @param {Roo.EventObject} e
30075 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30081 position : 'bottom',
30084 getAutoCreate : function()
30086 var iconCls = 'roo-navigation-bar-item-icon';
30088 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30092 cls: 'roo-navigation-bar-item',
30102 cfg.cls += ' active';
30105 cfg.cls += ' disabled';
30111 disable : function()
30113 this.setDisabled(true);
30116 enable : function()
30118 this.setDisabled(false);
30121 initEvents: function()
30123 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30125 this.iconEl.on('click', this.onClick, this);
30128 onClick : function(e)
30130 e.preventDefault();
30136 if(this.fireEvent('click', this, e) === false){
30140 this.parent().setActiveItem(this);
30143 isActive: function ()
30145 return this.active;
30148 setActive : function(state)
30150 if(this.active == state){
30154 this.active = state;
30157 this.el.addClass('active');
30161 this.el.removeClass('active');
30166 setDisabled : function(state)
30168 if(this.disabled == state){
30172 this.disabled = state;
30175 this.el.addClass('disabled');
30179 this.el.removeClass('disabled');
30182 tooltipEl : function()
30184 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30197 * @class Roo.bootstrap.FieldLabel
30198 * @extends Roo.bootstrap.Component
30199 * Bootstrap FieldLabel class
30200 * @cfg {String} html contents of the element
30201 * @cfg {String} tag tag of the element default label
30202 * @cfg {String} cls class of the element
30203 * @cfg {String} target label target
30204 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30205 * @cfg {String} invalidClass default "text-warning"
30206 * @cfg {String} validClass default "text-success"
30207 * @cfg {String} iconTooltip default "This field is required"
30208 * @cfg {String} indicatorpos (left|right) default left
30211 * Create a new FieldLabel
30212 * @param {Object} config The config object
30215 Roo.bootstrap.FieldLabel = function(config){
30216 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30221 * Fires after the field has been marked as invalid.
30222 * @param {Roo.form.FieldLabel} this
30223 * @param {String} msg The validation message
30228 * Fires after the field has been validated with no errors.
30229 * @param {Roo.form.FieldLabel} this
30235 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30242 invalidClass : 'has-warning',
30243 validClass : 'has-success',
30244 iconTooltip : 'This field is required',
30245 indicatorpos : 'left',
30247 getAutoCreate : function(){
30250 if (!this.allowBlank) {
30256 cls : 'roo-bootstrap-field-label ' + this.cls,
30261 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30262 tooltip : this.iconTooltip
30271 if(this.indicatorpos == 'right'){
30274 cls : 'roo-bootstrap-field-label ' + this.cls,
30283 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30284 tooltip : this.iconTooltip
30293 initEvents: function()
30295 Roo.bootstrap.Element.superclass.initEvents.call(this);
30297 this.indicator = this.indicatorEl();
30299 if(this.indicator){
30300 this.indicator.removeClass('visible');
30301 this.indicator.addClass('invisible');
30304 Roo.bootstrap.FieldLabel.register(this);
30307 indicatorEl : function()
30309 var indicator = this.el.select('i.roo-required-indicator',true).first();
30320 * Mark this field as valid
30322 markValid : function()
30324 if(this.indicator){
30325 this.indicator.removeClass('visible');
30326 this.indicator.addClass('invisible');
30329 this.el.removeClass(this.invalidClass);
30331 this.el.addClass(this.validClass);
30333 this.fireEvent('valid', this);
30337 * Mark this field as invalid
30338 * @param {String} msg The validation message
30340 markInvalid : function(msg)
30342 if(this.indicator){
30343 this.indicator.removeClass('invisible');
30344 this.indicator.addClass('visible');
30347 this.el.removeClass(this.validClass);
30349 this.el.addClass(this.invalidClass);
30351 this.fireEvent('invalid', this, msg);
30357 Roo.apply(Roo.bootstrap.FieldLabel, {
30362 * register a FieldLabel Group
30363 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30365 register : function(label)
30367 if(this.groups.hasOwnProperty(label.target)){
30371 this.groups[label.target] = label;
30375 * fetch a FieldLabel Group based on the target
30376 * @param {string} target
30377 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30379 get: function(target) {
30380 if (typeof(this.groups[target]) == 'undefined') {
30384 return this.groups[target] ;
30393 * page DateSplitField.
30399 * @class Roo.bootstrap.DateSplitField
30400 * @extends Roo.bootstrap.Component
30401 * Bootstrap DateSplitField class
30402 * @cfg {string} fieldLabel - the label associated
30403 * @cfg {Number} labelWidth set the width of label (0-12)
30404 * @cfg {String} labelAlign (top|left)
30405 * @cfg {Boolean} dayAllowBlank (true|false) default false
30406 * @cfg {Boolean} monthAllowBlank (true|false) default false
30407 * @cfg {Boolean} yearAllowBlank (true|false) default false
30408 * @cfg {string} dayPlaceholder
30409 * @cfg {string} monthPlaceholder
30410 * @cfg {string} yearPlaceholder
30411 * @cfg {string} dayFormat default 'd'
30412 * @cfg {string} monthFormat default 'm'
30413 * @cfg {string} yearFormat default 'Y'
30414 * @cfg {Number} labellg set the width of label (1-12)
30415 * @cfg {Number} labelmd set the width of label (1-12)
30416 * @cfg {Number} labelsm set the width of label (1-12)
30417 * @cfg {Number} labelxs set the width of label (1-12)
30421 * Create a new DateSplitField
30422 * @param {Object} config The config object
30425 Roo.bootstrap.DateSplitField = function(config){
30426 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30432 * getting the data of years
30433 * @param {Roo.bootstrap.DateSplitField} this
30434 * @param {Object} years
30439 * getting the data of days
30440 * @param {Roo.bootstrap.DateSplitField} this
30441 * @param {Object} days
30446 * Fires after the field has been marked as invalid.
30447 * @param {Roo.form.Field} this
30448 * @param {String} msg The validation message
30453 * Fires after the field has been validated with no errors.
30454 * @param {Roo.form.Field} this
30460 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30463 labelAlign : 'top',
30465 dayAllowBlank : false,
30466 monthAllowBlank : false,
30467 yearAllowBlank : false,
30468 dayPlaceholder : '',
30469 monthPlaceholder : '',
30470 yearPlaceholder : '',
30474 isFormField : true,
30480 getAutoCreate : function()
30484 cls : 'row roo-date-split-field-group',
30489 cls : 'form-hidden-field roo-date-split-field-group-value',
30495 var labelCls = 'col-md-12';
30496 var contentCls = 'col-md-4';
30498 if(this.fieldLabel){
30502 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30506 html : this.fieldLabel
30511 if(this.labelAlign == 'left'){
30513 if(this.labelWidth > 12){
30514 label.style = "width: " + this.labelWidth + 'px';
30517 if(this.labelWidth < 13 && this.labelmd == 0){
30518 this.labelmd = this.labelWidth;
30521 if(this.labellg > 0){
30522 labelCls = ' col-lg-' + this.labellg;
30523 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30526 if(this.labelmd > 0){
30527 labelCls = ' col-md-' + this.labelmd;
30528 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30531 if(this.labelsm > 0){
30532 labelCls = ' col-sm-' + this.labelsm;
30533 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30536 if(this.labelxs > 0){
30537 labelCls = ' col-xs-' + this.labelxs;
30538 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30542 label.cls += ' ' + labelCls;
30544 cfg.cn.push(label);
30547 Roo.each(['day', 'month', 'year'], function(t){
30550 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30557 inputEl: function ()
30559 return this.el.select('.roo-date-split-field-group-value', true).first();
30562 onRender : function(ct, position)
30566 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30568 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30570 this.dayField = new Roo.bootstrap.ComboBox({
30571 allowBlank : this.dayAllowBlank,
30572 alwaysQuery : true,
30573 displayField : 'value',
30576 forceSelection : true,
30578 placeholder : this.dayPlaceholder,
30579 selectOnFocus : true,
30580 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30581 triggerAction : 'all',
30583 valueField : 'value',
30584 store : new Roo.data.SimpleStore({
30585 data : (function() {
30587 _this.fireEvent('days', _this, days);
30590 fields : [ 'value' ]
30593 select : function (_self, record, index)
30595 _this.setValue(_this.getValue());
30600 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30602 this.monthField = new Roo.bootstrap.MonthField({
30603 after : '<i class=\"fa fa-calendar\"></i>',
30604 allowBlank : this.monthAllowBlank,
30605 placeholder : this.monthPlaceholder,
30608 render : function (_self)
30610 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30611 e.preventDefault();
30615 select : function (_self, oldvalue, newvalue)
30617 _this.setValue(_this.getValue());
30622 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30624 this.yearField = new Roo.bootstrap.ComboBox({
30625 allowBlank : this.yearAllowBlank,
30626 alwaysQuery : true,
30627 displayField : 'value',
30630 forceSelection : true,
30632 placeholder : this.yearPlaceholder,
30633 selectOnFocus : true,
30634 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30635 triggerAction : 'all',
30637 valueField : 'value',
30638 store : new Roo.data.SimpleStore({
30639 data : (function() {
30641 _this.fireEvent('years', _this, years);
30644 fields : [ 'value' ]
30647 select : function (_self, record, index)
30649 _this.setValue(_this.getValue());
30654 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30657 setValue : function(v, format)
30659 this.inputEl.dom.value = v;
30661 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30663 var d = Date.parseDate(v, f);
30670 this.setDay(d.format(this.dayFormat));
30671 this.setMonth(d.format(this.monthFormat));
30672 this.setYear(d.format(this.yearFormat));
30679 setDay : function(v)
30681 this.dayField.setValue(v);
30682 this.inputEl.dom.value = this.getValue();
30687 setMonth : function(v)
30689 this.monthField.setValue(v, true);
30690 this.inputEl.dom.value = this.getValue();
30695 setYear : function(v)
30697 this.yearField.setValue(v);
30698 this.inputEl.dom.value = this.getValue();
30703 getDay : function()
30705 return this.dayField.getValue();
30708 getMonth : function()
30710 return this.monthField.getValue();
30713 getYear : function()
30715 return this.yearField.getValue();
30718 getValue : function()
30720 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30722 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30732 this.inputEl.dom.value = '';
30737 validate : function()
30739 var d = this.dayField.validate();
30740 var m = this.monthField.validate();
30741 var y = this.yearField.validate();
30746 (!this.dayAllowBlank && !d) ||
30747 (!this.monthAllowBlank && !m) ||
30748 (!this.yearAllowBlank && !y)
30753 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30762 this.markInvalid();
30767 markValid : function()
30770 var label = this.el.select('label', true).first();
30771 var icon = this.el.select('i.fa-star', true).first();
30777 this.fireEvent('valid', this);
30781 * Mark this field as invalid
30782 * @param {String} msg The validation message
30784 markInvalid : function(msg)
30787 var label = this.el.select('label', true).first();
30788 var icon = this.el.select('i.fa-star', true).first();
30790 if(label && !icon){
30791 this.el.select('.roo-date-split-field-label', true).createChild({
30793 cls : 'text-danger fa fa-lg fa-star',
30794 tooltip : 'This field is required',
30795 style : 'margin-right:5px;'
30799 this.fireEvent('invalid', this, msg);
30802 clearInvalid : function()
30804 var label = this.el.select('label', true).first();
30805 var icon = this.el.select('i.fa-star', true).first();
30811 this.fireEvent('valid', this);
30814 getName: function()
30824 * http://masonry.desandro.com
30826 * The idea is to render all the bricks based on vertical width...
30828 * The original code extends 'outlayer' - we might need to use that....
30834 * @class Roo.bootstrap.LayoutMasonry
30835 * @extends Roo.bootstrap.Component
30836 * Bootstrap Layout Masonry class
30839 * Create a new Element
30840 * @param {Object} config The config object
30843 Roo.bootstrap.LayoutMasonry = function(config){
30845 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30849 Roo.bootstrap.LayoutMasonry.register(this);
30855 * Fire after layout the items
30856 * @param {Roo.bootstrap.LayoutMasonry} this
30857 * @param {Roo.EventObject} e
30864 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30867 * @cfg {Boolean} isLayoutInstant = no animation?
30869 isLayoutInstant : false, // needed?
30872 * @cfg {Number} boxWidth width of the columns
30877 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30882 * @cfg {Number} padWidth padding below box..
30887 * @cfg {Number} gutter gutter width..
30892 * @cfg {Number} maxCols maximum number of columns
30898 * @cfg {Boolean} isAutoInitial defalut true
30900 isAutoInitial : true,
30905 * @cfg {Boolean} isHorizontal defalut false
30907 isHorizontal : false,
30909 currentSize : null,
30915 bricks: null, //CompositeElement
30919 _isLayoutInited : false,
30921 // isAlternative : false, // only use for vertical layout...
30924 * @cfg {Number} alternativePadWidth padding below box..
30926 alternativePadWidth : 50,
30928 selectedBrick : [],
30930 getAutoCreate : function(){
30932 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30936 cls: 'blog-masonary-wrapper ' + this.cls,
30938 cls : 'mas-boxes masonary'
30945 getChildContainer: function( )
30947 if (this.boxesEl) {
30948 return this.boxesEl;
30951 this.boxesEl = this.el.select('.mas-boxes').first();
30953 return this.boxesEl;
30957 initEvents : function()
30961 if(this.isAutoInitial){
30962 Roo.log('hook children rendered');
30963 this.on('childrenrendered', function() {
30964 Roo.log('children rendered');
30970 initial : function()
30972 this.selectedBrick = [];
30974 this.currentSize = this.el.getBox(true);
30976 Roo.EventManager.onWindowResize(this.resize, this);
30978 if(!this.isAutoInitial){
30986 //this.layout.defer(500,this);
30990 resize : function()
30992 var cs = this.el.getBox(true);
30995 this.currentSize.width == cs.width &&
30996 this.currentSize.x == cs.x &&
30997 this.currentSize.height == cs.height &&
30998 this.currentSize.y == cs.y
31000 Roo.log("no change in with or X or Y");
31004 this.currentSize = cs;
31010 layout : function()
31012 this._resetLayout();
31014 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31016 this.layoutItems( isInstant );
31018 this._isLayoutInited = true;
31020 this.fireEvent('layout', this);
31024 _resetLayout : function()
31026 if(this.isHorizontal){
31027 this.horizontalMeasureColumns();
31031 this.verticalMeasureColumns();
31035 verticalMeasureColumns : function()
31037 this.getContainerWidth();
31039 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31040 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31044 var boxWidth = this.boxWidth + this.padWidth;
31046 if(this.containerWidth < this.boxWidth){
31047 boxWidth = this.containerWidth
31050 var containerWidth = this.containerWidth;
31052 var cols = Math.floor(containerWidth / boxWidth);
31054 this.cols = Math.max( cols, 1 );
31056 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31058 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31060 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31062 this.colWidth = boxWidth + avail - this.padWidth;
31064 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31065 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31068 horizontalMeasureColumns : function()
31070 this.getContainerWidth();
31072 var boxWidth = this.boxWidth;
31074 if(this.containerWidth < boxWidth){
31075 boxWidth = this.containerWidth;
31078 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31080 this.el.setHeight(boxWidth);
31084 getContainerWidth : function()
31086 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31089 layoutItems : function( isInstant )
31091 Roo.log(this.bricks);
31093 var items = Roo.apply([], this.bricks);
31095 if(this.isHorizontal){
31096 this._horizontalLayoutItems( items , isInstant );
31100 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31101 // this._verticalAlternativeLayoutItems( items , isInstant );
31105 this._verticalLayoutItems( items , isInstant );
31109 _verticalLayoutItems : function ( items , isInstant)
31111 if ( !items || !items.length ) {
31116 ['xs', 'xs', 'xs', 'tall'],
31117 ['xs', 'xs', 'tall'],
31118 ['xs', 'xs', 'sm'],
31119 ['xs', 'xs', 'xs'],
31125 ['sm', 'xs', 'xs'],
31129 ['tall', 'xs', 'xs', 'xs'],
31130 ['tall', 'xs', 'xs'],
31142 Roo.each(items, function(item, k){
31144 switch (item.size) {
31145 // these layouts take up a full box,
31156 boxes.push([item]);
31179 var filterPattern = function(box, length)
31187 var pattern = box.slice(0, length);
31191 Roo.each(pattern, function(i){
31192 format.push(i.size);
31195 Roo.each(standard, function(s){
31197 if(String(s) != String(format)){
31206 if(!match && length == 1){
31211 filterPattern(box, length - 1);
31215 queue.push(pattern);
31217 box = box.slice(length, box.length);
31219 filterPattern(box, 4);
31225 Roo.each(boxes, function(box, k){
31231 if(box.length == 1){
31236 filterPattern(box, 4);
31240 this._processVerticalLayoutQueue( queue, isInstant );
31244 // _verticalAlternativeLayoutItems : function( items , isInstant )
31246 // if ( !items || !items.length ) {
31250 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31254 _horizontalLayoutItems : function ( items , isInstant)
31256 if ( !items || !items.length || items.length < 3) {
31262 var eItems = items.slice(0, 3);
31264 items = items.slice(3, items.length);
31267 ['xs', 'xs', 'xs', 'wide'],
31268 ['xs', 'xs', 'wide'],
31269 ['xs', 'xs', 'sm'],
31270 ['xs', 'xs', 'xs'],
31276 ['sm', 'xs', 'xs'],
31280 ['wide', 'xs', 'xs', 'xs'],
31281 ['wide', 'xs', 'xs'],
31294 Roo.each(items, function(item, k){
31296 switch (item.size) {
31307 boxes.push([item]);
31331 var filterPattern = function(box, length)
31339 var pattern = box.slice(0, length);
31343 Roo.each(pattern, function(i){
31344 format.push(i.size);
31347 Roo.each(standard, function(s){
31349 if(String(s) != String(format)){
31358 if(!match && length == 1){
31363 filterPattern(box, length - 1);
31367 queue.push(pattern);
31369 box = box.slice(length, box.length);
31371 filterPattern(box, 4);
31377 Roo.each(boxes, function(box, k){
31383 if(box.length == 1){
31388 filterPattern(box, 4);
31395 var pos = this.el.getBox(true);
31399 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31401 var hit_end = false;
31403 Roo.each(queue, function(box){
31407 Roo.each(box, function(b){
31409 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31419 Roo.each(box, function(b){
31421 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31424 mx = Math.max(mx, b.x);
31428 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31432 Roo.each(box, function(b){
31434 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31448 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31451 /** Sets position of item in DOM
31452 * @param {Element} item
31453 * @param {Number} x - horizontal position
31454 * @param {Number} y - vertical position
31455 * @param {Boolean} isInstant - disables transitions
31457 _processVerticalLayoutQueue : function( queue, isInstant )
31459 var pos = this.el.getBox(true);
31464 for (var i = 0; i < this.cols; i++){
31468 Roo.each(queue, function(box, k){
31470 var col = k % this.cols;
31472 Roo.each(box, function(b,kk){
31474 b.el.position('absolute');
31476 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31477 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31479 if(b.size == 'md-left' || b.size == 'md-right'){
31480 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31481 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31484 b.el.setWidth(width);
31485 b.el.setHeight(height);
31487 b.el.select('iframe',true).setSize(width,height);
31491 for (var i = 0; i < this.cols; i++){
31493 if(maxY[i] < maxY[col]){
31498 col = Math.min(col, i);
31502 x = pos.x + col * (this.colWidth + this.padWidth);
31506 var positions = [];
31508 switch (box.length){
31510 positions = this.getVerticalOneBoxColPositions(x, y, box);
31513 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31516 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31519 positions = this.getVerticalFourBoxColPositions(x, y, box);
31525 Roo.each(box, function(b,kk){
31527 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31529 var sz = b.el.getSize();
31531 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31539 for (var i = 0; i < this.cols; i++){
31540 mY = Math.max(mY, maxY[i]);
31543 this.el.setHeight(mY - pos.y);
31547 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31549 // var pos = this.el.getBox(true);
31552 // var maxX = pos.right;
31554 // var maxHeight = 0;
31556 // Roo.each(items, function(item, k){
31560 // item.el.position('absolute');
31562 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31564 // item.el.setWidth(width);
31566 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31568 // item.el.setHeight(height);
31571 // item.el.setXY([x, y], isInstant ? false : true);
31573 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31576 // y = y + height + this.alternativePadWidth;
31578 // maxHeight = maxHeight + height + this.alternativePadWidth;
31582 // this.el.setHeight(maxHeight);
31586 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31588 var pos = this.el.getBox(true);
31593 var maxX = pos.right;
31595 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31597 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31599 Roo.each(queue, function(box, k){
31601 Roo.each(box, function(b, kk){
31603 b.el.position('absolute');
31605 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31606 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31608 if(b.size == 'md-left' || b.size == 'md-right'){
31609 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31610 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31613 b.el.setWidth(width);
31614 b.el.setHeight(height);
31622 var positions = [];
31624 switch (box.length){
31626 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31629 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31632 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31635 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31641 Roo.each(box, function(b,kk){
31643 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31645 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31653 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31655 Roo.each(eItems, function(b,k){
31657 b.size = (k == 0) ? 'sm' : 'xs';
31658 b.x = (k == 0) ? 2 : 1;
31659 b.y = (k == 0) ? 2 : 1;
31661 b.el.position('absolute');
31663 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31665 b.el.setWidth(width);
31667 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31669 b.el.setHeight(height);
31673 var positions = [];
31676 x : maxX - this.unitWidth * 2 - this.gutter,
31681 x : maxX - this.unitWidth,
31682 y : minY + (this.unitWidth + this.gutter) * 2
31686 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31690 Roo.each(eItems, function(b,k){
31692 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31698 getVerticalOneBoxColPositions : function(x, y, box)
31702 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31704 if(box[0].size == 'md-left'){
31708 if(box[0].size == 'md-right'){
31713 x : x + (this.unitWidth + this.gutter) * rand,
31720 getVerticalTwoBoxColPositions : function(x, y, box)
31724 if(box[0].size == 'xs'){
31728 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31732 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31746 x : x + (this.unitWidth + this.gutter) * 2,
31747 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31754 getVerticalThreeBoxColPositions : function(x, y, box)
31758 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31766 x : x + (this.unitWidth + this.gutter) * 1,
31771 x : x + (this.unitWidth + this.gutter) * 2,
31779 if(box[0].size == 'xs' && box[1].size == 'xs'){
31788 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31792 x : x + (this.unitWidth + this.gutter) * 1,
31806 x : x + (this.unitWidth + this.gutter) * 2,
31811 x : x + (this.unitWidth + this.gutter) * 2,
31812 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31819 getVerticalFourBoxColPositions : function(x, y, box)
31823 if(box[0].size == 'xs'){
31832 y : y + (this.unitHeight + this.gutter) * 1
31837 y : y + (this.unitHeight + this.gutter) * 2
31841 x : x + (this.unitWidth + this.gutter) * 1,
31855 x : x + (this.unitWidth + this.gutter) * 2,
31860 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31861 y : y + (this.unitHeight + this.gutter) * 1
31865 x : x + (this.unitWidth + this.gutter) * 2,
31866 y : y + (this.unitWidth + this.gutter) * 2
31873 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31877 if(box[0].size == 'md-left'){
31879 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31886 if(box[0].size == 'md-right'){
31888 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31889 y : minY + (this.unitWidth + this.gutter) * 1
31895 var rand = Math.floor(Math.random() * (4 - box[0].y));
31898 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31899 y : minY + (this.unitWidth + this.gutter) * rand
31906 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31910 if(box[0].size == 'xs'){
31913 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31918 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31919 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31927 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31932 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31933 y : minY + (this.unitWidth + this.gutter) * 2
31940 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31944 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31947 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31952 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31953 y : minY + (this.unitWidth + this.gutter) * 1
31957 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31958 y : minY + (this.unitWidth + this.gutter) * 2
31965 if(box[0].size == 'xs' && box[1].size == 'xs'){
31968 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31973 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31978 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31979 y : minY + (this.unitWidth + this.gutter) * 1
31987 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31992 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31993 y : minY + (this.unitWidth + this.gutter) * 2
31997 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31998 y : minY + (this.unitWidth + this.gutter) * 2
32005 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32009 if(box[0].size == 'xs'){
32012 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32017 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32022 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32027 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32028 y : minY + (this.unitWidth + this.gutter) * 1
32036 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32041 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32042 y : minY + (this.unitWidth + this.gutter) * 2
32046 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32047 y : minY + (this.unitWidth + this.gutter) * 2
32051 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32052 y : minY + (this.unitWidth + this.gutter) * 2
32060 * remove a Masonry Brick
32061 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32063 removeBrick : function(brick_id)
32069 for (var i = 0; i<this.bricks.length; i++) {
32070 if (this.bricks[i].id == brick_id) {
32071 this.bricks.splice(i,1);
32072 this.el.dom.removeChild(Roo.get(brick_id).dom);
32079 * adds a Masonry Brick
32080 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32082 addBrick : function(cfg)
32084 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32085 //this.register(cn);
32086 cn.parentId = this.id;
32087 cn.render(this.el);
32092 * register a Masonry Brick
32093 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32096 register : function(brick)
32098 this.bricks.push(brick);
32099 brick.masonryId = this.id;
32103 * clear all the Masonry Brick
32105 clearAll : function()
32108 //this.getChildContainer().dom.innerHTML = "";
32109 this.el.dom.innerHTML = '';
32112 getSelected : function()
32114 if (!this.selectedBrick) {
32118 return this.selectedBrick;
32122 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32126 * register a Masonry Layout
32127 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32130 register : function(layout)
32132 this.groups[layout.id] = layout;
32135 * fetch a Masonry Layout based on the masonry layout ID
32136 * @param {string} the masonry layout to add
32137 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32140 get: function(layout_id) {
32141 if (typeof(this.groups[layout_id]) == 'undefined') {
32144 return this.groups[layout_id] ;
32156 * http://masonry.desandro.com
32158 * The idea is to render all the bricks based on vertical width...
32160 * The original code extends 'outlayer' - we might need to use that....
32166 * @class Roo.bootstrap.LayoutMasonryAuto
32167 * @extends Roo.bootstrap.Component
32168 * Bootstrap Layout Masonry class
32171 * Create a new Element
32172 * @param {Object} config The config object
32175 Roo.bootstrap.LayoutMasonryAuto = function(config){
32176 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32179 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32182 * @cfg {Boolean} isFitWidth - resize the width..
32184 isFitWidth : false, // options..
32186 * @cfg {Boolean} isOriginLeft = left align?
32188 isOriginLeft : true,
32190 * @cfg {Boolean} isOriginTop = top align?
32192 isOriginTop : false,
32194 * @cfg {Boolean} isLayoutInstant = no animation?
32196 isLayoutInstant : false, // needed?
32198 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32200 isResizingContainer : true,
32202 * @cfg {Number} columnWidth width of the columns
32208 * @cfg {Number} maxCols maximum number of columns
32213 * @cfg {Number} padHeight padding below box..
32219 * @cfg {Boolean} isAutoInitial defalut true
32222 isAutoInitial : true,
32228 initialColumnWidth : 0,
32229 currentSize : null,
32231 colYs : null, // array.
32238 bricks: null, //CompositeElement
32239 cols : 0, // array?
32240 // element : null, // wrapped now this.el
32241 _isLayoutInited : null,
32244 getAutoCreate : function(){
32248 cls: 'blog-masonary-wrapper ' + this.cls,
32250 cls : 'mas-boxes masonary'
32257 getChildContainer: function( )
32259 if (this.boxesEl) {
32260 return this.boxesEl;
32263 this.boxesEl = this.el.select('.mas-boxes').first();
32265 return this.boxesEl;
32269 initEvents : function()
32273 if(this.isAutoInitial){
32274 Roo.log('hook children rendered');
32275 this.on('childrenrendered', function() {
32276 Roo.log('children rendered');
32283 initial : function()
32285 this.reloadItems();
32287 this.currentSize = this.el.getBox(true);
32289 /// was window resize... - let's see if this works..
32290 Roo.EventManager.onWindowResize(this.resize, this);
32292 if(!this.isAutoInitial){
32297 this.layout.defer(500,this);
32300 reloadItems: function()
32302 this.bricks = this.el.select('.masonry-brick', true);
32304 this.bricks.each(function(b) {
32305 //Roo.log(b.getSize());
32306 if (!b.attr('originalwidth')) {
32307 b.attr('originalwidth', b.getSize().width);
32312 Roo.log(this.bricks.elements.length);
32315 resize : function()
32318 var cs = this.el.getBox(true);
32320 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32321 Roo.log("no change in with or X");
32324 this.currentSize = cs;
32328 layout : function()
32331 this._resetLayout();
32332 //this._manageStamps();
32334 // don't animate first layout
32335 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32336 this.layoutItems( isInstant );
32338 // flag for initalized
32339 this._isLayoutInited = true;
32342 layoutItems : function( isInstant )
32344 //var items = this._getItemsForLayout( this.items );
32345 // original code supports filtering layout items.. we just ignore it..
32347 this._layoutItems( this.bricks , isInstant );
32349 this._postLayout();
32351 _layoutItems : function ( items , isInstant)
32353 //this.fireEvent( 'layout', this, items );
32356 if ( !items || !items.elements.length ) {
32357 // no items, emit event with empty array
32362 items.each(function(item) {
32363 Roo.log("layout item");
32365 // get x/y object from method
32366 var position = this._getItemLayoutPosition( item );
32368 position.item = item;
32369 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32370 queue.push( position );
32373 this._processLayoutQueue( queue );
32375 /** Sets position of item in DOM
32376 * @param {Element} item
32377 * @param {Number} x - horizontal position
32378 * @param {Number} y - vertical position
32379 * @param {Boolean} isInstant - disables transitions
32381 _processLayoutQueue : function( queue )
32383 for ( var i=0, len = queue.length; i < len; i++ ) {
32384 var obj = queue[i];
32385 obj.item.position('absolute');
32386 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32392 * Any logic you want to do after each layout,
32393 * i.e. size the container
32395 _postLayout : function()
32397 this.resizeContainer();
32400 resizeContainer : function()
32402 if ( !this.isResizingContainer ) {
32405 var size = this._getContainerSize();
32407 this.el.setSize(size.width,size.height);
32408 this.boxesEl.setSize(size.width,size.height);
32414 _resetLayout : function()
32416 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32417 this.colWidth = this.el.getWidth();
32418 //this.gutter = this.el.getWidth();
32420 this.measureColumns();
32426 this.colYs.push( 0 );
32432 measureColumns : function()
32434 this.getContainerWidth();
32435 // if columnWidth is 0, default to outerWidth of first item
32436 if ( !this.columnWidth ) {
32437 var firstItem = this.bricks.first();
32438 Roo.log(firstItem);
32439 this.columnWidth = this.containerWidth;
32440 if (firstItem && firstItem.attr('originalwidth') ) {
32441 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32443 // columnWidth fall back to item of first element
32444 Roo.log("set column width?");
32445 this.initialColumnWidth = this.columnWidth ;
32447 // if first elem has no width, default to size of container
32452 if (this.initialColumnWidth) {
32453 this.columnWidth = this.initialColumnWidth;
32458 // column width is fixed at the top - however if container width get's smaller we should
32461 // this bit calcs how man columns..
32463 var columnWidth = this.columnWidth += this.gutter;
32465 // calculate columns
32466 var containerWidth = this.containerWidth + this.gutter;
32468 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32469 // fix rounding errors, typically with gutters
32470 var excess = columnWidth - containerWidth % columnWidth;
32473 // if overshoot is less than a pixel, round up, otherwise floor it
32474 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32475 cols = Math[ mathMethod ]( cols );
32476 this.cols = Math.max( cols, 1 );
32477 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32479 // padding positioning..
32480 var totalColWidth = this.cols * this.columnWidth;
32481 var padavail = this.containerWidth - totalColWidth;
32482 // so for 2 columns - we need 3 'pads'
32484 var padNeeded = (1+this.cols) * this.padWidth;
32486 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32488 this.columnWidth += padExtra
32489 //this.padWidth = Math.floor(padavail / ( this.cols));
32491 // adjust colum width so that padding is fixed??
32493 // we have 3 columns ... total = width * 3
32494 // we have X left over... that should be used by
32496 //if (this.expandC) {
32504 getContainerWidth : function()
32506 /* // container is parent if fit width
32507 var container = this.isFitWidth ? this.element.parentNode : this.element;
32508 // check that this.size and size are there
32509 // IE8 triggers resize on body size change, so they might not be
32511 var size = getSize( container ); //FIXME
32512 this.containerWidth = size && size.innerWidth; //FIXME
32515 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32519 _getItemLayoutPosition : function( item ) // what is item?
32521 // we resize the item to our columnWidth..
32523 item.setWidth(this.columnWidth);
32524 item.autoBoxAdjust = false;
32526 var sz = item.getSize();
32528 // how many columns does this brick span
32529 var remainder = this.containerWidth % this.columnWidth;
32531 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32532 // round if off by 1 pixel, otherwise use ceil
32533 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32534 colSpan = Math.min( colSpan, this.cols );
32536 // normally this should be '1' as we dont' currently allow multi width columns..
32538 var colGroup = this._getColGroup( colSpan );
32539 // get the minimum Y value from the columns
32540 var minimumY = Math.min.apply( Math, colGroup );
32541 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32543 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32545 // position the brick
32547 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32548 y: this.currentSize.y + minimumY + this.padHeight
32552 // apply setHeight to necessary columns
32553 var setHeight = minimumY + sz.height + this.padHeight;
32554 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32556 var setSpan = this.cols + 1 - colGroup.length;
32557 for ( var i = 0; i < setSpan; i++ ) {
32558 this.colYs[ shortColIndex + i ] = setHeight ;
32565 * @param {Number} colSpan - number of columns the element spans
32566 * @returns {Array} colGroup
32568 _getColGroup : function( colSpan )
32570 if ( colSpan < 2 ) {
32571 // if brick spans only one column, use all the column Ys
32576 // how many different places could this brick fit horizontally
32577 var groupCount = this.cols + 1 - colSpan;
32578 // for each group potential horizontal position
32579 for ( var i = 0; i < groupCount; i++ ) {
32580 // make an array of colY values for that one group
32581 var groupColYs = this.colYs.slice( i, i + colSpan );
32582 // and get the max value of the array
32583 colGroup[i] = Math.max.apply( Math, groupColYs );
32588 _manageStamp : function( stamp )
32590 var stampSize = stamp.getSize();
32591 var offset = stamp.getBox();
32592 // get the columns that this stamp affects
32593 var firstX = this.isOriginLeft ? offset.x : offset.right;
32594 var lastX = firstX + stampSize.width;
32595 var firstCol = Math.floor( firstX / this.columnWidth );
32596 firstCol = Math.max( 0, firstCol );
32598 var lastCol = Math.floor( lastX / this.columnWidth );
32599 // lastCol should not go over if multiple of columnWidth #425
32600 lastCol -= lastX % this.columnWidth ? 0 : 1;
32601 lastCol = Math.min( this.cols - 1, lastCol );
32603 // set colYs to bottom of the stamp
32604 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32607 for ( var i = firstCol; i <= lastCol; i++ ) {
32608 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32613 _getContainerSize : function()
32615 this.maxY = Math.max.apply( Math, this.colYs );
32620 if ( this.isFitWidth ) {
32621 size.width = this._getContainerFitWidth();
32627 _getContainerFitWidth : function()
32629 var unusedCols = 0;
32630 // count unused columns
32633 if ( this.colYs[i] !== 0 ) {
32638 // fit container to columns that have been used
32639 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32642 needsResizeLayout : function()
32644 var previousWidth = this.containerWidth;
32645 this.getContainerWidth();
32646 return previousWidth !== this.containerWidth;
32661 * @class Roo.bootstrap.MasonryBrick
32662 * @extends Roo.bootstrap.Component
32663 * Bootstrap MasonryBrick class
32666 * Create a new MasonryBrick
32667 * @param {Object} config The config object
32670 Roo.bootstrap.MasonryBrick = function(config){
32672 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32674 Roo.bootstrap.MasonryBrick.register(this);
32680 * When a MasonryBrick is clcik
32681 * @param {Roo.bootstrap.MasonryBrick} this
32682 * @param {Roo.EventObject} e
32688 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32691 * @cfg {String} title
32695 * @cfg {String} html
32699 * @cfg {String} bgimage
32703 * @cfg {String} videourl
32707 * @cfg {String} cls
32711 * @cfg {String} href
32715 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32720 * @cfg {String} placetitle (center|bottom)
32725 * @cfg {Boolean} isFitContainer defalut true
32727 isFitContainer : true,
32730 * @cfg {Boolean} preventDefault defalut false
32732 preventDefault : false,
32735 * @cfg {Boolean} inverse defalut false
32737 maskInverse : false,
32739 getAutoCreate : function()
32741 if(!this.isFitContainer){
32742 return this.getSplitAutoCreate();
32745 var cls = 'masonry-brick masonry-brick-full';
32747 if(this.href.length){
32748 cls += ' masonry-brick-link';
32751 if(this.bgimage.length){
32752 cls += ' masonry-brick-image';
32755 if(this.maskInverse){
32756 cls += ' mask-inverse';
32759 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32760 cls += ' enable-mask';
32764 cls += ' masonry-' + this.size + '-brick';
32767 if(this.placetitle.length){
32769 switch (this.placetitle) {
32771 cls += ' masonry-center-title';
32774 cls += ' masonry-bottom-title';
32781 if(!this.html.length && !this.bgimage.length){
32782 cls += ' masonry-center-title';
32785 if(!this.html.length && this.bgimage.length){
32786 cls += ' masonry-bottom-title';
32791 cls += ' ' + this.cls;
32795 tag: (this.href.length) ? 'a' : 'div',
32800 cls: 'masonry-brick-mask'
32804 cls: 'masonry-brick-paragraph',
32810 if(this.href.length){
32811 cfg.href = this.href;
32814 var cn = cfg.cn[1].cn;
32816 if(this.title.length){
32819 cls: 'masonry-brick-title',
32824 if(this.html.length){
32827 cls: 'masonry-brick-text',
32832 if (!this.title.length && !this.html.length) {
32833 cfg.cn[1].cls += ' hide';
32836 if(this.bgimage.length){
32839 cls: 'masonry-brick-image-view',
32844 if(this.videourl.length){
32845 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32846 // youtube support only?
32849 cls: 'masonry-brick-image-view',
32852 allowfullscreen : true
32860 getSplitAutoCreate : function()
32862 var cls = 'masonry-brick masonry-brick-split';
32864 if(this.href.length){
32865 cls += ' masonry-brick-link';
32868 if(this.bgimage.length){
32869 cls += ' masonry-brick-image';
32873 cls += ' masonry-' + this.size + '-brick';
32876 switch (this.placetitle) {
32878 cls += ' masonry-center-title';
32881 cls += ' masonry-bottom-title';
32884 if(!this.bgimage.length){
32885 cls += ' masonry-center-title';
32888 if(this.bgimage.length){
32889 cls += ' masonry-bottom-title';
32895 cls += ' ' + this.cls;
32899 tag: (this.href.length) ? 'a' : 'div',
32904 cls: 'masonry-brick-split-head',
32908 cls: 'masonry-brick-paragraph',
32915 cls: 'masonry-brick-split-body',
32921 if(this.href.length){
32922 cfg.href = this.href;
32925 if(this.title.length){
32926 cfg.cn[0].cn[0].cn.push({
32928 cls: 'masonry-brick-title',
32933 if(this.html.length){
32934 cfg.cn[1].cn.push({
32936 cls: 'masonry-brick-text',
32941 if(this.bgimage.length){
32942 cfg.cn[0].cn.push({
32944 cls: 'masonry-brick-image-view',
32949 if(this.videourl.length){
32950 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32951 // youtube support only?
32952 cfg.cn[0].cn.cn.push({
32954 cls: 'masonry-brick-image-view',
32957 allowfullscreen : true
32964 initEvents: function()
32966 switch (this.size) {
32999 this.el.on('touchstart', this.onTouchStart, this);
33000 this.el.on('touchmove', this.onTouchMove, this);
33001 this.el.on('touchend', this.onTouchEnd, this);
33002 this.el.on('contextmenu', this.onContextMenu, this);
33004 this.el.on('mouseenter' ,this.enter, this);
33005 this.el.on('mouseleave', this.leave, this);
33006 this.el.on('click', this.onClick, this);
33009 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33010 this.parent().bricks.push(this);
33015 onClick: function(e, el)
33017 var time = this.endTimer - this.startTimer;
33018 // Roo.log(e.preventDefault());
33021 e.preventDefault();
33026 if(!this.preventDefault){
33030 e.preventDefault();
33032 if (this.activeClass != '') {
33033 this.selectBrick();
33036 this.fireEvent('click', this, e);
33039 enter: function(e, el)
33041 e.preventDefault();
33043 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33047 if(this.bgimage.length && this.html.length){
33048 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33052 leave: function(e, el)
33054 e.preventDefault();
33056 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33060 if(this.bgimage.length && this.html.length){
33061 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33065 onTouchStart: function(e, el)
33067 // e.preventDefault();
33069 this.touchmoved = false;
33071 if(!this.isFitContainer){
33075 if(!this.bgimage.length || !this.html.length){
33079 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33081 this.timer = new Date().getTime();
33085 onTouchMove: function(e, el)
33087 this.touchmoved = true;
33090 onContextMenu : function(e,el)
33092 e.preventDefault();
33093 e.stopPropagation();
33097 onTouchEnd: function(e, el)
33099 // e.preventDefault();
33101 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33108 if(!this.bgimage.length || !this.html.length){
33110 if(this.href.length){
33111 window.location.href = this.href;
33117 if(!this.isFitContainer){
33121 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33123 window.location.href = this.href;
33126 //selection on single brick only
33127 selectBrick : function() {
33129 if (!this.parentId) {
33133 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33134 var index = m.selectedBrick.indexOf(this.id);
33137 m.selectedBrick.splice(index,1);
33138 this.el.removeClass(this.activeClass);
33142 for(var i = 0; i < m.selectedBrick.length; i++) {
33143 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33144 b.el.removeClass(b.activeClass);
33147 m.selectedBrick = [];
33149 m.selectedBrick.push(this.id);
33150 this.el.addClass(this.activeClass);
33154 isSelected : function(){
33155 return this.el.hasClass(this.activeClass);
33160 Roo.apply(Roo.bootstrap.MasonryBrick, {
33163 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33165 * register a Masonry Brick
33166 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33169 register : function(brick)
33171 //this.groups[brick.id] = brick;
33172 this.groups.add(brick.id, brick);
33175 * fetch a masonry brick based on the masonry brick ID
33176 * @param {string} the masonry brick to add
33177 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33180 get: function(brick_id)
33182 // if (typeof(this.groups[brick_id]) == 'undefined') {
33185 // return this.groups[brick_id] ;
33187 if(this.groups.key(brick_id)) {
33188 return this.groups.key(brick_id);
33206 * @class Roo.bootstrap.Brick
33207 * @extends Roo.bootstrap.Component
33208 * Bootstrap Brick class
33211 * Create a new Brick
33212 * @param {Object} config The config object
33215 Roo.bootstrap.Brick = function(config){
33216 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33222 * When a Brick is click
33223 * @param {Roo.bootstrap.Brick} this
33224 * @param {Roo.EventObject} e
33230 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33233 * @cfg {String} title
33237 * @cfg {String} html
33241 * @cfg {String} bgimage
33245 * @cfg {String} cls
33249 * @cfg {String} href
33253 * @cfg {String} video
33257 * @cfg {Boolean} square
33261 getAutoCreate : function()
33263 var cls = 'roo-brick';
33265 if(this.href.length){
33266 cls += ' roo-brick-link';
33269 if(this.bgimage.length){
33270 cls += ' roo-brick-image';
33273 if(!this.html.length && !this.bgimage.length){
33274 cls += ' roo-brick-center-title';
33277 if(!this.html.length && this.bgimage.length){
33278 cls += ' roo-brick-bottom-title';
33282 cls += ' ' + this.cls;
33286 tag: (this.href.length) ? 'a' : 'div',
33291 cls: 'roo-brick-paragraph',
33297 if(this.href.length){
33298 cfg.href = this.href;
33301 var cn = cfg.cn[0].cn;
33303 if(this.title.length){
33306 cls: 'roo-brick-title',
33311 if(this.html.length){
33314 cls: 'roo-brick-text',
33321 if(this.bgimage.length){
33324 cls: 'roo-brick-image-view',
33332 initEvents: function()
33334 if(this.title.length || this.html.length){
33335 this.el.on('mouseenter' ,this.enter, this);
33336 this.el.on('mouseleave', this.leave, this);
33339 Roo.EventManager.onWindowResize(this.resize, this);
33341 if(this.bgimage.length){
33342 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33343 this.imageEl.on('load', this.onImageLoad, this);
33350 onImageLoad : function()
33355 resize : function()
33357 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33359 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33361 if(this.bgimage.length){
33362 var image = this.el.select('.roo-brick-image-view', true).first();
33364 image.setWidth(paragraph.getWidth());
33367 image.setHeight(paragraph.getWidth());
33370 this.el.setHeight(image.getHeight());
33371 paragraph.setHeight(image.getHeight());
33377 enter: function(e, el)
33379 e.preventDefault();
33381 if(this.bgimage.length){
33382 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33383 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33387 leave: function(e, el)
33389 e.preventDefault();
33391 if(this.bgimage.length){
33392 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33393 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33408 * @class Roo.bootstrap.NumberField
33409 * @extends Roo.bootstrap.Input
33410 * Bootstrap NumberField class
33416 * Create a new NumberField
33417 * @param {Object} config The config object
33420 Roo.bootstrap.NumberField = function(config){
33421 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33424 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33427 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33429 allowDecimals : true,
33431 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33433 decimalSeparator : ".",
33435 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33437 decimalPrecision : 2,
33439 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33441 allowNegative : true,
33444 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33448 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33450 minValue : Number.NEGATIVE_INFINITY,
33452 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33454 maxValue : Number.MAX_VALUE,
33456 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33458 minText : "The minimum value for this field is {0}",
33460 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33462 maxText : "The maximum value for this field is {0}",
33464 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33465 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33467 nanText : "{0} is not a valid number",
33469 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33471 thousandsDelimiter : false,
33473 * @cfg {String} valueAlign alignment of value
33475 valueAlign : "left",
33477 getAutoCreate : function()
33479 var hiddenInput = {
33483 cls: 'hidden-number-input'
33487 hiddenInput.name = this.name;
33492 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33494 this.name = hiddenInput.name;
33496 if(cfg.cn.length > 0) {
33497 cfg.cn.push(hiddenInput);
33504 initEvents : function()
33506 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33508 var allowed = "0123456789";
33510 if(this.allowDecimals){
33511 allowed += this.decimalSeparator;
33514 if(this.allowNegative){
33518 if(this.thousandsDelimiter) {
33522 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33524 var keyPress = function(e){
33526 var k = e.getKey();
33528 var c = e.getCharCode();
33531 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33532 allowed.indexOf(String.fromCharCode(c)) === -1
33538 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33542 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33547 this.el.on("keypress", keyPress, this);
33550 validateValue : function(value)
33553 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33557 var num = this.parseValue(value);
33560 this.markInvalid(String.format(this.nanText, value));
33564 if(num < this.minValue){
33565 this.markInvalid(String.format(this.minText, this.minValue));
33569 if(num > this.maxValue){
33570 this.markInvalid(String.format(this.maxText, this.maxValue));
33577 getValue : function()
33579 var v = this.hiddenEl().getValue();
33581 return this.fixPrecision(this.parseValue(v));
33584 parseValue : function(value)
33586 if(this.thousandsDelimiter) {
33588 r = new RegExp(",", "g");
33589 value = value.replace(r, "");
33592 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33593 return isNaN(value) ? '' : value;
33596 fixPrecision : function(value)
33598 if(this.thousandsDelimiter) {
33600 r = new RegExp(",", "g");
33601 value = value.replace(r, "");
33604 var nan = isNaN(value);
33606 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33607 return nan ? '' : value;
33609 return parseFloat(value).toFixed(this.decimalPrecision);
33612 setValue : function(v)
33614 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33620 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33622 this.inputEl().dom.value = (v == '') ? '' :
33623 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33625 if(!this.allowZero && v === '0') {
33626 this.hiddenEl().dom.value = '';
33627 this.inputEl().dom.value = '';
33634 decimalPrecisionFcn : function(v)
33636 return Math.floor(v);
33639 beforeBlur : function()
33641 var v = this.parseValue(this.getRawValue());
33643 if(v || v === 0 || v === ''){
33648 hiddenEl : function()
33650 return this.el.select('input.hidden-number-input',true).first();
33662 * @class Roo.bootstrap.DocumentSlider
33663 * @extends Roo.bootstrap.Component
33664 * Bootstrap DocumentSlider class
33667 * Create a new DocumentViewer
33668 * @param {Object} config The config object
33671 Roo.bootstrap.DocumentSlider = function(config){
33672 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33679 * Fire after initEvent
33680 * @param {Roo.bootstrap.DocumentSlider} this
33685 * Fire after update
33686 * @param {Roo.bootstrap.DocumentSlider} this
33692 * @param {Roo.bootstrap.DocumentSlider} this
33698 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33704 getAutoCreate : function()
33708 cls : 'roo-document-slider',
33712 cls : 'roo-document-slider-header',
33716 cls : 'roo-document-slider-header-title'
33722 cls : 'roo-document-slider-body',
33726 cls : 'roo-document-slider-prev',
33730 cls : 'fa fa-chevron-left'
33736 cls : 'roo-document-slider-thumb',
33740 cls : 'roo-document-slider-image'
33746 cls : 'roo-document-slider-next',
33750 cls : 'fa fa-chevron-right'
33762 initEvents : function()
33764 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33765 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33767 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33768 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33770 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33771 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33773 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33774 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33776 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33777 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33779 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33780 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33782 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33783 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33785 this.thumbEl.on('click', this.onClick, this);
33787 this.prevIndicator.on('click', this.prev, this);
33789 this.nextIndicator.on('click', this.next, this);
33793 initial : function()
33795 if(this.files.length){
33796 this.indicator = 1;
33800 this.fireEvent('initial', this);
33803 update : function()
33805 this.imageEl.attr('src', this.files[this.indicator - 1]);
33807 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33809 this.prevIndicator.show();
33811 if(this.indicator == 1){
33812 this.prevIndicator.hide();
33815 this.nextIndicator.show();
33817 if(this.indicator == this.files.length){
33818 this.nextIndicator.hide();
33821 this.thumbEl.scrollTo('top');
33823 this.fireEvent('update', this);
33826 onClick : function(e)
33828 e.preventDefault();
33830 this.fireEvent('click', this);
33835 e.preventDefault();
33837 this.indicator = Math.max(1, this.indicator - 1);
33844 e.preventDefault();
33846 this.indicator = Math.min(this.files.length, this.indicator + 1);
33860 * @class Roo.bootstrap.RadioSet
33861 * @extends Roo.bootstrap.Input
33862 * Bootstrap RadioSet class
33863 * @cfg {String} indicatorpos (left|right) default left
33864 * @cfg {Boolean} inline (true|false) inline the element (default true)
33865 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33867 * Create a new RadioSet
33868 * @param {Object} config The config object
33871 Roo.bootstrap.RadioSet = function(config){
33873 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33877 Roo.bootstrap.RadioSet.register(this);
33882 * Fires when the element is checked or unchecked.
33883 * @param {Roo.bootstrap.RadioSet} this This radio
33884 * @param {Roo.bootstrap.Radio} item The checked item
33889 * Fires when the element is click.
33890 * @param {Roo.bootstrap.RadioSet} this This radio set
33891 * @param {Roo.bootstrap.Radio} item The checked item
33892 * @param {Roo.EventObject} e The event object
33899 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33907 indicatorpos : 'left',
33909 getAutoCreate : function()
33913 cls : 'roo-radio-set-label',
33917 html : this.fieldLabel
33922 if(this.indicatorpos == 'left'){
33925 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33926 tooltip : 'This field is required'
33931 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33932 tooltip : 'This field is required'
33938 cls : 'roo-radio-set-items'
33941 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33943 if (align === 'left' && this.fieldLabel.length) {
33946 cls : "roo-radio-set-right",
33952 if(this.labelWidth > 12){
33953 label.style = "width: " + this.labelWidth + 'px';
33956 if(this.labelWidth < 13 && this.labelmd == 0){
33957 this.labelmd = this.labelWidth;
33960 if(this.labellg > 0){
33961 label.cls += ' col-lg-' + this.labellg;
33962 items.cls += ' col-lg-' + (12 - this.labellg);
33965 if(this.labelmd > 0){
33966 label.cls += ' col-md-' + this.labelmd;
33967 items.cls += ' col-md-' + (12 - this.labelmd);
33970 if(this.labelsm > 0){
33971 label.cls += ' col-sm-' + this.labelsm;
33972 items.cls += ' col-sm-' + (12 - this.labelsm);
33975 if(this.labelxs > 0){
33976 label.cls += ' col-xs-' + this.labelxs;
33977 items.cls += ' col-xs-' + (12 - this.labelxs);
33983 cls : 'roo-radio-set',
33987 cls : 'roo-radio-set-input',
33990 value : this.value ? this.value : ''
33997 if(this.weight.length){
33998 cfg.cls += ' roo-radio-' + this.weight;
34002 cfg.cls += ' roo-radio-set-inline';
34006 ['xs','sm','md','lg'].map(function(size){
34007 if (settings[size]) {
34008 cfg.cls += ' col-' + size + '-' + settings[size];
34016 initEvents : function()
34018 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34019 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34021 if(!this.fieldLabel.length){
34022 this.labelEl.hide();
34025 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34026 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34028 this.indicator = this.indicatorEl();
34030 if(this.indicator){
34031 this.indicator.addClass('invisible');
34034 this.originalValue = this.getValue();
34038 inputEl: function ()
34040 return this.el.select('.roo-radio-set-input', true).first();
34043 getChildContainer : function()
34045 return this.itemsEl;
34048 register : function(item)
34050 this.radioes.push(item);
34054 validate : function()
34056 if(this.getVisibilityEl().hasClass('hidden')){
34062 Roo.each(this.radioes, function(i){
34071 if(this.allowBlank) {
34075 if(this.disabled || valid){
34080 this.markInvalid();
34085 markValid : function()
34087 if(this.labelEl.isVisible(true)){
34088 this.indicatorEl().removeClass('visible');
34089 this.indicatorEl().addClass('invisible');
34092 this.el.removeClass([this.invalidClass, this.validClass]);
34093 this.el.addClass(this.validClass);
34095 this.fireEvent('valid', this);
34098 markInvalid : function(msg)
34100 if(this.allowBlank || this.disabled){
34104 if(this.labelEl.isVisible(true)){
34105 this.indicatorEl().removeClass('invisible');
34106 this.indicatorEl().addClass('visible');
34109 this.el.removeClass([this.invalidClass, this.validClass]);
34110 this.el.addClass(this.invalidClass);
34112 this.fireEvent('invalid', this, msg);
34116 setValue : function(v, suppressEvent)
34118 if(this.value === v){
34125 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34128 Roo.each(this.radioes, function(i){
34130 i.el.removeClass('checked');
34133 Roo.each(this.radioes, function(i){
34135 if(i.value === v || i.value.toString() === v.toString()){
34137 i.el.addClass('checked');
34139 if(suppressEvent !== true){
34140 this.fireEvent('check', this, i);
34151 clearInvalid : function(){
34153 if(!this.el || this.preventMark){
34157 this.el.removeClass([this.invalidClass]);
34159 this.fireEvent('valid', this);
34164 Roo.apply(Roo.bootstrap.RadioSet, {
34168 register : function(set)
34170 this.groups[set.name] = set;
34173 get: function(name)
34175 if (typeof(this.groups[name]) == 'undefined') {
34179 return this.groups[name] ;
34185 * Ext JS Library 1.1.1
34186 * Copyright(c) 2006-2007, Ext JS, LLC.
34188 * Originally Released Under LGPL - original licence link has changed is not relivant.
34191 * <script type="text/javascript">
34196 * @class Roo.bootstrap.SplitBar
34197 * @extends Roo.util.Observable
34198 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34202 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34203 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34204 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34205 split.minSize = 100;
34206 split.maxSize = 600;
34207 split.animate = true;
34208 split.on('moved', splitterMoved);
34211 * Create a new SplitBar
34212 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34213 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34214 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34215 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34216 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34217 position of the SplitBar).
34219 Roo.bootstrap.SplitBar = function(cfg){
34224 // dragElement : elm
34225 // resizingElement: el,
34227 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34228 // placement : Roo.bootstrap.SplitBar.LEFT ,
34229 // existingProxy ???
34232 this.el = Roo.get(cfg.dragElement, true);
34233 this.el.dom.unselectable = "on";
34235 this.resizingEl = Roo.get(cfg.resizingElement, true);
34239 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34240 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34243 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34246 * The minimum size of the resizing element. (Defaults to 0)
34252 * The maximum size of the resizing element. (Defaults to 2000)
34255 this.maxSize = 2000;
34258 * Whether to animate the transition to the new size
34261 this.animate = false;
34264 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34267 this.useShim = false;
34272 if(!cfg.existingProxy){
34274 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34276 this.proxy = Roo.get(cfg.existingProxy).dom;
34279 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34282 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34285 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34288 this.dragSpecs = {};
34291 * @private The adapter to use to positon and resize elements
34293 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34294 this.adapter.init(this);
34296 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34298 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34299 this.el.addClass("roo-splitbar-h");
34302 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34303 this.el.addClass("roo-splitbar-v");
34309 * Fires when the splitter is moved (alias for {@link #event-moved})
34310 * @param {Roo.bootstrap.SplitBar} this
34311 * @param {Number} newSize the new width or height
34316 * Fires when the splitter is moved
34317 * @param {Roo.bootstrap.SplitBar} this
34318 * @param {Number} newSize the new width or height
34322 * @event beforeresize
34323 * Fires before the splitter is dragged
34324 * @param {Roo.bootstrap.SplitBar} this
34326 "beforeresize" : true,
34328 "beforeapply" : true
34331 Roo.util.Observable.call(this);
34334 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34335 onStartProxyDrag : function(x, y){
34336 this.fireEvent("beforeresize", this);
34338 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34340 o.enableDisplayMode("block");
34341 // all splitbars share the same overlay
34342 Roo.bootstrap.SplitBar.prototype.overlay = o;
34344 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34345 this.overlay.show();
34346 Roo.get(this.proxy).setDisplayed("block");
34347 var size = this.adapter.getElementSize(this);
34348 this.activeMinSize = this.getMinimumSize();;
34349 this.activeMaxSize = this.getMaximumSize();;
34350 var c1 = size - this.activeMinSize;
34351 var c2 = Math.max(this.activeMaxSize - size, 0);
34352 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34353 this.dd.resetConstraints();
34354 this.dd.setXConstraint(
34355 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34356 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34358 this.dd.setYConstraint(0, 0);
34360 this.dd.resetConstraints();
34361 this.dd.setXConstraint(0, 0);
34362 this.dd.setYConstraint(
34363 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34364 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34367 this.dragSpecs.startSize = size;
34368 this.dragSpecs.startPoint = [x, y];
34369 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34373 * @private Called after the drag operation by the DDProxy
34375 onEndProxyDrag : function(e){
34376 Roo.get(this.proxy).setDisplayed(false);
34377 var endPoint = Roo.lib.Event.getXY(e);
34379 this.overlay.hide();
34382 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34383 newSize = this.dragSpecs.startSize +
34384 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34385 endPoint[0] - this.dragSpecs.startPoint[0] :
34386 this.dragSpecs.startPoint[0] - endPoint[0]
34389 newSize = this.dragSpecs.startSize +
34390 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34391 endPoint[1] - this.dragSpecs.startPoint[1] :
34392 this.dragSpecs.startPoint[1] - endPoint[1]
34395 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34396 if(newSize != this.dragSpecs.startSize){
34397 if(this.fireEvent('beforeapply', this, newSize) !== false){
34398 this.adapter.setElementSize(this, newSize);
34399 this.fireEvent("moved", this, newSize);
34400 this.fireEvent("resize", this, newSize);
34406 * Get the adapter this SplitBar uses
34407 * @return The adapter object
34409 getAdapter : function(){
34410 return this.adapter;
34414 * Set the adapter this SplitBar uses
34415 * @param {Object} adapter A SplitBar adapter object
34417 setAdapter : function(adapter){
34418 this.adapter = adapter;
34419 this.adapter.init(this);
34423 * Gets the minimum size for the resizing element
34424 * @return {Number} The minimum size
34426 getMinimumSize : function(){
34427 return this.minSize;
34431 * Sets the minimum size for the resizing element
34432 * @param {Number} minSize The minimum size
34434 setMinimumSize : function(minSize){
34435 this.minSize = minSize;
34439 * Gets the maximum size for the resizing element
34440 * @return {Number} The maximum size
34442 getMaximumSize : function(){
34443 return this.maxSize;
34447 * Sets the maximum size for the resizing element
34448 * @param {Number} maxSize The maximum size
34450 setMaximumSize : function(maxSize){
34451 this.maxSize = maxSize;
34455 * Sets the initialize size for the resizing element
34456 * @param {Number} size The initial size
34458 setCurrentSize : function(size){
34459 var oldAnimate = this.animate;
34460 this.animate = false;
34461 this.adapter.setElementSize(this, size);
34462 this.animate = oldAnimate;
34466 * Destroy this splitbar.
34467 * @param {Boolean} removeEl True to remove the element
34469 destroy : function(removeEl){
34471 this.shim.remove();
34474 this.proxy.parentNode.removeChild(this.proxy);
34482 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
34484 Roo.bootstrap.SplitBar.createProxy = function(dir){
34485 var proxy = new Roo.Element(document.createElement("div"));
34486 proxy.unselectable();
34487 var cls = 'roo-splitbar-proxy';
34488 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34489 document.body.appendChild(proxy.dom);
34494 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34495 * Default Adapter. It assumes the splitter and resizing element are not positioned
34496 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34498 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34501 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34502 // do nothing for now
34503 init : function(s){
34507 * Called before drag operations to get the current size of the resizing element.
34508 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34510 getElementSize : function(s){
34511 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34512 return s.resizingEl.getWidth();
34514 return s.resizingEl.getHeight();
34519 * Called after drag operations to set the size of the resizing element.
34520 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34521 * @param {Number} newSize The new size to set
34522 * @param {Function} onComplete A function to be invoked when resizing is complete
34524 setElementSize : function(s, newSize, onComplete){
34525 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34527 s.resizingEl.setWidth(newSize);
34529 onComplete(s, newSize);
34532 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34537 s.resizingEl.setHeight(newSize);
34539 onComplete(s, newSize);
34542 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34549 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34550 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34551 * Adapter that moves the splitter element to align with the resized sizing element.
34552 * Used with an absolute positioned SplitBar.
34553 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34554 * document.body, make sure you assign an id to the body element.
34556 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34557 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34558 this.container = Roo.get(container);
34561 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34562 init : function(s){
34563 this.basic.init(s);
34566 getElementSize : function(s){
34567 return this.basic.getElementSize(s);
34570 setElementSize : function(s, newSize, onComplete){
34571 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34574 moveSplitter : function(s){
34575 var yes = Roo.bootstrap.SplitBar;
34576 switch(s.placement){
34578 s.el.setX(s.resizingEl.getRight());
34581 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34584 s.el.setY(s.resizingEl.getBottom());
34587 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34594 * Orientation constant - Create a vertical SplitBar
34598 Roo.bootstrap.SplitBar.VERTICAL = 1;
34601 * Orientation constant - Create a horizontal SplitBar
34605 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34608 * Placement constant - The resizing element is to the left of the splitter element
34612 Roo.bootstrap.SplitBar.LEFT = 1;
34615 * Placement constant - The resizing element is to the right of the splitter element
34619 Roo.bootstrap.SplitBar.RIGHT = 2;
34622 * Placement constant - The resizing element is positioned above the splitter element
34626 Roo.bootstrap.SplitBar.TOP = 3;
34629 * Placement constant - The resizing element is positioned under splitter element
34633 Roo.bootstrap.SplitBar.BOTTOM = 4;
34634 Roo.namespace("Roo.bootstrap.layout");/*
34636 * Ext JS Library 1.1.1
34637 * Copyright(c) 2006-2007, Ext JS, LLC.
34639 * Originally Released Under LGPL - original licence link has changed is not relivant.
34642 * <script type="text/javascript">
34646 * @class Roo.bootstrap.layout.Manager
34647 * @extends Roo.bootstrap.Component
34648 * Base class for layout managers.
34650 Roo.bootstrap.layout.Manager = function(config)
34652 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34658 /** false to disable window resize monitoring @type Boolean */
34659 this.monitorWindowResize = true;
34664 * Fires when a layout is performed.
34665 * @param {Roo.LayoutManager} this
34669 * @event regionresized
34670 * Fires when the user resizes a region.
34671 * @param {Roo.LayoutRegion} region The resized region
34672 * @param {Number} newSize The new size (width for east/west, height for north/south)
34674 "regionresized" : true,
34676 * @event regioncollapsed
34677 * Fires when a region is collapsed.
34678 * @param {Roo.LayoutRegion} region The collapsed region
34680 "regioncollapsed" : true,
34682 * @event regionexpanded
34683 * Fires when a region is expanded.
34684 * @param {Roo.LayoutRegion} region The expanded region
34686 "regionexpanded" : true
34688 this.updating = false;
34691 this.el = Roo.get(config.el);
34697 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34702 monitorWindowResize : true,
34708 onRender : function(ct, position)
34711 this.el = Roo.get(ct);
34714 //this.fireEvent('render',this);
34718 initEvents: function()
34722 // ie scrollbar fix
34723 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34724 document.body.scroll = "no";
34725 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34726 this.el.position('relative');
34728 this.id = this.el.id;
34729 this.el.addClass("roo-layout-container");
34730 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34731 if(this.el.dom != document.body ) {
34732 this.el.on('resize', this.layout,this);
34733 this.el.on('show', this.layout,this);
34739 * Returns true if this layout is currently being updated
34740 * @return {Boolean}
34742 isUpdating : function(){
34743 return this.updating;
34747 * Suspend the LayoutManager from doing auto-layouts while
34748 * making multiple add or remove calls
34750 beginUpdate : function(){
34751 this.updating = true;
34755 * Restore auto-layouts and optionally disable the manager from performing a layout
34756 * @param {Boolean} noLayout true to disable a layout update
34758 endUpdate : function(noLayout){
34759 this.updating = false;
34765 layout: function(){
34769 onRegionResized : function(region, newSize){
34770 this.fireEvent("regionresized", region, newSize);
34774 onRegionCollapsed : function(region){
34775 this.fireEvent("regioncollapsed", region);
34778 onRegionExpanded : function(region){
34779 this.fireEvent("regionexpanded", region);
34783 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34784 * performs box-model adjustments.
34785 * @return {Object} The size as an object {width: (the width), height: (the height)}
34787 getViewSize : function()
34790 if(this.el.dom != document.body){
34791 size = this.el.getSize();
34793 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34795 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34796 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34801 * Returns the Element this layout is bound to.
34802 * @return {Roo.Element}
34804 getEl : function(){
34809 * Returns the specified region.
34810 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34811 * @return {Roo.LayoutRegion}
34813 getRegion : function(target){
34814 return this.regions[target.toLowerCase()];
34817 onWindowResize : function(){
34818 if(this.monitorWindowResize){
34825 * Ext JS Library 1.1.1
34826 * Copyright(c) 2006-2007, Ext JS, LLC.
34828 * Originally Released Under LGPL - original licence link has changed is not relivant.
34831 * <script type="text/javascript">
34834 * @class Roo.bootstrap.layout.Border
34835 * @extends Roo.bootstrap.layout.Manager
34836 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34837 * please see: examples/bootstrap/nested.html<br><br>
34839 <b>The container the layout is rendered into can be either the body element or any other element.
34840 If it is not the body element, the container needs to either be an absolute positioned element,
34841 or you will need to add "position:relative" to the css of the container. You will also need to specify
34842 the container size if it is not the body element.</b>
34845 * Create a new Border
34846 * @param {Object} config Configuration options
34848 Roo.bootstrap.layout.Border = function(config){
34849 config = config || {};
34850 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34854 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34855 if(config[region]){
34856 config[region].region = region;
34857 this.addRegion(config[region]);
34863 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34865 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34867 * Creates and adds a new region if it doesn't already exist.
34868 * @param {String} target The target region key (north, south, east, west or center).
34869 * @param {Object} config The regions config object
34870 * @return {BorderLayoutRegion} The new region
34872 addRegion : function(config)
34874 if(!this.regions[config.region]){
34875 var r = this.factory(config);
34876 this.bindRegion(r);
34878 return this.regions[config.region];
34882 bindRegion : function(r){
34883 this.regions[r.config.region] = r;
34885 r.on("visibilitychange", this.layout, this);
34886 r.on("paneladded", this.layout, this);
34887 r.on("panelremoved", this.layout, this);
34888 r.on("invalidated", this.layout, this);
34889 r.on("resized", this.onRegionResized, this);
34890 r.on("collapsed", this.onRegionCollapsed, this);
34891 r.on("expanded", this.onRegionExpanded, this);
34895 * Performs a layout update.
34897 layout : function()
34899 if(this.updating) {
34903 // render all the rebions if they have not been done alreayd?
34904 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34905 if(this.regions[region] && !this.regions[region].bodyEl){
34906 this.regions[region].onRender(this.el)
34910 var size = this.getViewSize();
34911 var w = size.width;
34912 var h = size.height;
34917 //var x = 0, y = 0;
34919 var rs = this.regions;
34920 var north = rs["north"];
34921 var south = rs["south"];
34922 var west = rs["west"];
34923 var east = rs["east"];
34924 var center = rs["center"];
34925 //if(this.hideOnLayout){ // not supported anymore
34926 //c.el.setStyle("display", "none");
34928 if(north && north.isVisible()){
34929 var b = north.getBox();
34930 var m = north.getMargins();
34931 b.width = w - (m.left+m.right);
34934 centerY = b.height + b.y + m.bottom;
34935 centerH -= centerY;
34936 north.updateBox(this.safeBox(b));
34938 if(south && south.isVisible()){
34939 var b = south.getBox();
34940 var m = south.getMargins();
34941 b.width = w - (m.left+m.right);
34943 var totalHeight = (b.height + m.top + m.bottom);
34944 b.y = h - totalHeight + m.top;
34945 centerH -= totalHeight;
34946 south.updateBox(this.safeBox(b));
34948 if(west && west.isVisible()){
34949 var b = west.getBox();
34950 var m = west.getMargins();
34951 b.height = centerH - (m.top+m.bottom);
34953 b.y = centerY + m.top;
34954 var totalWidth = (b.width + m.left + m.right);
34955 centerX += totalWidth;
34956 centerW -= totalWidth;
34957 west.updateBox(this.safeBox(b));
34959 if(east && east.isVisible()){
34960 var b = east.getBox();
34961 var m = east.getMargins();
34962 b.height = centerH - (m.top+m.bottom);
34963 var totalWidth = (b.width + m.left + m.right);
34964 b.x = w - totalWidth + m.left;
34965 b.y = centerY + m.top;
34966 centerW -= totalWidth;
34967 east.updateBox(this.safeBox(b));
34970 var m = center.getMargins();
34972 x: centerX + m.left,
34973 y: centerY + m.top,
34974 width: centerW - (m.left+m.right),
34975 height: centerH - (m.top+m.bottom)
34977 //if(this.hideOnLayout){
34978 //center.el.setStyle("display", "block");
34980 center.updateBox(this.safeBox(centerBox));
34983 this.fireEvent("layout", this);
34987 safeBox : function(box){
34988 box.width = Math.max(0, box.width);
34989 box.height = Math.max(0, box.height);
34994 * Adds a ContentPanel (or subclass) to this layout.
34995 * @param {String} target The target region key (north, south, east, west or center).
34996 * @param {Roo.ContentPanel} panel The panel to add
34997 * @return {Roo.ContentPanel} The added panel
34999 add : function(target, panel){
35001 target = target.toLowerCase();
35002 return this.regions[target].add(panel);
35006 * Remove a ContentPanel (or subclass) to this layout.
35007 * @param {String} target The target region key (north, south, east, west or center).
35008 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35009 * @return {Roo.ContentPanel} The removed panel
35011 remove : function(target, panel){
35012 target = target.toLowerCase();
35013 return this.regions[target].remove(panel);
35017 * Searches all regions for a panel with the specified id
35018 * @param {String} panelId
35019 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35021 findPanel : function(panelId){
35022 var rs = this.regions;
35023 for(var target in rs){
35024 if(typeof rs[target] != "function"){
35025 var p = rs[target].getPanel(panelId);
35035 * Searches all regions for a panel with the specified id and activates (shows) it.
35036 * @param {String/ContentPanel} panelId The panels id or the panel itself
35037 * @return {Roo.ContentPanel} The shown panel or null
35039 showPanel : function(panelId) {
35040 var rs = this.regions;
35041 for(var target in rs){
35042 var r = rs[target];
35043 if(typeof r != "function"){
35044 if(r.hasPanel(panelId)){
35045 return r.showPanel(panelId);
35053 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35054 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35057 restoreState : function(provider){
35059 provider = Roo.state.Manager;
35061 var sm = new Roo.LayoutStateManager();
35062 sm.init(this, provider);
35068 * Adds a xtype elements to the layout.
35072 xtype : 'ContentPanel',
35079 xtype : 'NestedLayoutPanel',
35085 items : [ ... list of content panels or nested layout panels.. ]
35089 * @param {Object} cfg Xtype definition of item to add.
35091 addxtype : function(cfg)
35093 // basically accepts a pannel...
35094 // can accept a layout region..!?!?
35095 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35098 // theory? children can only be panels??
35100 //if (!cfg.xtype.match(/Panel$/)) {
35105 if (typeof(cfg.region) == 'undefined') {
35106 Roo.log("Failed to add Panel, region was not set");
35110 var region = cfg.region;
35116 xitems = cfg.items;
35123 case 'Content': // ContentPanel (el, cfg)
35124 case 'Scroll': // ContentPanel (el, cfg)
35126 cfg.autoCreate = true;
35127 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35129 // var el = this.el.createChild();
35130 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35133 this.add(region, ret);
35137 case 'TreePanel': // our new panel!
35138 cfg.el = this.el.createChild();
35139 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35140 this.add(region, ret);
35145 // create a new Layout (which is a Border Layout...
35147 var clayout = cfg.layout;
35148 clayout.el = this.el.createChild();
35149 clayout.items = clayout.items || [];
35153 // replace this exitems with the clayout ones..
35154 xitems = clayout.items;
35156 // force background off if it's in center...
35157 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35158 cfg.background = false;
35160 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35163 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35164 //console.log('adding nested layout panel ' + cfg.toSource());
35165 this.add(region, ret);
35166 nb = {}; /// find first...
35171 // needs grid and region
35173 //var el = this.getRegion(region).el.createChild();
35175 *var el = this.el.createChild();
35176 // create the grid first...
35177 cfg.grid.container = el;
35178 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35181 if (region == 'center' && this.active ) {
35182 cfg.background = false;
35185 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35187 this.add(region, ret);
35189 if (cfg.background) {
35190 // render grid on panel activation (if panel background)
35191 ret.on('activate', function(gp) {
35192 if (!gp.grid.rendered) {
35193 // gp.grid.render(el);
35197 // cfg.grid.render(el);
35203 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35204 // it was the old xcomponent building that caused this before.
35205 // espeically if border is the top element in the tree.
35215 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35217 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35218 this.add(region, ret);
35222 throw "Can not add '" + cfg.xtype + "' to Border";
35228 this.beginUpdate();
35232 Roo.each(xitems, function(i) {
35233 region = nb && i.region ? i.region : false;
35235 var add = ret.addxtype(i);
35238 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35239 if (!i.background) {
35240 abn[region] = nb[region] ;
35247 // make the last non-background panel active..
35248 //if (nb) { Roo.log(abn); }
35251 for(var r in abn) {
35252 region = this.getRegion(r);
35254 // tried using nb[r], but it does not work..
35256 region.showPanel(abn[r]);
35267 factory : function(cfg)
35270 var validRegions = Roo.bootstrap.layout.Border.regions;
35272 var target = cfg.region;
35275 var r = Roo.bootstrap.layout;
35279 return new r.North(cfg);
35281 return new r.South(cfg);
35283 return new r.East(cfg);
35285 return new r.West(cfg);
35287 return new r.Center(cfg);
35289 throw 'Layout region "'+target+'" not supported.';
35296 * Ext JS Library 1.1.1
35297 * Copyright(c) 2006-2007, Ext JS, LLC.
35299 * Originally Released Under LGPL - original licence link has changed is not relivant.
35302 * <script type="text/javascript">
35306 * @class Roo.bootstrap.layout.Basic
35307 * @extends Roo.util.Observable
35308 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35309 * and does not have a titlebar, tabs or any other features. All it does is size and position
35310 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35311 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35312 * @cfg {string} region the region that it inhabits..
35313 * @cfg {bool} skipConfig skip config?
35317 Roo.bootstrap.layout.Basic = function(config){
35319 this.mgr = config.mgr;
35321 this.position = config.region;
35323 var skipConfig = config.skipConfig;
35327 * @scope Roo.BasicLayoutRegion
35331 * @event beforeremove
35332 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35333 * @param {Roo.LayoutRegion} this
35334 * @param {Roo.ContentPanel} panel The panel
35335 * @param {Object} e The cancel event object
35337 "beforeremove" : true,
35339 * @event invalidated
35340 * Fires when the layout for this region is changed.
35341 * @param {Roo.LayoutRegion} this
35343 "invalidated" : true,
35345 * @event visibilitychange
35346 * Fires when this region is shown or hidden
35347 * @param {Roo.LayoutRegion} this
35348 * @param {Boolean} visibility true or false
35350 "visibilitychange" : true,
35352 * @event paneladded
35353 * Fires when a panel is added.
35354 * @param {Roo.LayoutRegion} this
35355 * @param {Roo.ContentPanel} panel The panel
35357 "paneladded" : true,
35359 * @event panelremoved
35360 * Fires when a panel is removed.
35361 * @param {Roo.LayoutRegion} this
35362 * @param {Roo.ContentPanel} panel The panel
35364 "panelremoved" : true,
35366 * @event beforecollapse
35367 * Fires when this region before collapse.
35368 * @param {Roo.LayoutRegion} this
35370 "beforecollapse" : true,
35373 * Fires when this region is collapsed.
35374 * @param {Roo.LayoutRegion} this
35376 "collapsed" : true,
35379 * Fires when this region is expanded.
35380 * @param {Roo.LayoutRegion} this
35385 * Fires when this region is slid into view.
35386 * @param {Roo.LayoutRegion} this
35388 "slideshow" : true,
35391 * Fires when this region slides out of view.
35392 * @param {Roo.LayoutRegion} this
35394 "slidehide" : true,
35396 * @event panelactivated
35397 * Fires when a panel is activated.
35398 * @param {Roo.LayoutRegion} this
35399 * @param {Roo.ContentPanel} panel The activated panel
35401 "panelactivated" : true,
35404 * Fires when the user resizes this region.
35405 * @param {Roo.LayoutRegion} this
35406 * @param {Number} newSize The new size (width for east/west, height for north/south)
35410 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35411 this.panels = new Roo.util.MixedCollection();
35412 this.panels.getKey = this.getPanelId.createDelegate(this);
35414 this.activePanel = null;
35415 // ensure listeners are added...
35417 if (config.listeners || config.events) {
35418 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35419 listeners : config.listeners || {},
35420 events : config.events || {}
35424 if(skipConfig !== true){
35425 this.applyConfig(config);
35429 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35431 getPanelId : function(p){
35435 applyConfig : function(config){
35436 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35437 this.config = config;
35442 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35443 * the width, for horizontal (north, south) the height.
35444 * @param {Number} newSize The new width or height
35446 resizeTo : function(newSize){
35447 var el = this.el ? this.el :
35448 (this.activePanel ? this.activePanel.getEl() : null);
35450 switch(this.position){
35453 el.setWidth(newSize);
35454 this.fireEvent("resized", this, newSize);
35458 el.setHeight(newSize);
35459 this.fireEvent("resized", this, newSize);
35465 getBox : function(){
35466 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35469 getMargins : function(){
35470 return this.margins;
35473 updateBox : function(box){
35475 var el = this.activePanel.getEl();
35476 el.dom.style.left = box.x + "px";
35477 el.dom.style.top = box.y + "px";
35478 this.activePanel.setSize(box.width, box.height);
35482 * Returns the container element for this region.
35483 * @return {Roo.Element}
35485 getEl : function(){
35486 return this.activePanel;
35490 * Returns true if this region is currently visible.
35491 * @return {Boolean}
35493 isVisible : function(){
35494 return this.activePanel ? true : false;
35497 setActivePanel : function(panel){
35498 panel = this.getPanel(panel);
35499 if(this.activePanel && this.activePanel != panel){
35500 this.activePanel.setActiveState(false);
35501 this.activePanel.getEl().setLeftTop(-10000,-10000);
35503 this.activePanel = panel;
35504 panel.setActiveState(true);
35506 panel.setSize(this.box.width, this.box.height);
35508 this.fireEvent("panelactivated", this, panel);
35509 this.fireEvent("invalidated");
35513 * Show the specified panel.
35514 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35515 * @return {Roo.ContentPanel} The shown panel or null
35517 showPanel : function(panel){
35518 panel = this.getPanel(panel);
35520 this.setActivePanel(panel);
35526 * Get the active panel for this region.
35527 * @return {Roo.ContentPanel} The active panel or null
35529 getActivePanel : function(){
35530 return this.activePanel;
35534 * Add the passed ContentPanel(s)
35535 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35536 * @return {Roo.ContentPanel} The panel added (if only one was added)
35538 add : function(panel){
35539 if(arguments.length > 1){
35540 for(var i = 0, len = arguments.length; i < len; i++) {
35541 this.add(arguments[i]);
35545 if(this.hasPanel(panel)){
35546 this.showPanel(panel);
35549 var el = panel.getEl();
35550 if(el.dom.parentNode != this.mgr.el.dom){
35551 this.mgr.el.dom.appendChild(el.dom);
35553 if(panel.setRegion){
35554 panel.setRegion(this);
35556 this.panels.add(panel);
35557 el.setStyle("position", "absolute");
35558 if(!panel.background){
35559 this.setActivePanel(panel);
35560 if(this.config.initialSize && this.panels.getCount()==1){
35561 this.resizeTo(this.config.initialSize);
35564 this.fireEvent("paneladded", this, panel);
35569 * Returns true if the panel is in this region.
35570 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35571 * @return {Boolean}
35573 hasPanel : function(panel){
35574 if(typeof panel == "object"){ // must be panel obj
35575 panel = panel.getId();
35577 return this.getPanel(panel) ? true : false;
35581 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35582 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35583 * @param {Boolean} preservePanel Overrides the config preservePanel option
35584 * @return {Roo.ContentPanel} The panel that was removed
35586 remove : function(panel, preservePanel){
35587 panel = this.getPanel(panel);
35592 this.fireEvent("beforeremove", this, panel, e);
35593 if(e.cancel === true){
35596 var panelId = panel.getId();
35597 this.panels.removeKey(panelId);
35602 * Returns the panel specified or null if it's not in this region.
35603 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35604 * @return {Roo.ContentPanel}
35606 getPanel : function(id){
35607 if(typeof id == "object"){ // must be panel obj
35610 return this.panels.get(id);
35614 * Returns this regions position (north/south/east/west/center).
35617 getPosition: function(){
35618 return this.position;
35622 * Ext JS Library 1.1.1
35623 * Copyright(c) 2006-2007, Ext JS, LLC.
35625 * Originally Released Under LGPL - original licence link has changed is not relivant.
35628 * <script type="text/javascript">
35632 * @class Roo.bootstrap.layout.Region
35633 * @extends Roo.bootstrap.layout.Basic
35634 * This class represents a region in a layout manager.
35636 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35637 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
35638 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35639 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35640 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35641 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35642 * @cfg {String} title The title for the region (overrides panel titles)
35643 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35644 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35645 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35646 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35647 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35648 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35649 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35650 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35651 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35652 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35654 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35655 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35656 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35657 * @cfg {Number} width For East/West panels
35658 * @cfg {Number} height For North/South panels
35659 * @cfg {Boolean} split To show the splitter
35660 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35662 * @cfg {string} cls Extra CSS classes to add to region
35664 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35665 * @cfg {string} region the region that it inhabits..
35668 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35669 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35671 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35672 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35673 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35675 Roo.bootstrap.layout.Region = function(config)
35677 this.applyConfig(config);
35679 var mgr = config.mgr;
35680 var pos = config.region;
35681 config.skipConfig = true;
35682 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35685 this.onRender(mgr.el);
35688 this.visible = true;
35689 this.collapsed = false;
35690 this.unrendered_panels = [];
35693 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35695 position: '', // set by wrapper (eg. north/south etc..)
35696 unrendered_panels : null, // unrendered panels.
35697 createBody : function(){
35698 /** This region's body element
35699 * @type Roo.Element */
35700 this.bodyEl = this.el.createChild({
35702 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35706 onRender: function(ctr, pos)
35708 var dh = Roo.DomHelper;
35709 /** This region's container element
35710 * @type Roo.Element */
35711 this.el = dh.append(ctr.dom, {
35713 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35715 /** This region's title element
35716 * @type Roo.Element */
35718 this.titleEl = dh.append(this.el.dom,
35721 unselectable: "on",
35722 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35724 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35725 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35728 this.titleEl.enableDisplayMode();
35729 /** This region's title text element
35730 * @type HTMLElement */
35731 this.titleTextEl = this.titleEl.dom.firstChild;
35732 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35734 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35735 this.closeBtn.enableDisplayMode();
35736 this.closeBtn.on("click", this.closeClicked, this);
35737 this.closeBtn.hide();
35739 this.createBody(this.config);
35740 if(this.config.hideWhenEmpty){
35742 this.on("paneladded", this.validateVisibility, this);
35743 this.on("panelremoved", this.validateVisibility, this);
35745 if(this.autoScroll){
35746 this.bodyEl.setStyle("overflow", "auto");
35748 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35750 //if(c.titlebar !== false){
35751 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35752 this.titleEl.hide();
35754 this.titleEl.show();
35755 if(this.config.title){
35756 this.titleTextEl.innerHTML = this.config.title;
35760 if(this.config.collapsed){
35761 this.collapse(true);
35763 if(this.config.hidden){
35767 if (this.unrendered_panels && this.unrendered_panels.length) {
35768 for (var i =0;i< this.unrendered_panels.length; i++) {
35769 this.add(this.unrendered_panels[i]);
35771 this.unrendered_panels = null;
35777 applyConfig : function(c)
35780 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35781 var dh = Roo.DomHelper;
35782 if(c.titlebar !== false){
35783 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35784 this.collapseBtn.on("click", this.collapse, this);
35785 this.collapseBtn.enableDisplayMode();
35787 if(c.showPin === true || this.showPin){
35788 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35789 this.stickBtn.enableDisplayMode();
35790 this.stickBtn.on("click", this.expand, this);
35791 this.stickBtn.hide();
35796 /** This region's collapsed element
35797 * @type Roo.Element */
35800 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35801 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35804 if(c.floatable !== false){
35805 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35806 this.collapsedEl.on("click", this.collapseClick, this);
35809 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35810 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35811 id: "message", unselectable: "on", style:{"float":"left"}});
35812 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35814 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35815 this.expandBtn.on("click", this.expand, this);
35819 if(this.collapseBtn){
35820 this.collapseBtn.setVisible(c.collapsible == true);
35823 this.cmargins = c.cmargins || this.cmargins ||
35824 (this.position == "west" || this.position == "east" ?
35825 {top: 0, left: 2, right:2, bottom: 0} :
35826 {top: 2, left: 0, right:0, bottom: 2});
35828 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35831 this.bottomTabs = c.tabPosition != "top";
35833 this.autoScroll = c.autoScroll || false;
35838 this.duration = c.duration || .30;
35839 this.slideDuration = c.slideDuration || .45;
35844 * Returns true if this region is currently visible.
35845 * @return {Boolean}
35847 isVisible : function(){
35848 return this.visible;
35852 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35853 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35855 //setCollapsedTitle : function(title){
35856 // title = title || " ";
35857 // if(this.collapsedTitleTextEl){
35858 // this.collapsedTitleTextEl.innerHTML = title;
35862 getBox : function(){
35864 // if(!this.collapsed){
35865 b = this.el.getBox(false, true);
35867 // b = this.collapsedEl.getBox(false, true);
35872 getMargins : function(){
35873 return this.margins;
35874 //return this.collapsed ? this.cmargins : this.margins;
35877 highlight : function(){
35878 this.el.addClass("x-layout-panel-dragover");
35881 unhighlight : function(){
35882 this.el.removeClass("x-layout-panel-dragover");
35885 updateBox : function(box)
35887 if (!this.bodyEl) {
35888 return; // not rendered yet..
35892 if(!this.collapsed){
35893 this.el.dom.style.left = box.x + "px";
35894 this.el.dom.style.top = box.y + "px";
35895 this.updateBody(box.width, box.height);
35897 this.collapsedEl.dom.style.left = box.x + "px";
35898 this.collapsedEl.dom.style.top = box.y + "px";
35899 this.collapsedEl.setSize(box.width, box.height);
35902 this.tabs.autoSizeTabs();
35906 updateBody : function(w, h)
35909 this.el.setWidth(w);
35910 w -= this.el.getBorderWidth("rl");
35911 if(this.config.adjustments){
35912 w += this.config.adjustments[0];
35915 if(h !== null && h > 0){
35916 this.el.setHeight(h);
35917 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35918 h -= this.el.getBorderWidth("tb");
35919 if(this.config.adjustments){
35920 h += this.config.adjustments[1];
35922 this.bodyEl.setHeight(h);
35924 h = this.tabs.syncHeight(h);
35927 if(this.panelSize){
35928 w = w !== null ? w : this.panelSize.width;
35929 h = h !== null ? h : this.panelSize.height;
35931 if(this.activePanel){
35932 var el = this.activePanel.getEl();
35933 w = w !== null ? w : el.getWidth();
35934 h = h !== null ? h : el.getHeight();
35935 this.panelSize = {width: w, height: h};
35936 this.activePanel.setSize(w, h);
35938 if(Roo.isIE && this.tabs){
35939 this.tabs.el.repaint();
35944 * Returns the container element for this region.
35945 * @return {Roo.Element}
35947 getEl : function(){
35952 * Hides this region.
35955 //if(!this.collapsed){
35956 this.el.dom.style.left = "-2000px";
35959 // this.collapsedEl.dom.style.left = "-2000px";
35960 // this.collapsedEl.hide();
35962 this.visible = false;
35963 this.fireEvent("visibilitychange", this, false);
35967 * Shows this region if it was previously hidden.
35970 //if(!this.collapsed){
35973 // this.collapsedEl.show();
35975 this.visible = true;
35976 this.fireEvent("visibilitychange", this, true);
35979 closeClicked : function(){
35980 if(this.activePanel){
35981 this.remove(this.activePanel);
35985 collapseClick : function(e){
35987 e.stopPropagation();
35990 e.stopPropagation();
35996 * Collapses this region.
35997 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36000 collapse : function(skipAnim, skipCheck = false){
36001 if(this.collapsed) {
36005 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36007 this.collapsed = true;
36009 this.split.el.hide();
36011 if(this.config.animate && skipAnim !== true){
36012 this.fireEvent("invalidated", this);
36013 this.animateCollapse();
36015 this.el.setLocation(-20000,-20000);
36017 this.collapsedEl.show();
36018 this.fireEvent("collapsed", this);
36019 this.fireEvent("invalidated", this);
36025 animateCollapse : function(){
36030 * Expands this region if it was previously collapsed.
36031 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36032 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36035 expand : function(e, skipAnim){
36037 e.stopPropagation();
36039 if(!this.collapsed || this.el.hasActiveFx()) {
36043 this.afterSlideIn();
36046 this.collapsed = false;
36047 if(this.config.animate && skipAnim !== true){
36048 this.animateExpand();
36052 this.split.el.show();
36054 this.collapsedEl.setLocation(-2000,-2000);
36055 this.collapsedEl.hide();
36056 this.fireEvent("invalidated", this);
36057 this.fireEvent("expanded", this);
36061 animateExpand : function(){
36065 initTabs : function()
36067 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36069 var ts = new Roo.bootstrap.panel.Tabs({
36070 el: this.bodyEl.dom,
36071 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36072 disableTooltips: this.config.disableTabTips,
36073 toolbar : this.config.toolbar
36076 if(this.config.hideTabs){
36077 ts.stripWrap.setDisplayed(false);
36080 ts.resizeTabs = this.config.resizeTabs === true;
36081 ts.minTabWidth = this.config.minTabWidth || 40;
36082 ts.maxTabWidth = this.config.maxTabWidth || 250;
36083 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36084 ts.monitorResize = false;
36085 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36086 ts.bodyEl.addClass('roo-layout-tabs-body');
36087 this.panels.each(this.initPanelAsTab, this);
36090 initPanelAsTab : function(panel){
36091 var ti = this.tabs.addTab(
36095 this.config.closeOnTab && panel.isClosable(),
36098 if(panel.tabTip !== undefined){
36099 ti.setTooltip(panel.tabTip);
36101 ti.on("activate", function(){
36102 this.setActivePanel(panel);
36105 if(this.config.closeOnTab){
36106 ti.on("beforeclose", function(t, e){
36108 this.remove(panel);
36112 panel.tabItem = ti;
36117 updatePanelTitle : function(panel, title)
36119 if(this.activePanel == panel){
36120 this.updateTitle(title);
36123 var ti = this.tabs.getTab(panel.getEl().id);
36125 if(panel.tabTip !== undefined){
36126 ti.setTooltip(panel.tabTip);
36131 updateTitle : function(title){
36132 if(this.titleTextEl && !this.config.title){
36133 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36137 setActivePanel : function(panel)
36139 panel = this.getPanel(panel);
36140 if(this.activePanel && this.activePanel != panel){
36141 if(this.activePanel.setActiveState(false) === false){
36145 this.activePanel = panel;
36146 panel.setActiveState(true);
36147 if(this.panelSize){
36148 panel.setSize(this.panelSize.width, this.panelSize.height);
36151 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36153 this.updateTitle(panel.getTitle());
36155 this.fireEvent("invalidated", this);
36157 this.fireEvent("panelactivated", this, panel);
36161 * Shows the specified panel.
36162 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36163 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36165 showPanel : function(panel)
36167 panel = this.getPanel(panel);
36170 var tab = this.tabs.getTab(panel.getEl().id);
36171 if(tab.isHidden()){
36172 this.tabs.unhideTab(tab.id);
36176 this.setActivePanel(panel);
36183 * Get the active panel for this region.
36184 * @return {Roo.ContentPanel} The active panel or null
36186 getActivePanel : function(){
36187 return this.activePanel;
36190 validateVisibility : function(){
36191 if(this.panels.getCount() < 1){
36192 this.updateTitle(" ");
36193 this.closeBtn.hide();
36196 if(!this.isVisible()){
36203 * Adds the passed ContentPanel(s) to this region.
36204 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36205 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36207 add : function(panel)
36209 if(arguments.length > 1){
36210 for(var i = 0, len = arguments.length; i < len; i++) {
36211 this.add(arguments[i]);
36216 // if we have not been rendered yet, then we can not really do much of this..
36217 if (!this.bodyEl) {
36218 this.unrendered_panels.push(panel);
36225 if(this.hasPanel(panel)){
36226 this.showPanel(panel);
36229 panel.setRegion(this);
36230 this.panels.add(panel);
36231 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36232 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36233 // and hide them... ???
36234 this.bodyEl.dom.appendChild(panel.getEl().dom);
36235 if(panel.background !== true){
36236 this.setActivePanel(panel);
36238 this.fireEvent("paneladded", this, panel);
36245 this.initPanelAsTab(panel);
36249 if(panel.background !== true){
36250 this.tabs.activate(panel.getEl().id);
36252 this.fireEvent("paneladded", this, panel);
36257 * Hides the tab for the specified panel.
36258 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36260 hidePanel : function(panel){
36261 if(this.tabs && (panel = this.getPanel(panel))){
36262 this.tabs.hideTab(panel.getEl().id);
36267 * Unhides the tab for a previously hidden panel.
36268 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36270 unhidePanel : function(panel){
36271 if(this.tabs && (panel = this.getPanel(panel))){
36272 this.tabs.unhideTab(panel.getEl().id);
36276 clearPanels : function(){
36277 while(this.panels.getCount() > 0){
36278 this.remove(this.panels.first());
36283 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36284 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36285 * @param {Boolean} preservePanel Overrides the config preservePanel option
36286 * @return {Roo.ContentPanel} The panel that was removed
36288 remove : function(panel, preservePanel)
36290 panel = this.getPanel(panel);
36295 this.fireEvent("beforeremove", this, panel, e);
36296 if(e.cancel === true){
36299 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36300 var panelId = panel.getId();
36301 this.panels.removeKey(panelId);
36303 document.body.appendChild(panel.getEl().dom);
36306 this.tabs.removeTab(panel.getEl().id);
36307 }else if (!preservePanel){
36308 this.bodyEl.dom.removeChild(panel.getEl().dom);
36310 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36311 var p = this.panels.first();
36312 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36313 tempEl.appendChild(p.getEl().dom);
36314 this.bodyEl.update("");
36315 this.bodyEl.dom.appendChild(p.getEl().dom);
36317 this.updateTitle(p.getTitle());
36319 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36320 this.setActivePanel(p);
36322 panel.setRegion(null);
36323 if(this.activePanel == panel){
36324 this.activePanel = null;
36326 if(this.config.autoDestroy !== false && preservePanel !== true){
36327 try{panel.destroy();}catch(e){}
36329 this.fireEvent("panelremoved", this, panel);
36334 * Returns the TabPanel component used by this region
36335 * @return {Roo.TabPanel}
36337 getTabs : function(){
36341 createTool : function(parentEl, className){
36342 var btn = Roo.DomHelper.append(parentEl, {
36344 cls: "x-layout-tools-button",
36347 cls: "roo-layout-tools-button-inner " + className,
36351 btn.addClassOnOver("roo-layout-tools-button-over");
36356 * Ext JS Library 1.1.1
36357 * Copyright(c) 2006-2007, Ext JS, LLC.
36359 * Originally Released Under LGPL - original licence link has changed is not relivant.
36362 * <script type="text/javascript">
36368 * @class Roo.SplitLayoutRegion
36369 * @extends Roo.LayoutRegion
36370 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36372 Roo.bootstrap.layout.Split = function(config){
36373 this.cursor = config.cursor;
36374 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36377 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36379 splitTip : "Drag to resize.",
36380 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36381 useSplitTips : false,
36383 applyConfig : function(config){
36384 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36387 onRender : function(ctr,pos) {
36389 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36390 if(!this.config.split){
36395 var splitEl = Roo.DomHelper.append(ctr.dom, {
36397 id: this.el.id + "-split",
36398 cls: "roo-layout-split roo-layout-split-"+this.position,
36401 /** The SplitBar for this region
36402 * @type Roo.SplitBar */
36403 // does not exist yet...
36404 Roo.log([this.position, this.orientation]);
36406 this.split = new Roo.bootstrap.SplitBar({
36407 dragElement : splitEl,
36408 resizingElement: this.el,
36409 orientation : this.orientation
36412 this.split.on("moved", this.onSplitMove, this);
36413 this.split.useShim = this.config.useShim === true;
36414 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36415 if(this.useSplitTips){
36416 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36418 //if(config.collapsible){
36419 // this.split.el.on("dblclick", this.collapse, this);
36422 if(typeof this.config.minSize != "undefined"){
36423 this.split.minSize = this.config.minSize;
36425 if(typeof this.config.maxSize != "undefined"){
36426 this.split.maxSize = this.config.maxSize;
36428 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36429 this.hideSplitter();
36434 getHMaxSize : function(){
36435 var cmax = this.config.maxSize || 10000;
36436 var center = this.mgr.getRegion("center");
36437 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36440 getVMaxSize : function(){
36441 var cmax = this.config.maxSize || 10000;
36442 var center = this.mgr.getRegion("center");
36443 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36446 onSplitMove : function(split, newSize){
36447 this.fireEvent("resized", this, newSize);
36451 * Returns the {@link Roo.SplitBar} for this region.
36452 * @return {Roo.SplitBar}
36454 getSplitBar : function(){
36459 this.hideSplitter();
36460 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36463 hideSplitter : function(){
36465 this.split.el.setLocation(-2000,-2000);
36466 this.split.el.hide();
36472 this.split.el.show();
36474 Roo.bootstrap.layout.Split.superclass.show.call(this);
36477 beforeSlide: function(){
36478 if(Roo.isGecko){// firefox overflow auto bug workaround
36479 this.bodyEl.clip();
36481 this.tabs.bodyEl.clip();
36483 if(this.activePanel){
36484 this.activePanel.getEl().clip();
36486 if(this.activePanel.beforeSlide){
36487 this.activePanel.beforeSlide();
36493 afterSlide : function(){
36494 if(Roo.isGecko){// firefox overflow auto bug workaround
36495 this.bodyEl.unclip();
36497 this.tabs.bodyEl.unclip();
36499 if(this.activePanel){
36500 this.activePanel.getEl().unclip();
36501 if(this.activePanel.afterSlide){
36502 this.activePanel.afterSlide();
36508 initAutoHide : function(){
36509 if(this.autoHide !== false){
36510 if(!this.autoHideHd){
36511 var st = new Roo.util.DelayedTask(this.slideIn, this);
36512 this.autoHideHd = {
36513 "mouseout": function(e){
36514 if(!e.within(this.el, true)){
36518 "mouseover" : function(e){
36524 this.el.on(this.autoHideHd);
36528 clearAutoHide : function(){
36529 if(this.autoHide !== false){
36530 this.el.un("mouseout", this.autoHideHd.mouseout);
36531 this.el.un("mouseover", this.autoHideHd.mouseover);
36535 clearMonitor : function(){
36536 Roo.get(document).un("click", this.slideInIf, this);
36539 // these names are backwards but not changed for compat
36540 slideOut : function(){
36541 if(this.isSlid || this.el.hasActiveFx()){
36544 this.isSlid = true;
36545 if(this.collapseBtn){
36546 this.collapseBtn.hide();
36548 this.closeBtnState = this.closeBtn.getStyle('display');
36549 this.closeBtn.hide();
36551 this.stickBtn.show();
36554 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36555 this.beforeSlide();
36556 this.el.setStyle("z-index", 10001);
36557 this.el.slideIn(this.getSlideAnchor(), {
36558 callback: function(){
36560 this.initAutoHide();
36561 Roo.get(document).on("click", this.slideInIf, this);
36562 this.fireEvent("slideshow", this);
36569 afterSlideIn : function(){
36570 this.clearAutoHide();
36571 this.isSlid = false;
36572 this.clearMonitor();
36573 this.el.setStyle("z-index", "");
36574 if(this.collapseBtn){
36575 this.collapseBtn.show();
36577 this.closeBtn.setStyle('display', this.closeBtnState);
36579 this.stickBtn.hide();
36581 this.fireEvent("slidehide", this);
36584 slideIn : function(cb){
36585 if(!this.isSlid || this.el.hasActiveFx()){
36589 this.isSlid = false;
36590 this.beforeSlide();
36591 this.el.slideOut(this.getSlideAnchor(), {
36592 callback: function(){
36593 this.el.setLeftTop(-10000, -10000);
36595 this.afterSlideIn();
36603 slideInIf : function(e){
36604 if(!e.within(this.el)){
36609 animateCollapse : function(){
36610 this.beforeSlide();
36611 this.el.setStyle("z-index", 20000);
36612 var anchor = this.getSlideAnchor();
36613 this.el.slideOut(anchor, {
36614 callback : function(){
36615 this.el.setStyle("z-index", "");
36616 this.collapsedEl.slideIn(anchor, {duration:.3});
36618 this.el.setLocation(-10000,-10000);
36620 this.fireEvent("collapsed", this);
36627 animateExpand : function(){
36628 this.beforeSlide();
36629 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36630 this.el.setStyle("z-index", 20000);
36631 this.collapsedEl.hide({
36634 this.el.slideIn(this.getSlideAnchor(), {
36635 callback : function(){
36636 this.el.setStyle("z-index", "");
36639 this.split.el.show();
36641 this.fireEvent("invalidated", this);
36642 this.fireEvent("expanded", this);
36670 getAnchor : function(){
36671 return this.anchors[this.position];
36674 getCollapseAnchor : function(){
36675 return this.canchors[this.position];
36678 getSlideAnchor : function(){
36679 return this.sanchors[this.position];
36682 getAlignAdj : function(){
36683 var cm = this.cmargins;
36684 switch(this.position){
36700 getExpandAdj : function(){
36701 var c = this.collapsedEl, cm = this.cmargins;
36702 switch(this.position){
36704 return [-(cm.right+c.getWidth()+cm.left), 0];
36707 return [cm.right+c.getWidth()+cm.left, 0];
36710 return [0, -(cm.top+cm.bottom+c.getHeight())];
36713 return [0, cm.top+cm.bottom+c.getHeight()];
36719 * Ext JS Library 1.1.1
36720 * Copyright(c) 2006-2007, Ext JS, LLC.
36722 * Originally Released Under LGPL - original licence link has changed is not relivant.
36725 * <script type="text/javascript">
36728 * These classes are private internal classes
36730 Roo.bootstrap.layout.Center = function(config){
36731 config.region = "center";
36732 Roo.bootstrap.layout.Region.call(this, config);
36733 this.visible = true;
36734 this.minWidth = config.minWidth || 20;
36735 this.minHeight = config.minHeight || 20;
36738 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36740 // center panel can't be hidden
36744 // center panel can't be hidden
36747 getMinWidth: function(){
36748 return this.minWidth;
36751 getMinHeight: function(){
36752 return this.minHeight;
36765 Roo.bootstrap.layout.North = function(config)
36767 config.region = 'north';
36768 config.cursor = 'n-resize';
36770 Roo.bootstrap.layout.Split.call(this, config);
36774 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36775 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36776 this.split.el.addClass("roo-layout-split-v");
36778 var size = config.initialSize || config.height;
36779 if(typeof size != "undefined"){
36780 this.el.setHeight(size);
36783 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36785 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36789 getBox : function(){
36790 if(this.collapsed){
36791 return this.collapsedEl.getBox();
36793 var box = this.el.getBox();
36795 box.height += this.split.el.getHeight();
36800 updateBox : function(box){
36801 if(this.split && !this.collapsed){
36802 box.height -= this.split.el.getHeight();
36803 this.split.el.setLeft(box.x);
36804 this.split.el.setTop(box.y+box.height);
36805 this.split.el.setWidth(box.width);
36807 if(this.collapsed){
36808 this.updateBody(box.width, null);
36810 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36818 Roo.bootstrap.layout.South = function(config){
36819 config.region = 'south';
36820 config.cursor = 's-resize';
36821 Roo.bootstrap.layout.Split.call(this, config);
36823 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36824 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36825 this.split.el.addClass("roo-layout-split-v");
36827 var size = config.initialSize || config.height;
36828 if(typeof size != "undefined"){
36829 this.el.setHeight(size);
36833 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36834 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36835 getBox : function(){
36836 if(this.collapsed){
36837 return this.collapsedEl.getBox();
36839 var box = this.el.getBox();
36841 var sh = this.split.el.getHeight();
36848 updateBox : function(box){
36849 if(this.split && !this.collapsed){
36850 var sh = this.split.el.getHeight();
36853 this.split.el.setLeft(box.x);
36854 this.split.el.setTop(box.y-sh);
36855 this.split.el.setWidth(box.width);
36857 if(this.collapsed){
36858 this.updateBody(box.width, null);
36860 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36864 Roo.bootstrap.layout.East = function(config){
36865 config.region = "east";
36866 config.cursor = "e-resize";
36867 Roo.bootstrap.layout.Split.call(this, config);
36869 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36870 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36871 this.split.el.addClass("roo-layout-split-h");
36873 var size = config.initialSize || config.width;
36874 if(typeof size != "undefined"){
36875 this.el.setWidth(size);
36878 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36879 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36880 getBox : function(){
36881 if(this.collapsed){
36882 return this.collapsedEl.getBox();
36884 var box = this.el.getBox();
36886 var sw = this.split.el.getWidth();
36893 updateBox : function(box){
36894 if(this.split && !this.collapsed){
36895 var sw = this.split.el.getWidth();
36897 this.split.el.setLeft(box.x);
36898 this.split.el.setTop(box.y);
36899 this.split.el.setHeight(box.height);
36902 if(this.collapsed){
36903 this.updateBody(null, box.height);
36905 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36909 Roo.bootstrap.layout.West = function(config){
36910 config.region = "west";
36911 config.cursor = "w-resize";
36913 Roo.bootstrap.layout.Split.call(this, config);
36915 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36916 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36917 this.split.el.addClass("roo-layout-split-h");
36921 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36922 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36924 onRender: function(ctr, pos)
36926 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36927 var size = this.config.initialSize || this.config.width;
36928 if(typeof size != "undefined"){
36929 this.el.setWidth(size);
36933 getBox : function(){
36934 if(this.collapsed){
36935 return this.collapsedEl.getBox();
36937 var box = this.el.getBox();
36939 box.width += this.split.el.getWidth();
36944 updateBox : function(box){
36945 if(this.split && !this.collapsed){
36946 var sw = this.split.el.getWidth();
36948 this.split.el.setLeft(box.x+box.width);
36949 this.split.el.setTop(box.y);
36950 this.split.el.setHeight(box.height);
36952 if(this.collapsed){
36953 this.updateBody(null, box.height);
36955 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36958 Roo.namespace("Roo.bootstrap.panel");/*
36960 * Ext JS Library 1.1.1
36961 * Copyright(c) 2006-2007, Ext JS, LLC.
36963 * Originally Released Under LGPL - original licence link has changed is not relivant.
36966 * <script type="text/javascript">
36969 * @class Roo.ContentPanel
36970 * @extends Roo.util.Observable
36971 * A basic ContentPanel element.
36972 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36973 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36974 * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
36975 * @cfg {Boolean} closable True if the panel can be closed/removed
36976 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36977 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36978 * @cfg {Toolbar} toolbar A toolbar for this panel
36979 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36980 * @cfg {String} title The title for this panel
36981 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36982 * @cfg {String} url Calls {@link #setUrl} with this value
36983 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36984 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36985 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36986 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36987 * @cfg {Boolean} badges render the badges
36990 * Create a new ContentPanel.
36991 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36992 * @param {String/Object} config A string to set only the title or a config object
36993 * @param {String} content (optional) Set the HTML content for this panel
36994 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36996 Roo.bootstrap.panel.Content = function( config){
36998 this.tpl = config.tpl || false;
37000 var el = config.el;
37001 var content = config.content;
37003 if(config.autoCreate){ // xtype is available if this is called from factory
37006 this.el = Roo.get(el);
37007 if(!this.el && config && config.autoCreate){
37008 if(typeof config.autoCreate == "object"){
37009 if(!config.autoCreate.id){
37010 config.autoCreate.id = config.id||el;
37012 this.el = Roo.DomHelper.append(document.body,
37013 config.autoCreate, true);
37015 var elcfg = { tag: "div",
37016 cls: "roo-layout-inactive-content",
37020 elcfg.html = config.html;
37024 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37027 this.closable = false;
37028 this.loaded = false;
37029 this.active = false;
37032 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37034 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37036 this.wrapEl = this.el; //this.el.wrap();
37038 if (config.toolbar.items) {
37039 ti = config.toolbar.items ;
37040 delete config.toolbar.items ;
37044 this.toolbar.render(this.wrapEl, 'before');
37045 for(var i =0;i < ti.length;i++) {
37046 // Roo.log(['add child', items[i]]);
37047 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37049 this.toolbar.items = nitems;
37050 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37051 delete config.toolbar;
37055 // xtype created footer. - not sure if will work as we normally have to render first..
37056 if (this.footer && !this.footer.el && this.footer.xtype) {
37057 if (!this.wrapEl) {
37058 this.wrapEl = this.el.wrap();
37061 this.footer.container = this.wrapEl.createChild();
37063 this.footer = Roo.factory(this.footer, Roo);
37068 if(typeof config == "string"){
37069 this.title = config;
37071 Roo.apply(this, config);
37075 this.resizeEl = Roo.get(this.resizeEl, true);
37077 this.resizeEl = this.el;
37079 // handle view.xtype
37087 * Fires when this panel is activated.
37088 * @param {Roo.ContentPanel} this
37092 * @event deactivate
37093 * Fires when this panel is activated.
37094 * @param {Roo.ContentPanel} this
37096 "deactivate" : true,
37100 * Fires when this panel is resized if fitToFrame is true.
37101 * @param {Roo.ContentPanel} this
37102 * @param {Number} width The width after any component adjustments
37103 * @param {Number} height The height after any component adjustments
37109 * Fires when this tab is created
37110 * @param {Roo.ContentPanel} this
37121 if(this.autoScroll){
37122 this.resizeEl.setStyle("overflow", "auto");
37124 // fix randome scrolling
37125 //this.el.on('scroll', function() {
37126 // Roo.log('fix random scolling');
37127 // this.scrollTo('top',0);
37130 content = content || this.content;
37132 this.setContent(content);
37134 if(config && config.url){
37135 this.setUrl(this.url, this.params, this.loadOnce);
37140 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37142 if (this.view && typeof(this.view.xtype) != 'undefined') {
37143 this.view.el = this.el.appendChild(document.createElement("div"));
37144 this.view = Roo.factory(this.view);
37145 this.view.render && this.view.render(false, '');
37149 this.fireEvent('render', this);
37152 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37156 setRegion : function(region){
37157 this.region = region;
37158 this.setActiveClass(region && !this.background);
37162 setActiveClass: function(state)
37165 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37166 this.el.setStyle('position','relative');
37168 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37169 this.el.setStyle('position', 'absolute');
37174 * Returns the toolbar for this Panel if one was configured.
37175 * @return {Roo.Toolbar}
37177 getToolbar : function(){
37178 return this.toolbar;
37181 setActiveState : function(active)
37183 this.active = active;
37184 this.setActiveClass(active);
37186 if(this.fireEvent("deactivate", this) === false){
37191 this.fireEvent("activate", this);
37195 * Updates this panel's element
37196 * @param {String} content The new content
37197 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37199 setContent : function(content, loadScripts){
37200 this.el.update(content, loadScripts);
37203 ignoreResize : function(w, h){
37204 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37207 this.lastSize = {width: w, height: h};
37212 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37213 * @return {Roo.UpdateManager} The UpdateManager
37215 getUpdateManager : function(){
37216 return this.el.getUpdateManager();
37219 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37220 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
37223 url: "your-url.php",
37224 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37225 callback: yourFunction,
37226 scope: yourObject, //(optional scope)
37229 text: "Loading...",
37234 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37235 * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
37236 * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
37237 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37238 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
37239 * @return {Roo.ContentPanel} this
37242 var um = this.el.getUpdateManager();
37243 um.update.apply(um, arguments);
37249 * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
37250 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37251 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
37252 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
37253 * @return {Roo.UpdateManager} The UpdateManager
37255 setUrl : function(url, params, loadOnce){
37256 if(this.refreshDelegate){
37257 this.removeListener("activate", this.refreshDelegate);
37259 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37260 this.on("activate", this.refreshDelegate);
37261 return this.el.getUpdateManager();
37264 _handleRefresh : function(url, params, loadOnce){
37265 if(!loadOnce || !this.loaded){
37266 var updater = this.el.getUpdateManager();
37267 updater.update(url, params, this._setLoaded.createDelegate(this));
37271 _setLoaded : function(){
37272 this.loaded = true;
37276 * Returns this panel's id
37279 getId : function(){
37284 * Returns this panel's element - used by regiosn to add.
37285 * @return {Roo.Element}
37287 getEl : function(){
37288 return this.wrapEl || this.el;
37293 adjustForComponents : function(width, height)
37295 //Roo.log('adjustForComponents ');
37296 if(this.resizeEl != this.el){
37297 width -= this.el.getFrameWidth('lr');
37298 height -= this.el.getFrameWidth('tb');
37301 var te = this.toolbar.getEl();
37302 te.setWidth(width);
37303 height -= te.getHeight();
37306 var te = this.footer.getEl();
37307 te.setWidth(width);
37308 height -= te.getHeight();
37312 if(this.adjustments){
37313 width += this.adjustments[0];
37314 height += this.adjustments[1];
37316 return {"width": width, "height": height};
37319 setSize : function(width, height){
37320 if(this.fitToFrame && !this.ignoreResize(width, height)){
37321 if(this.fitContainer && this.resizeEl != this.el){
37322 this.el.setSize(width, height);
37324 var size = this.adjustForComponents(width, height);
37325 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37326 this.fireEvent('resize', this, size.width, size.height);
37331 * Returns this panel's title
37334 getTitle : function(){
37336 if (typeof(this.title) != 'object') {
37341 for (var k in this.title) {
37342 if (!this.title.hasOwnProperty(k)) {
37346 if (k.indexOf('-') >= 0) {
37347 var s = k.split('-');
37348 for (var i = 0; i<s.length; i++) {
37349 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37352 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37359 * Set this panel's title
37360 * @param {String} title
37362 setTitle : function(title){
37363 this.title = title;
37365 this.region.updatePanelTitle(this, title);
37370 * Returns true is this panel was configured to be closable
37371 * @return {Boolean}
37373 isClosable : function(){
37374 return this.closable;
37377 beforeSlide : function(){
37379 this.resizeEl.clip();
37382 afterSlide : function(){
37384 this.resizeEl.unclip();
37388 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37389 * Will fail silently if the {@link #setUrl} method has not been called.
37390 * This does not activate the panel, just updates its content.
37392 refresh : function(){
37393 if(this.refreshDelegate){
37394 this.loaded = false;
37395 this.refreshDelegate();
37400 * Destroys this panel
37402 destroy : function(){
37403 this.el.removeAllListeners();
37404 var tempEl = document.createElement("span");
37405 tempEl.appendChild(this.el.dom);
37406 tempEl.innerHTML = "";
37412 * form - if the content panel contains a form - this is a reference to it.
37413 * @type {Roo.form.Form}
37417 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37418 * This contains a reference to it.
37424 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37434 * @param {Object} cfg Xtype definition of item to add.
37438 getChildContainer: function () {
37439 return this.getEl();
37444 var ret = new Roo.factory(cfg);
37449 if (cfg.xtype.match(/^Form$/)) {
37452 //if (this.footer) {
37453 // el = this.footer.container.insertSibling(false, 'before');
37455 el = this.el.createChild();
37458 this.form = new Roo.form.Form(cfg);
37461 if ( this.form.allItems.length) {
37462 this.form.render(el.dom);
37466 // should only have one of theses..
37467 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37468 // views.. should not be just added - used named prop 'view''
37470 cfg.el = this.el.appendChild(document.createElement("div"));
37473 var ret = new Roo.factory(cfg);
37475 ret.render && ret.render(false, ''); // render blank..
37485 * @class Roo.bootstrap.panel.Grid
37486 * @extends Roo.bootstrap.panel.Content
37488 * Create a new GridPanel.
37489 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37490 * @param {Object} config A the config object
37496 Roo.bootstrap.panel.Grid = function(config)
37500 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37501 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37503 config.el = this.wrapper;
37504 //this.el = this.wrapper;
37506 if (config.container) {
37507 // ctor'ed from a Border/panel.grid
37510 this.wrapper.setStyle("overflow", "hidden");
37511 this.wrapper.addClass('roo-grid-container');
37516 if(config.toolbar){
37517 var tool_el = this.wrapper.createChild();
37518 this.toolbar = Roo.factory(config.toolbar);
37520 if (config.toolbar.items) {
37521 ti = config.toolbar.items ;
37522 delete config.toolbar.items ;
37526 this.toolbar.render(tool_el);
37527 for(var i =0;i < ti.length;i++) {
37528 // Roo.log(['add child', items[i]]);
37529 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37531 this.toolbar.items = nitems;
37533 delete config.toolbar;
37536 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37537 config.grid.scrollBody = true;;
37538 config.grid.monitorWindowResize = false; // turn off autosizing
37539 config.grid.autoHeight = false;
37540 config.grid.autoWidth = false;
37542 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37544 if (config.background) {
37545 // render grid on panel activation (if panel background)
37546 this.on('activate', function(gp) {
37547 if (!gp.grid.rendered) {
37548 gp.grid.render(this.wrapper);
37549 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37554 this.grid.render(this.wrapper);
37555 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37558 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37559 // ??? needed ??? config.el = this.wrapper;
37564 // xtype created footer. - not sure if will work as we normally have to render first..
37565 if (this.footer && !this.footer.el && this.footer.xtype) {
37567 var ctr = this.grid.getView().getFooterPanel(true);
37568 this.footer.dataSource = this.grid.dataSource;
37569 this.footer = Roo.factory(this.footer, Roo);
37570 this.footer.render(ctr);
37580 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37581 getId : function(){
37582 return this.grid.id;
37586 * Returns the grid for this panel
37587 * @return {Roo.bootstrap.Table}
37589 getGrid : function(){
37593 setSize : function(width, height){
37594 if(!this.ignoreResize(width, height)){
37595 var grid = this.grid;
37596 var size = this.adjustForComponents(width, height);
37597 var gridel = grid.getGridEl();
37598 gridel.setSize(size.width, size.height);
37600 var thd = grid.getGridEl().select('thead',true).first();
37601 var tbd = grid.getGridEl().select('tbody', true).first();
37603 tbd.setSize(width, height - thd.getHeight());
37612 beforeSlide : function(){
37613 this.grid.getView().scroller.clip();
37616 afterSlide : function(){
37617 this.grid.getView().scroller.unclip();
37620 destroy : function(){
37621 this.grid.destroy();
37623 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37628 * @class Roo.bootstrap.panel.Nest
37629 * @extends Roo.bootstrap.panel.Content
37631 * Create a new Panel, that can contain a layout.Border.
37634 * @param {Roo.BorderLayout} layout The layout for this panel
37635 * @param {String/Object} config A string to set only the title or a config object
37637 Roo.bootstrap.panel.Nest = function(config)
37639 // construct with only one argument..
37640 /* FIXME - implement nicer consturctors
37641 if (layout.layout) {
37643 layout = config.layout;
37644 delete config.layout;
37646 if (layout.xtype && !layout.getEl) {
37647 // then layout needs constructing..
37648 layout = Roo.factory(layout, Roo);
37652 config.el = config.layout.getEl();
37654 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37656 config.layout.monitorWindowResize = false; // turn off autosizing
37657 this.layout = config.layout;
37658 this.layout.getEl().addClass("roo-layout-nested-layout");
37665 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37667 setSize : function(width, height){
37668 if(!this.ignoreResize(width, height)){
37669 var size = this.adjustForComponents(width, height);
37670 var el = this.layout.getEl();
37671 if (size.height < 1) {
37672 el.setWidth(size.width);
37674 el.setSize(size.width, size.height);
37676 var touch = el.dom.offsetWidth;
37677 this.layout.layout();
37678 // ie requires a double layout on the first pass
37679 if(Roo.isIE && !this.initialized){
37680 this.initialized = true;
37681 this.layout.layout();
37686 // activate all subpanels if not currently active..
37688 setActiveState : function(active){
37689 this.active = active;
37690 this.setActiveClass(active);
37693 this.fireEvent("deactivate", this);
37697 this.fireEvent("activate", this);
37698 // not sure if this should happen before or after..
37699 if (!this.layout) {
37700 return; // should not happen..
37703 for (var r in this.layout.regions) {
37704 reg = this.layout.getRegion(r);
37705 if (reg.getActivePanel()) {
37706 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37707 reg.setActivePanel(reg.getActivePanel());
37710 if (!reg.panels.length) {
37713 reg.showPanel(reg.getPanel(0));
37722 * Returns the nested BorderLayout for this panel
37723 * @return {Roo.BorderLayout}
37725 getLayout : function(){
37726 return this.layout;
37730 * Adds a xtype elements to the layout of the nested panel
37734 xtype : 'ContentPanel',
37741 xtype : 'NestedLayoutPanel',
37747 items : [ ... list of content panels or nested layout panels.. ]
37751 * @param {Object} cfg Xtype definition of item to add.
37753 addxtype : function(cfg) {
37754 return this.layout.addxtype(cfg);
37759 * Ext JS Library 1.1.1
37760 * Copyright(c) 2006-2007, Ext JS, LLC.
37762 * Originally Released Under LGPL - original licence link has changed is not relivant.
37765 * <script type="text/javascript">
37768 * @class Roo.TabPanel
37769 * @extends Roo.util.Observable
37770 * A lightweight tab container.
37774 // basic tabs 1, built from existing content
37775 var tabs = new Roo.TabPanel("tabs1");
37776 tabs.addTab("script", "View Script");
37777 tabs.addTab("markup", "View Markup");
37778 tabs.activate("script");
37780 // more advanced tabs, built from javascript
37781 var jtabs = new Roo.TabPanel("jtabs");
37782 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37784 // set up the UpdateManager
37785 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37786 var updater = tab2.getUpdateManager();
37787 updater.setDefaultUrl("ajax1.htm");
37788 tab2.on('activate', updater.refresh, updater, true);
37790 // Use setUrl for Ajax loading
37791 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37792 tab3.setUrl("ajax2.htm", null, true);
37795 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37798 jtabs.activate("jtabs-1");
37801 * Create a new TabPanel.
37802 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37803 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37805 Roo.bootstrap.panel.Tabs = function(config){
37807 * The container element for this TabPanel.
37808 * @type Roo.Element
37810 this.el = Roo.get(config.el);
37813 if(typeof config == "boolean"){
37814 this.tabPosition = config ? "bottom" : "top";
37816 Roo.apply(this, config);
37820 if(this.tabPosition == "bottom"){
37821 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37822 this.el.addClass("roo-tabs-bottom");
37824 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37825 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37826 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37828 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37830 if(this.tabPosition != "bottom"){
37831 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37832 * @type Roo.Element
37834 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37835 this.el.addClass("roo-tabs-top");
37839 this.bodyEl.setStyle("position", "relative");
37841 this.active = null;
37842 this.activateDelegate = this.activate.createDelegate(this);
37847 * Fires when the active tab changes
37848 * @param {Roo.TabPanel} this
37849 * @param {Roo.TabPanelItem} activePanel The new active tab
37853 * @event beforetabchange
37854 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37855 * @param {Roo.TabPanel} this
37856 * @param {Object} e Set cancel to true on this object to cancel the tab change
37857 * @param {Roo.TabPanelItem} tab The tab being changed to
37859 "beforetabchange" : true
37862 Roo.EventManager.onWindowResize(this.onResize, this);
37863 this.cpad = this.el.getPadding("lr");
37864 this.hiddenCount = 0;
37867 // toolbar on the tabbar support...
37868 if (this.toolbar) {
37869 alert("no toolbar support yet");
37870 this.toolbar = false;
37872 var tcfg = this.toolbar;
37873 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37874 this.toolbar = new Roo.Toolbar(tcfg);
37875 if (Roo.isSafari) {
37876 var tbl = tcfg.container.child('table', true);
37877 tbl.setAttribute('width', '100%');
37885 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37888 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37890 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37892 tabPosition : "top",
37894 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37896 currentTabWidth : 0,
37898 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37902 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37906 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37908 preferredTabWidth : 175,
37910 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37912 resizeTabs : false,
37914 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37916 monitorResize : true,
37918 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37923 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37924 * @param {String} id The id of the div to use <b>or create</b>
37925 * @param {String} text The text for the tab
37926 * @param {String} content (optional) Content to put in the TabPanelItem body
37927 * @param {Boolean} closable (optional) True to create a close icon on the tab
37928 * @return {Roo.TabPanelItem} The created TabPanelItem
37930 addTab : function(id, text, content, closable, tpl)
37932 var item = new Roo.bootstrap.panel.TabItem({
37936 closable : closable,
37939 this.addTabItem(item);
37941 item.setContent(content);
37947 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37948 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37949 * @return {Roo.TabPanelItem}
37951 getTab : function(id){
37952 return this.items[id];
37956 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37957 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37959 hideTab : function(id){
37960 var t = this.items[id];
37963 this.hiddenCount++;
37964 this.autoSizeTabs();
37969 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37970 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37972 unhideTab : function(id){
37973 var t = this.items[id];
37975 t.setHidden(false);
37976 this.hiddenCount--;
37977 this.autoSizeTabs();
37982 * Adds an existing {@link Roo.TabPanelItem}.
37983 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37985 addTabItem : function(item){
37986 this.items[item.id] = item;
37987 this.items.push(item);
37988 // if(this.resizeTabs){
37989 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37990 // this.autoSizeTabs();
37992 // item.autoSize();
37997 * Removes a {@link Roo.TabPanelItem}.
37998 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38000 removeTab : function(id){
38001 var items = this.items;
38002 var tab = items[id];
38003 if(!tab) { return; }
38004 var index = items.indexOf(tab);
38005 if(this.active == tab && items.length > 1){
38006 var newTab = this.getNextAvailable(index);
38011 this.stripEl.dom.removeChild(tab.pnode.dom);
38012 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38013 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38015 items.splice(index, 1);
38016 delete this.items[tab.id];
38017 tab.fireEvent("close", tab);
38018 tab.purgeListeners();
38019 this.autoSizeTabs();
38022 getNextAvailable : function(start){
38023 var items = this.items;
38025 // look for a next tab that will slide over to
38026 // replace the one being removed
38027 while(index < items.length){
38028 var item = items[++index];
38029 if(item && !item.isHidden()){
38033 // if one isn't found select the previous tab (on the left)
38036 var item = items[--index];
38037 if(item && !item.isHidden()){
38045 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38046 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38048 disableTab : function(id){
38049 var tab = this.items[id];
38050 if(tab && this.active != tab){
38056 * Enables a {@link Roo.TabPanelItem} that is disabled.
38057 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38059 enableTab : function(id){
38060 var tab = this.items[id];
38065 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38066 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38067 * @return {Roo.TabPanelItem} The TabPanelItem.
38069 activate : function(id){
38070 var tab = this.items[id];
38074 if(tab == this.active || tab.disabled){
38078 this.fireEvent("beforetabchange", this, e, tab);
38079 if(e.cancel !== true && !tab.disabled){
38081 this.active.hide();
38083 this.active = this.items[id];
38084 this.active.show();
38085 this.fireEvent("tabchange", this, this.active);
38091 * Gets the active {@link Roo.TabPanelItem}.
38092 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38094 getActiveTab : function(){
38095 return this.active;
38099 * Updates the tab body element to fit the height of the container element
38100 * for overflow scrolling
38101 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38103 syncHeight : function(targetHeight){
38104 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38105 var bm = this.bodyEl.getMargins();
38106 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38107 this.bodyEl.setHeight(newHeight);
38111 onResize : function(){
38112 if(this.monitorResize){
38113 this.autoSizeTabs();
38118 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38120 beginUpdate : function(){
38121 this.updating = true;
38125 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38127 endUpdate : function(){
38128 this.updating = false;
38129 this.autoSizeTabs();
38133 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38135 autoSizeTabs : function(){
38136 var count = this.items.length;
38137 var vcount = count - this.hiddenCount;
38138 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38141 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38142 var availWidth = Math.floor(w / vcount);
38143 var b = this.stripBody;
38144 if(b.getWidth() > w){
38145 var tabs = this.items;
38146 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38147 if(availWidth < this.minTabWidth){
38148 /*if(!this.sleft){ // incomplete scrolling code
38149 this.createScrollButtons();
38152 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38155 if(this.currentTabWidth < this.preferredTabWidth){
38156 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38162 * Returns the number of tabs in this TabPanel.
38165 getCount : function(){
38166 return this.items.length;
38170 * Resizes all the tabs to the passed width
38171 * @param {Number} The new width
38173 setTabWidth : function(width){
38174 this.currentTabWidth = width;
38175 for(var i = 0, len = this.items.length; i < len; i++) {
38176 if(!this.items[i].isHidden()) {
38177 this.items[i].setWidth(width);
38183 * Destroys this TabPanel
38184 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38186 destroy : function(removeEl){
38187 Roo.EventManager.removeResizeListener(this.onResize, this);
38188 for(var i = 0, len = this.items.length; i < len; i++){
38189 this.items[i].purgeListeners();
38191 if(removeEl === true){
38192 this.el.update("");
38197 createStrip : function(container)
38199 var strip = document.createElement("nav");
38200 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38201 container.appendChild(strip);
38205 createStripList : function(strip)
38207 // div wrapper for retard IE
38208 // returns the "tr" element.
38209 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38210 //'<div class="x-tabs-strip-wrap">'+
38211 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38212 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38213 return strip.firstChild; //.firstChild.firstChild.firstChild;
38215 createBody : function(container)
38217 var body = document.createElement("div");
38218 Roo.id(body, "tab-body");
38219 //Roo.fly(body).addClass("x-tabs-body");
38220 Roo.fly(body).addClass("tab-content");
38221 container.appendChild(body);
38224 createItemBody :function(bodyEl, id){
38225 var body = Roo.getDom(id);
38227 body = document.createElement("div");
38230 //Roo.fly(body).addClass("x-tabs-item-body");
38231 Roo.fly(body).addClass("tab-pane");
38232 bodyEl.insertBefore(body, bodyEl.firstChild);
38236 createStripElements : function(stripEl, text, closable, tpl)
38238 var td = document.createElement("li"); // was td..
38241 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38244 stripEl.appendChild(td);
38246 td.className = "x-tabs-closable";
38247 if(!this.closeTpl){
38248 this.closeTpl = new Roo.Template(
38249 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38250 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38251 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38254 var el = this.closeTpl.overwrite(td, {"text": text});
38255 var close = el.getElementsByTagName("div")[0];
38256 var inner = el.getElementsByTagName("em")[0];
38257 return {"el": el, "close": close, "inner": inner};
38260 // not sure what this is..
38261 // if(!this.tabTpl){
38262 //this.tabTpl = new Roo.Template(
38263 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38264 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38266 // this.tabTpl = new Roo.Template(
38267 // '<a href="#">' +
38268 // '<span unselectable="on"' +
38269 // (this.disableTooltips ? '' : ' title="{text}"') +
38270 // ' >{text}</span></a>'
38276 var template = tpl || this.tabTpl || false;
38280 template = new Roo.Template(
38282 '<span unselectable="on"' +
38283 (this.disableTooltips ? '' : ' title="{text}"') +
38284 ' >{text}</span></a>'
38288 switch (typeof(template)) {
38292 template = new Roo.Template(template);
38298 var el = template.overwrite(td, {"text": text});
38300 var inner = el.getElementsByTagName("span")[0];
38302 return {"el": el, "inner": inner};
38310 * @class Roo.TabPanelItem
38311 * @extends Roo.util.Observable
38312 * Represents an individual item (tab plus body) in a TabPanel.
38313 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38314 * @param {String} id The id of this TabPanelItem
38315 * @param {String} text The text for the tab of this TabPanelItem
38316 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38318 Roo.bootstrap.panel.TabItem = function(config){
38320 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38321 * @type Roo.TabPanel
38323 this.tabPanel = config.panel;
38325 * The id for this TabPanelItem
38328 this.id = config.id;
38330 this.disabled = false;
38332 this.text = config.text;
38334 this.loaded = false;
38335 this.closable = config.closable;
38338 * The body element for this TabPanelItem.
38339 * @type Roo.Element
38341 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38342 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38343 this.bodyEl.setStyle("display", "block");
38344 this.bodyEl.setStyle("zoom", "1");
38345 //this.hideAction();
38347 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38349 this.el = Roo.get(els.el);
38350 this.inner = Roo.get(els.inner, true);
38351 this.textEl = Roo.get(this.el.dom.firstChild, true);
38352 this.pnode = Roo.get(els.el.parentNode, true);
38353 // this.el.on("mousedown", this.onTabMouseDown, this);
38354 this.el.on("click", this.onTabClick, this);
38356 if(config.closable){
38357 var c = Roo.get(els.close, true);
38358 c.dom.title = this.closeText;
38359 c.addClassOnOver("close-over");
38360 c.on("click", this.closeClick, this);
38366 * Fires when this tab becomes the active tab.
38367 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38368 * @param {Roo.TabPanelItem} this
38372 * @event beforeclose
38373 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38374 * @param {Roo.TabPanelItem} this
38375 * @param {Object} e Set cancel to true on this object to cancel the close.
38377 "beforeclose": true,
38380 * Fires when this tab is closed.
38381 * @param {Roo.TabPanelItem} this
38385 * @event deactivate
38386 * Fires when this tab is no longer the active tab.
38387 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38388 * @param {Roo.TabPanelItem} this
38390 "deactivate" : true
38392 this.hidden = false;
38394 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38397 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38399 purgeListeners : function(){
38400 Roo.util.Observable.prototype.purgeListeners.call(this);
38401 this.el.removeAllListeners();
38404 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38407 this.pnode.addClass("active");
38410 this.tabPanel.stripWrap.repaint();
38412 this.fireEvent("activate", this.tabPanel, this);
38416 * Returns true if this tab is the active tab.
38417 * @return {Boolean}
38419 isActive : function(){
38420 return this.tabPanel.getActiveTab() == this;
38424 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38427 this.pnode.removeClass("active");
38429 this.fireEvent("deactivate", this.tabPanel, this);
38432 hideAction : function(){
38433 this.bodyEl.hide();
38434 this.bodyEl.setStyle("position", "absolute");
38435 this.bodyEl.setLeft("-20000px");
38436 this.bodyEl.setTop("-20000px");
38439 showAction : function(){
38440 this.bodyEl.setStyle("position", "relative");
38441 this.bodyEl.setTop("");
38442 this.bodyEl.setLeft("");
38443 this.bodyEl.show();
38447 * Set the tooltip for the tab.
38448 * @param {String} tooltip The tab's tooltip
38450 setTooltip : function(text){
38451 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38452 this.textEl.dom.qtip = text;
38453 this.textEl.dom.removeAttribute('title');
38455 this.textEl.dom.title = text;
38459 onTabClick : function(e){
38460 e.preventDefault();
38461 this.tabPanel.activate(this.id);
38464 onTabMouseDown : function(e){
38465 e.preventDefault();
38466 this.tabPanel.activate(this.id);
38469 getWidth : function(){
38470 return this.inner.getWidth();
38473 setWidth : function(width){
38474 var iwidth = width - this.pnode.getPadding("lr");
38475 this.inner.setWidth(iwidth);
38476 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38477 this.pnode.setWidth(width);
38481 * Show or hide the tab
38482 * @param {Boolean} hidden True to hide or false to show.
38484 setHidden : function(hidden){
38485 this.hidden = hidden;
38486 this.pnode.setStyle("display", hidden ? "none" : "");
38490 * Returns true if this tab is "hidden"
38491 * @return {Boolean}
38493 isHidden : function(){
38494 return this.hidden;
38498 * Returns the text for this tab
38501 getText : function(){
38505 autoSize : function(){
38506 //this.el.beginMeasure();
38507 this.textEl.setWidth(1);
38509 * #2804 [new] Tabs in Roojs
38510 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38512 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38513 //this.el.endMeasure();
38517 * Sets the text for the tab (Note: this also sets the tooltip text)
38518 * @param {String} text The tab's text and tooltip
38520 setText : function(text){
38522 this.textEl.update(text);
38523 this.setTooltip(text);
38524 //if(!this.tabPanel.resizeTabs){
38525 // this.autoSize();
38529 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38531 activate : function(){
38532 this.tabPanel.activate(this.id);
38536 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38538 disable : function(){
38539 if(this.tabPanel.active != this){
38540 this.disabled = true;
38541 this.pnode.addClass("disabled");
38546 * Enables this TabPanelItem if it was previously disabled.
38548 enable : function(){
38549 this.disabled = false;
38550 this.pnode.removeClass("disabled");
38554 * Sets the content for this TabPanelItem.
38555 * @param {String} content The content
38556 * @param {Boolean} loadScripts true to look for and load scripts
38558 setContent : function(content, loadScripts){
38559 this.bodyEl.update(content, loadScripts);
38563 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38564 * @return {Roo.UpdateManager} The UpdateManager
38566 getUpdateManager : function(){
38567 return this.bodyEl.getUpdateManager();
38571 * Set a URL to be used to load the content for this TabPanelItem.
38572 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38573 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
38574 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
38575 * @return {Roo.UpdateManager} The UpdateManager
38577 setUrl : function(url, params, loadOnce){
38578 if(this.refreshDelegate){
38579 this.un('activate', this.refreshDelegate);
38581 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38582 this.on("activate", this.refreshDelegate);
38583 return this.bodyEl.getUpdateManager();
38587 _handleRefresh : function(url, params, loadOnce){
38588 if(!loadOnce || !this.loaded){
38589 var updater = this.bodyEl.getUpdateManager();
38590 updater.update(url, params, this._setLoaded.createDelegate(this));
38595 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38596 * Will fail silently if the setUrl method has not been called.
38597 * This does not activate the panel, just updates its content.
38599 refresh : function(){
38600 if(this.refreshDelegate){
38601 this.loaded = false;
38602 this.refreshDelegate();
38607 _setLoaded : function(){
38608 this.loaded = true;
38612 closeClick : function(e){
38615 this.fireEvent("beforeclose", this, o);
38616 if(o.cancel !== true){
38617 this.tabPanel.removeTab(this.id);
38621 * The text displayed in the tooltip for the close icon.
38624 closeText : "Close this tab"
38627 * This script refer to:
38628 * Title: International Telephone Input
38629 * Author: Jack O'Connor
38630 * Code version: v12.1.12
38631 * Availability: https://github.com/jackocnr/intl-tel-input.git
38634 Roo.bootstrap.PhoneInputData = function() {
38637 "Afghanistan (افغانستان)",
38642 "Albania (Shqipëri)",
38647 "Algeria (الجزائر)",
38672 "Antigua and Barbuda",
38682 "Armenia (Հայաստան)",
38698 "Austria (Österreich)",
38703 "Azerbaijan (Azərbaycan)",
38713 "Bahrain (البحرين)",
38718 "Bangladesh (বাংলাদেশ)",
38728 "Belarus (Беларусь)",
38733 "Belgium (België)",
38763 "Bosnia and Herzegovina (Босна и Херцеговина)",
38778 "British Indian Ocean Territory",
38783 "British Virgin Islands",
38793 "Bulgaria (България)",
38803 "Burundi (Uburundi)",
38808 "Cambodia (កម្ពុជា)",
38813 "Cameroon (Cameroun)",
38822 ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
38825 "Cape Verde (Kabu Verdi)",
38830 "Caribbean Netherlands",
38841 "Central African Republic (République centrafricaine)",
38861 "Christmas Island",
38867 "Cocos (Keeling) Islands",
38878 "Comoros (جزر القمر)",
38883 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38888 "Congo (Republic) (Congo-Brazzaville)",
38908 "Croatia (Hrvatska)",
38929 "Czech Republic (Česká republika)",
38934 "Denmark (Danmark)",
38949 "Dominican Republic (República Dominicana)",
38953 ["809", "829", "849"]
38971 "Equatorial Guinea (Guinea Ecuatorial)",
38991 "Falkland Islands (Islas Malvinas)",
38996 "Faroe Islands (Føroyar)",
39017 "French Guiana (Guyane française)",
39022 "French Polynesia (Polynésie française)",
39037 "Georgia (საქართველო)",
39042 "Germany (Deutschland)",
39062 "Greenland (Kalaallit Nunaat)",
39099 "Guinea-Bissau (Guiné Bissau)",
39124 "Hungary (Magyarország)",
39129 "Iceland (Ísland)",
39149 "Iraq (العراق)",
39165 "Israel (ישראל)",
39192 "Jordan (الأردن)",
39197 "Kazakhstan (Казахстан)",
39218 "Kuwait (الكويت)",
39223 "Kyrgyzstan (Кыргызстан)",
39233 "Latvia (Latvija)",
39238 "Lebanon (لبنان)",
39253 "Libya (ليبيا)",
39263 "Lithuania (Lietuva)",
39278 "Macedonia (FYROM) (Македонија)",
39283 "Madagascar (Madagasikara)",
39313 "Marshall Islands",
39323 "Mauritania (موريتانيا)",
39328 "Mauritius (Moris)",
39349 "Moldova (Republica Moldova)",
39359 "Mongolia (Монгол)",
39364 "Montenegro (Crna Gora)",
39374 "Morocco (المغرب)",
39380 "Mozambique (Moçambique)",
39385 "Myanmar (Burma) (မြန်မာ)",
39390 "Namibia (Namibië)",
39405 "Netherlands (Nederland)",
39410 "New Caledonia (Nouvelle-Calédonie)",
39445 "North Korea (조선 민주주의 인민 공화국)",
39450 "Northern Mariana Islands",
39466 "Pakistan (پاکستان)",
39476 "Palestine (فلسطين)",
39486 "Papua New Guinea",
39528 "Réunion (La Réunion)",
39534 "Romania (România)",
39550 "Saint Barthélemy",
39561 "Saint Kitts and Nevis",
39571 "Saint Martin (Saint-Martin (partie française))",
39577 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39582 "Saint Vincent and the Grenadines",
39597 "São Tomé and Príncipe (São Tomé e Príncipe)",
39602 "Saudi Arabia (المملكة العربية السعودية)",
39607 "Senegal (Sénégal)",
39637 "Slovakia (Slovensko)",
39642 "Slovenia (Slovenija)",
39652 "Somalia (Soomaaliya)",
39662 "South Korea (대한민국)",
39667 "South Sudan (جنوب السودان)",
39677 "Sri Lanka (ශ්රී ලංකාව)",
39682 "Sudan (السودان)",
39692 "Svalbard and Jan Mayen",
39703 "Sweden (Sverige)",
39708 "Switzerland (Schweiz)",
39713 "Syria (سوريا)",
39758 "Trinidad and Tobago",
39763 "Tunisia (تونس)",
39768 "Turkey (Türkiye)",
39778 "Turks and Caicos Islands",
39788 "U.S. Virgin Islands",
39798 "Ukraine (Україна)",
39803 "United Arab Emirates (الإمارات العربية المتحدة)",
39825 "Uzbekistan (Oʻzbekiston)",
39835 "Vatican City (Città del Vaticano)",
39846 "Vietnam (Việt Nam)",
39851 "Wallis and Futuna (Wallis-et-Futuna)",
39856 "Western Sahara (الصحراء الغربية)",
39862 "Yemen (اليمن)",
39886 * This script refer to:
39887 * Title: International Telephone Input
39888 * Author: Jack O'Connor
39889 * Code version: v12.1.12
39890 * Availability: https://github.com/jackocnr/intl-tel-input.git
39894 * @class Roo.bootstrap.PhoneInput
39895 * @extends Roo.bootstrap.TriggerField
39896 * An input with International dial-code selection
39898 * @cfg {String} defaultDialCode default '+852'
39899 * @cfg {Array} preferedCountries default []
39902 * Create a new PhoneInput.
39903 * @param {Object} config Configuration options
39906 Roo.bootstrap.PhoneInput = function(config) {
39907 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39910 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39912 listWidth: undefined,
39914 selectedClass: 'active',
39916 invalidClass : "has-warning",
39918 validClass: 'has-success',
39920 allowed: '0123456789',
39925 * @cfg {String} defaultDialCode The default dial code when initializing the input
39927 defaultDialCode: '+852',
39930 * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
39932 preferedCountries: false,
39934 getAutoCreate : function()
39936 var data = Roo.bootstrap.PhoneInputData();
39937 var align = this.labelAlign || this.parentLabelAlign();
39940 this.allCountries = [];
39941 this.dialCodeMapping = [];
39943 for (var i = 0; i < data.length; i++) {
39945 this.allCountries[i] = {
39949 priority: c[3] || 0,
39950 areaCodes: c[4] || null
39952 this.dialCodeMapping[c[2]] = {
39955 priority: c[3] || 0,
39956 areaCodes: c[4] || null
39968 // type: 'number', -- do not use number - we get the flaky up/down arrows.
39969 maxlength: this.max_length,
39970 cls : 'form-control tel-input',
39971 autocomplete: 'new-password'
39974 var hiddenInput = {
39977 cls: 'hidden-tel-input'
39981 hiddenInput.name = this.name;
39984 if (this.disabled) {
39985 input.disabled = true;
39988 var flag_container = {
40005 cls: this.hasFeedback ? 'has-feedback' : '',
40011 cls: 'dial-code-holder',
40018 cls: 'roo-select2-container input-group',
40025 if (this.fieldLabel.length) {
40028 tooltip: 'This field is required'
40034 cls: 'control-label',
40040 html: this.fieldLabel
40043 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40049 if(this.indicatorpos == 'right') {
40050 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40057 if(align == 'left') {
40065 if(this.labelWidth > 12){
40066 label.style = "width: " + this.labelWidth + 'px';
40068 if(this.labelWidth < 13 && this.labelmd == 0){
40069 this.labelmd = this.labelWidth;
40071 if(this.labellg > 0){
40072 label.cls += ' col-lg-' + this.labellg;
40073 input.cls += ' col-lg-' + (12 - this.labellg);
40075 if(this.labelmd > 0){
40076 label.cls += ' col-md-' + this.labelmd;
40077 container.cls += ' col-md-' + (12 - this.labelmd);
40079 if(this.labelsm > 0){
40080 label.cls += ' col-sm-' + this.labelsm;
40081 container.cls += ' col-sm-' + (12 - this.labelsm);
40083 if(this.labelxs > 0){
40084 label.cls += ' col-xs-' + this.labelxs;
40085 container.cls += ' col-xs-' + (12 - this.labelxs);
40095 var settings = this;
40097 ['xs','sm','md','lg'].map(function(size){
40098 if (settings[size]) {
40099 cfg.cls += ' col-' + size + '-' + settings[size];
40103 this.store = new Roo.data.Store({
40104 proxy : new Roo.data.MemoryProxy({}),
40105 reader : new Roo.data.JsonReader({
40116 'name' : 'dialCode',
40120 'name' : 'priority',
40124 'name' : 'areaCodes',
40131 if(!this.preferedCountries) {
40132 this.preferedCountries = [
40139 var p = this.preferedCountries.reverse();
40142 for (var i = 0; i < p.length; i++) {
40143 for (var j = 0; j < this.allCountries.length; j++) {
40144 if(this.allCountries[j].iso2 == p[i]) {
40145 var t = this.allCountries[j];
40146 this.allCountries.splice(j,1);
40147 this.allCountries.unshift(t);
40153 this.store.proxy.data = {
40155 data: this.allCountries
40161 initEvents : function()
40164 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40166 this.indicator = this.indicatorEl();
40167 this.flag = this.flagEl();
40168 this.dialCodeHolder = this.dialCodeHolderEl();
40170 this.trigger = this.el.select('div.flag-box',true).first();
40171 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40176 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40177 _this.list.setWidth(lw);
40180 this.list.on('mouseover', this.onViewOver, this);
40181 this.list.on('mousemove', this.onViewMove, this);
40182 this.inputEl().on("keyup", this.onKeyUp, this);
40183 this.inputEl().on("keypress", this.onKeyPress, this);
40185 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40187 this.view = new Roo.View(this.list, this.tpl, {
40188 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40191 this.view.on('click', this.onViewClick, this);
40192 this.setValue(this.defaultDialCode);
40195 onTriggerClick : function(e)
40197 Roo.log('trigger click');
40202 if(this.isExpanded()){
40204 this.hasFocus = false;
40206 this.store.load({});
40207 this.hasFocus = true;
40212 isExpanded : function()
40214 return this.list.isVisible();
40217 collapse : function()
40219 if(!this.isExpanded()){
40223 Roo.get(document).un('mousedown', this.collapseIf, this);
40224 Roo.get(document).un('mousewheel', this.collapseIf, this);
40225 this.fireEvent('collapse', this);
40229 expand : function()
40233 if(this.isExpanded() || !this.hasFocus){
40237 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40238 this.list.setWidth(lw);
40241 this.restrictHeight();
40243 Roo.get(document).on('mousedown', this.collapseIf, this);
40244 Roo.get(document).on('mousewheel', this.collapseIf, this);
40246 this.fireEvent('expand', this);
40249 restrictHeight : function()
40251 this.list.alignTo(this.inputEl(), this.listAlign);
40252 this.list.alignTo(this.inputEl(), this.listAlign);
40255 onViewOver : function(e, t)
40257 if(this.inKeyMode){
40260 var item = this.view.findItemFromChild(t);
40263 var index = this.view.indexOf(item);
40264 this.select(index, false);
40269 onViewClick : function(view, doFocus, el, e)
40271 var index = this.view.getSelectedIndexes()[0];
40273 var r = this.store.getAt(index);
40276 this.onSelect(r, index);
40278 if(doFocus !== false && !this.blockFocus){
40279 this.inputEl().focus();
40283 onViewMove : function(e, t)
40285 this.inKeyMode = false;
40288 select : function(index, scrollIntoView)
40290 this.selectedIndex = index;
40291 this.view.select(index);
40292 if(scrollIntoView !== false){
40293 var el = this.view.getNode(index);
40295 this.list.scrollChildIntoView(el, false);
40300 createList : function()
40302 this.list = Roo.get(document.body).createChild({
40304 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40305 style: 'display:none'
40308 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40311 collapseIf : function(e)
40313 var in_combo = e.within(this.el);
40314 var in_list = e.within(this.list);
40315 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40317 if (in_combo || in_list || is_list) {
40323 onSelect : function(record, index)
40325 if(this.fireEvent('beforeselect', this, record, index) !== false){
40327 this.setFlagClass(record.data.iso2);
40328 this.setDialCode(record.data.dialCode);
40329 this.hasFocus = false;
40331 this.fireEvent('select', this, record, index);
40335 flagEl : function()
40337 var flag = this.el.select('div.flag',true).first();
40344 dialCodeHolderEl : function()
40346 var d = this.el.select('input.dial-code-holder',true).first();
40353 setDialCode : function(v)
40355 this.dialCodeHolder.dom.value = '+'+v;
40358 setFlagClass : function(n)
40360 this.flag.dom.className = 'flag '+n;
40363 getValue : function()
40365 var v = this.inputEl().getValue();
40366 if(this.dialCodeHolder) {
40367 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40372 setValue : function(v)
40374 var d = this.getDialCode(v);
40376 //invalid dial code
40377 if(v.length == 0 || !d || d.length == 0) {
40379 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40380 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40386 this.setFlagClass(this.dialCodeMapping[d].iso2);
40387 this.setDialCode(d);
40388 this.inputEl().dom.value = v.replace('+'+d,'');
40389 this.hiddenEl().dom.value = this.getValue();
40394 getDialCode : function(v)
40398 if (v.length == 0) {
40399 return this.dialCodeHolder.dom.value;
40403 if (v.charAt(0) != "+") {
40406 var numericChars = "";
40407 for (var i = 1; i < v.length; i++) {
40408 var c = v.charAt(i);
40411 if (this.dialCodeMapping[numericChars]) {
40412 dialCode = v.substr(1, i);
40414 if (numericChars.length == 4) {
40424 this.setValue(this.defaultDialCode);
40428 hiddenEl : function()
40430 return this.el.select('input.hidden-tel-input',true).first();
40433 // after setting val
40434 onKeyUp : function(e){
40435 this.setValue(this.getValue());
40438 onKeyPress : function(e){
40439 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40446 * @class Roo.bootstrap.MoneyField
40447 * @extends Roo.bootstrap.ComboBox
40448 * Bootstrap MoneyField class
40451 * Create a new MoneyField.
40452 * @param {Object} config Configuration options
40455 Roo.bootstrap.MoneyField = function(config) {
40457 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40461 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40464 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40466 allowDecimals : true,
40468 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40470 decimalSeparator : ".",
40472 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40474 decimalPrecision : 0,
40476 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40478 allowNegative : true,
40480 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40484 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40486 minValue : Number.NEGATIVE_INFINITY,
40488 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40490 maxValue : Number.MAX_VALUE,
40492 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40494 minText : "The minimum value for this field is {0}",
40496 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40498 maxText : "The maximum value for this field is {0}",
40500 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40501 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40503 nanText : "{0} is not a valid number",
40505 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40509 * @cfg {String} defaults currency of the MoneyField
40510 * value should be in lkey
40512 defaultCurrency : false,
40514 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40516 thousandsDelimiter : false,
40518 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40529 getAutoCreate : function()
40531 var align = this.labelAlign || this.parentLabelAlign();
40543 cls : 'form-control roo-money-amount-input',
40544 autocomplete: 'new-password'
40547 var hiddenInput = {
40551 cls: 'hidden-number-input'
40554 if(this.max_length) {
40555 input.maxlength = this.max_length;
40559 hiddenInput.name = this.name;
40562 if (this.disabled) {
40563 input.disabled = true;
40566 var clg = 12 - this.inputlg;
40567 var cmd = 12 - this.inputmd;
40568 var csm = 12 - this.inputsm;
40569 var cxs = 12 - this.inputxs;
40573 cls : 'row roo-money-field',
40577 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40581 cls: 'roo-select2-container input-group',
40585 cls : 'form-control roo-money-currency-input',
40586 autocomplete: 'new-password',
40588 name : this.currencyName
40592 cls : 'input-group-addon',
40606 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40610 cls: this.hasFeedback ? 'has-feedback' : '',
40621 if (this.fieldLabel.length) {
40624 tooltip: 'This field is required'
40630 cls: 'control-label',
40636 html: this.fieldLabel
40639 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40645 if(this.indicatorpos == 'right') {
40646 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40653 if(align == 'left') {
40661 if(this.labelWidth > 12){
40662 label.style = "width: " + this.labelWidth + 'px';
40664 if(this.labelWidth < 13 && this.labelmd == 0){
40665 this.labelmd = this.labelWidth;
40667 if(this.labellg > 0){
40668 label.cls += ' col-lg-' + this.labellg;
40669 input.cls += ' col-lg-' + (12 - this.labellg);
40671 if(this.labelmd > 0){
40672 label.cls += ' col-md-' + this.labelmd;
40673 container.cls += ' col-md-' + (12 - this.labelmd);
40675 if(this.labelsm > 0){
40676 label.cls += ' col-sm-' + this.labelsm;
40677 container.cls += ' col-sm-' + (12 - this.labelsm);
40679 if(this.labelxs > 0){
40680 label.cls += ' col-xs-' + this.labelxs;
40681 container.cls += ' col-xs-' + (12 - this.labelxs);
40692 var settings = this;
40694 ['xs','sm','md','lg'].map(function(size){
40695 if (settings[size]) {
40696 cfg.cls += ' col-' + size + '-' + settings[size];
40703 initEvents : function()
40705 this.indicator = this.indicatorEl();
40707 this.initCurrencyEvent();
40709 this.initNumberEvent();
40712 initCurrencyEvent : function()
40715 throw "can not find store for combo";
40718 this.store = Roo.factory(this.store, Roo.data);
40719 this.store.parent = this;
40723 this.triggerEl = this.el.select('.input-group-addon', true).first();
40725 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40730 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40731 _this.list.setWidth(lw);
40734 this.list.on('mouseover', this.onViewOver, this);
40735 this.list.on('mousemove', this.onViewMove, this);
40736 this.list.on('scroll', this.onViewScroll, this);
40739 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40742 this.view = new Roo.View(this.list, this.tpl, {
40743 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40746 this.view.on('click', this.onViewClick, this);
40748 this.store.on('beforeload', this.onBeforeLoad, this);
40749 this.store.on('load', this.onLoad, this);
40750 this.store.on('loadexception', this.onLoadException, this);
40752 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40753 "up" : function(e){
40754 this.inKeyMode = true;
40758 "down" : function(e){
40759 if(!this.isExpanded()){
40760 this.onTriggerClick();
40762 this.inKeyMode = true;
40767 "enter" : function(e){
40770 if(this.fireEvent("specialkey", this, e)){
40771 this.onViewClick(false);
40777 "esc" : function(e){
40781 "tab" : function(e){
40784 if(this.fireEvent("specialkey", this, e)){
40785 this.onViewClick(false);
40793 doRelay : function(foo, bar, hname){
40794 if(hname == 'down' || this.scope.isExpanded()){
40795 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40803 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40807 initNumberEvent : function(e)
40809 this.inputEl().on("keydown" , this.fireKey, this);
40810 this.inputEl().on("focus", this.onFocus, this);
40811 this.inputEl().on("blur", this.onBlur, this);
40813 this.inputEl().relayEvent('keyup', this);
40815 if(this.indicator){
40816 this.indicator.addClass('invisible');
40819 this.originalValue = this.getValue();
40821 if(this.validationEvent == 'keyup'){
40822 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40823 this.inputEl().on('keyup', this.filterValidation, this);
40825 else if(this.validationEvent !== false){
40826 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40829 if(this.selectOnFocus){
40830 this.on("focus", this.preFocus, this);
40833 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40834 this.inputEl().on("keypress", this.filterKeys, this);
40836 this.inputEl().relayEvent('keypress', this);
40839 var allowed = "0123456789";
40841 if(this.allowDecimals){
40842 allowed += this.decimalSeparator;
40845 if(this.allowNegative){
40849 if(this.thousandsDelimiter) {
40853 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40855 var keyPress = function(e){
40857 var k = e.getKey();
40859 var c = e.getCharCode();
40862 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40863 allowed.indexOf(String.fromCharCode(c)) === -1
40869 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40873 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40878 this.inputEl().on("keypress", keyPress, this);
40882 onTriggerClick : function(e)
40889 this.loadNext = false;
40891 if(this.isExpanded()){
40896 this.hasFocus = true;
40898 if(this.triggerAction == 'all') {
40899 this.doQuery(this.allQuery, true);
40903 this.doQuery(this.getRawValue());
40906 getCurrency : function()
40908 var v = this.currencyEl().getValue();
40913 restrictHeight : function()
40915 this.list.alignTo(this.currencyEl(), this.listAlign);
40916 this.list.alignTo(this.currencyEl(), this.listAlign);
40919 onViewClick : function(view, doFocus, el, e)
40921 var index = this.view.getSelectedIndexes()[0];
40923 var r = this.store.getAt(index);
40926 this.onSelect(r, index);
40930 onSelect : function(record, index){
40932 if(this.fireEvent('beforeselect', this, record, index) !== false){
40934 this.setFromCurrencyData(index > -1 ? record.data : false);
40938 this.fireEvent('select', this, record, index);
40942 setFromCurrencyData : function(o)
40946 this.lastCurrency = o;
40948 if (this.currencyField) {
40949 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40951 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40954 this.lastSelectionText = currency;
40956 //setting default currency
40957 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40958 this.setCurrency(this.defaultCurrency);
40962 this.setCurrency(currency);
40965 setFromData : function(o)
40969 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40971 this.setFromCurrencyData(c);
40976 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40978 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40981 this.setValue(value);
40985 setCurrency : function(v)
40987 this.currencyValue = v;
40990 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40995 setValue : function(v)
40997 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41003 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41005 this.inputEl().dom.value = (v == '') ? '' :
41006 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41008 if(!this.allowZero && v === '0') {
41009 this.hiddenEl().dom.value = '';
41010 this.inputEl().dom.value = '';
41017 getRawValue : function()
41019 var v = this.inputEl().getValue();
41024 getValue : function()
41026 return this.fixPrecision(this.parseValue(this.getRawValue()));
41029 parseValue : function(value)
41031 if(this.thousandsDelimiter) {
41033 r = new RegExp(",", "g");
41034 value = value.replace(r, "");
41037 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41038 return isNaN(value) ? '' : value;
41042 fixPrecision : function(value)
41044 if(this.thousandsDelimiter) {
41046 r = new RegExp(",", "g");
41047 value = value.replace(r, "");
41050 var nan = isNaN(value);
41052 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41053 return nan ? '' : value;
41055 return parseFloat(value).toFixed(this.decimalPrecision);
41058 decimalPrecisionFcn : function(v)
41060 return Math.floor(v);
41063 validateValue : function(value)
41065 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41069 var num = this.parseValue(value);
41072 this.markInvalid(String.format(this.nanText, value));
41076 if(num < this.minValue){
41077 this.markInvalid(String.format(this.minText, this.minValue));
41081 if(num > this.maxValue){
41082 this.markInvalid(String.format(this.maxText, this.maxValue));
41089 validate : function()
41091 if(this.disabled || this.allowBlank){
41096 var currency = this.getCurrency();
41098 if(this.validateValue(this.getRawValue()) && currency.length){
41103 this.markInvalid();
41107 getName: function()
41112 beforeBlur : function()
41118 var v = this.parseValue(this.getRawValue());
41125 onBlur : function()
41129 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41130 //this.el.removeClass(this.focusClass);
41133 this.hasFocus = false;
41135 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41139 var v = this.getValue();
41141 if(String(v) !== String(this.startValue)){
41142 this.fireEvent('change', this, v, this.startValue);
41145 this.fireEvent("blur", this);
41148 inputEl : function()
41150 return this.el.select('.roo-money-amount-input', true).first();
41153 currencyEl : function()
41155 return this.el.select('.roo-money-currency-input', true).first();
41158 hiddenEl : function()
41160 return this.el.select('input.hidden-number-input',true).first();