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'
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 ml-md-auto';
4265 cfg.cls += ' navbar-left';
4269 if (this.align === 'right') {
4270 cfg.cls += ' navbar-right ml-md-auto';
4272 cfg.cls += ' mr-auto';
4276 cfg.cls += ' navbar-inverse';
4284 * sets the active Navigation item
4285 * @param {Roo.bootstrap.NavItem} the new current navitem
4287 setActiveItem : function(item)
4290 Roo.each(this.navItems, function(v){
4295 v.setActive(false, true);
4302 item.setActive(true, true);
4303 this.fireEvent('changed', this, item, prev);
4308 * gets the active Navigation item
4309 * @return {Roo.bootstrap.NavItem} the current navitem
4311 getActive : function()
4315 Roo.each(this.navItems, function(v){
4326 indexOfNav : function()
4330 Roo.each(this.navItems, function(v,i){
4341 * adds a Navigation item
4342 * @param {Roo.bootstrap.NavItem} the navitem to add
4344 addItem : function(cfg)
4346 var cn = new Roo.bootstrap.NavItem(cfg);
4348 cn.parentId = this.id;
4349 cn.onRender(this.el, null);
4353 * register a Navigation item
4354 * @param {Roo.bootstrap.NavItem} the navitem to add
4356 register : function(item)
4358 this.navItems.push( item);
4359 item.navId = this.navId;
4364 * clear all the Navigation item
4367 clearAll : function()
4370 this.el.dom.innerHTML = '';
4373 getNavItem: function(tabId)
4376 Roo.each(this.navItems, function(e) {
4377 if (e.tabId == tabId) {
4387 setActiveNext : function()
4389 var i = this.indexOfNav(this.getActive());
4390 if (i > this.navItems.length) {
4393 this.setActiveItem(this.navItems[i+1]);
4395 setActivePrev : function()
4397 var i = this.indexOfNav(this.getActive());
4401 this.setActiveItem(this.navItems[i-1]);
4403 clearWasActive : function(except) {
4404 Roo.each(this.navItems, function(e) {
4405 if (e.tabId != except.tabId && e.was_active) {
4406 e.was_active = false;
4413 getWasActive : function ()
4416 Roo.each(this.navItems, function(e) {
4431 Roo.apply(Roo.bootstrap.NavGroup, {
4435 * register a Navigation Group
4436 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4438 register : function(navgrp)
4440 this.groups[navgrp.navId] = navgrp;
4444 * fetch a Navigation Group based on the navigation ID
4445 * @param {string} the navgroup to add
4446 * @returns {Roo.bootstrap.NavGroup} the navgroup
4448 get: function(navId) {
4449 if (typeof(this.groups[navId]) == 'undefined') {
4451 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4453 return this.groups[navId] ;
4468 * @class Roo.bootstrap.NavItem
4469 * @extends Roo.bootstrap.Component
4470 * Bootstrap Navbar.NavItem class
4471 * @cfg {String} href link to
4472 * @cfg {String} html content of button
4473 * @cfg {String} badge text inside badge
4474 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4475 * @cfg {String} glyphicon name of glyphicon
4476 * @cfg {String} icon name of font awesome icon
4477 * @cfg {Boolean} active Is item active
4478 * @cfg {Boolean} disabled Is item disabled
4480 * @cfg {Boolean} preventDefault (true | false) default false
4481 * @cfg {String} tabId the tab that this item activates.
4482 * @cfg {String} tagtype (a|span) render as a href or span?
4483 * @cfg {Boolean} animateRef (true|false) link to element default false
4486 * Create a new Navbar Item
4487 * @param {Object} config The config object
4489 Roo.bootstrap.NavItem = function(config){
4490 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4495 * The raw click event for the entire grid.
4496 * @param {Roo.EventObject} e
4501 * Fires when the active item active state changes
4502 * @param {Roo.bootstrap.NavItem} this
4503 * @param {boolean} state the new state
4509 * Fires when scroll to element
4510 * @param {Roo.bootstrap.NavItem} this
4511 * @param {Object} options
4512 * @param {Roo.EventObject} e
4520 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4528 preventDefault : false,
4535 getAutoCreate : function(){
4544 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4546 if (this.disabled) {
4547 cfg.cls += ' disabled';
4550 if (this.href || this.html || this.glyphicon || this.icon) {
4554 href : this.href || "#",
4555 html: this.html || ''
4558 if (this.tagtype == 'a') {
4559 cfg.cn[0].cls = 'nav-link';
4562 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4565 if(this.glyphicon) {
4566 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4571 cfg.cn[0].html += " <span class='caret'></span>";
4575 if (this.badge !== '') {
4577 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4585 initEvents: function()
4587 if (typeof (this.menu) != 'undefined') {
4588 this.menu.parentType = this.xtype;
4589 this.menu.triggerEl = this.el;
4590 this.menu = this.addxtype(Roo.apply({}, this.menu));
4593 this.el.select('a',true).on('click', this.onClick, this);
4595 if(this.tagtype == 'span'){
4596 this.el.select('span',true).on('click', this.onClick, this);
4599 // at this point parent should be available..
4600 this.parent().register(this);
4603 onClick : function(e)
4605 if (e.getTarget('.dropdown-menu-item')) {
4606 // did you click on a menu itemm.... - then don't trigger onclick..
4611 this.preventDefault ||
4614 Roo.log("NavItem - prevent Default?");
4618 if (this.disabled) {
4622 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4623 if (tg && tg.transition) {
4624 Roo.log("waiting for the transitionend");
4630 //Roo.log("fire event clicked");
4631 if(this.fireEvent('click', this, e) === false){
4635 if(this.tagtype == 'span'){
4639 //Roo.log(this.href);
4640 var ael = this.el.select('a',true).first();
4643 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4644 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4645 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4646 return; // ignore... - it's a 'hash' to another page.
4648 Roo.log("NavItem - prevent Default?");
4650 this.scrollToElement(e);
4654 var p = this.parent();
4656 if (['tabs','pills'].indexOf(p.type)!==-1) {
4657 if (typeof(p.setActiveItem) !== 'undefined') {
4658 p.setActiveItem(this);
4662 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4663 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4664 // remove the collapsed menu expand...
4665 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4669 isActive: function () {
4672 setActive : function(state, fire, is_was_active)
4674 if (this.active && !state && this.navId) {
4675 this.was_active = true;
4676 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4678 nv.clearWasActive(this);
4682 this.active = state;
4685 this.el.removeClass('active');
4686 } else if (!this.el.hasClass('active')) {
4687 this.el.addClass('active');
4690 this.fireEvent('changed', this, state);
4693 // show a panel if it's registered and related..
4695 if (!this.navId || !this.tabId || !state || is_was_active) {
4699 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4703 var pan = tg.getPanelByName(this.tabId);
4707 // if we can not flip to new panel - go back to old nav highlight..
4708 if (false == tg.showPanel(pan)) {
4709 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4711 var onav = nv.getWasActive();
4713 onav.setActive(true, false, true);
4722 // this should not be here...
4723 setDisabled : function(state)
4725 this.disabled = state;
4727 this.el.removeClass('disabled');
4728 } else if (!this.el.hasClass('disabled')) {
4729 this.el.addClass('disabled');
4735 * Fetch the element to display the tooltip on.
4736 * @return {Roo.Element} defaults to this.el
4738 tooltipEl : function()
4740 return this.el.select('' + this.tagtype + '', true).first();
4743 scrollToElement : function(e)
4745 var c = document.body;
4748 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4750 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4751 c = document.documentElement;
4754 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4760 var o = target.calcOffsetsTo(c);
4767 this.fireEvent('scrollto', this, options, e);
4769 Roo.get(c).scrollTo('top', options.value, true);
4782 * <span> icon </span>
4783 * <span> text </span>
4784 * <span>badge </span>
4788 * @class Roo.bootstrap.NavSidebarItem
4789 * @extends Roo.bootstrap.NavItem
4790 * Bootstrap Navbar.NavSidebarItem class
4791 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4792 * {Boolean} open is the menu open
4793 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4794 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4795 * {String} buttonSize (sm|md|lg)the extra classes for the button
4796 * {Boolean} showArrow show arrow next to the text (default true)
4798 * Create a new Navbar Button
4799 * @param {Object} config The config object
4801 Roo.bootstrap.NavSidebarItem = function(config){
4802 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4807 * The raw click event for the entire grid.
4808 * @param {Roo.EventObject} e
4813 * Fires when the active item active state changes
4814 * @param {Roo.bootstrap.NavSidebarItem} this
4815 * @param {boolean} state the new state
4823 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4825 badgeWeight : 'default',
4831 buttonWeight : 'default',
4837 getAutoCreate : function(){
4842 href : this.href || '#',
4848 if(this.buttonView){
4851 href : this.href || '#',
4852 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4865 cfg.cls += ' active';
4868 if (this.disabled) {
4869 cfg.cls += ' disabled';
4872 cfg.cls += ' open x-open';
4875 if (this.glyphicon || this.icon) {
4876 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4877 a.cn.push({ tag : 'i', cls : c }) ;
4880 if(!this.buttonView){
4883 html : this.html || ''
4890 if (this.badge !== '') {
4891 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4897 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4900 a.cls += ' dropdown-toggle treeview' ;
4906 initEvents : function()
4908 if (typeof (this.menu) != 'undefined') {
4909 this.menu.parentType = this.xtype;
4910 this.menu.triggerEl = this.el;
4911 this.menu = this.addxtype(Roo.apply({}, this.menu));
4914 this.el.on('click', this.onClick, this);
4916 if(this.badge !== ''){
4917 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4922 onClick : function(e)
4929 if(this.preventDefault){
4933 this.fireEvent('click', this);
4936 disable : function()
4938 this.setDisabled(true);
4943 this.setDisabled(false);
4946 setDisabled : function(state)
4948 if(this.disabled == state){
4952 this.disabled = state;
4955 this.el.addClass('disabled');
4959 this.el.removeClass('disabled');
4964 setActive : function(state)
4966 if(this.active == state){
4970 this.active = state;
4973 this.el.addClass('active');
4977 this.el.removeClass('active');
4982 isActive: function ()
4987 setBadge : function(str)
4993 this.badgeEl.dom.innerHTML = str;
5010 * @class Roo.bootstrap.Row
5011 * @extends Roo.bootstrap.Component
5012 * Bootstrap Row class (contains columns...)
5016 * @param {Object} config The config object
5019 Roo.bootstrap.Row = function(config){
5020 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5023 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5025 getAutoCreate : function(){
5044 * @class Roo.bootstrap.Element
5045 * @extends Roo.bootstrap.Component
5046 * Bootstrap Element class
5047 * @cfg {String} html contents of the element
5048 * @cfg {String} tag tag of the element
5049 * @cfg {String} cls class of the element
5050 * @cfg {Boolean} preventDefault (true|false) default false
5051 * @cfg {Boolean} clickable (true|false) default false
5054 * Create a new Element
5055 * @param {Object} config The config object
5058 Roo.bootstrap.Element = function(config){
5059 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5065 * When a element is chick
5066 * @param {Roo.bootstrap.Element} this
5067 * @param {Roo.EventObject} e
5073 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5078 preventDefault: false,
5081 getAutoCreate : function(){
5085 // cls: this.cls, double assign in parent class Component.js :: onRender
5092 initEvents: function()
5094 Roo.bootstrap.Element.superclass.initEvents.call(this);
5097 this.el.on('click', this.onClick, this);
5102 onClick : function(e)
5104 if(this.preventDefault){
5108 this.fireEvent('click', this, e);
5111 getValue : function()
5113 return this.el.dom.innerHTML;
5116 setValue : function(value)
5118 this.el.dom.innerHTML = value;
5133 * @class Roo.bootstrap.Pagination
5134 * @extends Roo.bootstrap.Component
5135 * Bootstrap Pagination class
5136 * @cfg {String} size xs | sm | md | lg
5137 * @cfg {Boolean} inverse false | true
5140 * Create a new Pagination
5141 * @param {Object} config The config object
5144 Roo.bootstrap.Pagination = function(config){
5145 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5148 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5154 getAutoCreate : function(){
5160 cfg.cls += ' inverse';
5166 cfg.cls += " " + this.cls;
5184 * @class Roo.bootstrap.PaginationItem
5185 * @extends Roo.bootstrap.Component
5186 * Bootstrap PaginationItem class
5187 * @cfg {String} html text
5188 * @cfg {String} href the link
5189 * @cfg {Boolean} preventDefault (true | false) default true
5190 * @cfg {Boolean} active (true | false) default false
5191 * @cfg {Boolean} disabled default false
5195 * Create a new PaginationItem
5196 * @param {Object} config The config object
5200 Roo.bootstrap.PaginationItem = function(config){
5201 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5206 * The raw click event for the entire grid.
5207 * @param {Roo.EventObject} e
5213 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5217 preventDefault: true,
5222 getAutoCreate : function(){
5228 href : this.href ? this.href : '#',
5229 html : this.html ? this.html : ''
5239 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5243 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5249 initEvents: function() {
5251 this.el.on('click', this.onClick, this);
5254 onClick : function(e)
5256 Roo.log('PaginationItem on click ');
5257 if(this.preventDefault){
5265 this.fireEvent('click', this, e);
5281 * @class Roo.bootstrap.Slider
5282 * @extends Roo.bootstrap.Component
5283 * Bootstrap Slider class
5286 * Create a new Slider
5287 * @param {Object} config The config object
5290 Roo.bootstrap.Slider = function(config){
5291 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5294 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5296 getAutoCreate : function(){
5300 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5304 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5316 * Ext JS Library 1.1.1
5317 * Copyright(c) 2006-2007, Ext JS, LLC.
5319 * Originally Released Under LGPL - original licence link has changed is not relivant.
5322 * <script type="text/javascript">
5327 * @class Roo.grid.ColumnModel
5328 * @extends Roo.util.Observable
5329 * This is the default implementation of a ColumnModel used by the Grid. It defines
5330 * the columns in the grid.
5333 var colModel = new Roo.grid.ColumnModel([
5334 {header: "Ticker", width: 60, sortable: true, locked: true},
5335 {header: "Company Name", width: 150, sortable: true},
5336 {header: "Market Cap.", width: 100, sortable: true},
5337 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5338 {header: "Employees", width: 100, sortable: true, resizable: false}
5343 * The config options listed for this class are options which may appear in each
5344 * individual column definition.
5345 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5347 * @param {Object} config An Array of column config objects. See this class's
5348 * config objects for details.
5350 Roo.grid.ColumnModel = function(config){
5352 * The config passed into the constructor
5354 this.config = config;
5357 // if no id, create one
5358 // if the column does not have a dataIndex mapping,
5359 // map it to the order it is in the config
5360 for(var i = 0, len = config.length; i < len; i++){
5362 if(typeof c.dataIndex == "undefined"){
5365 if(typeof c.renderer == "string"){
5366 c.renderer = Roo.util.Format[c.renderer];
5368 if(typeof c.id == "undefined"){
5371 if(c.editor && c.editor.xtype){
5372 c.editor = Roo.factory(c.editor, Roo.grid);
5374 if(c.editor && c.editor.isFormField){
5375 c.editor = new Roo.grid.GridEditor(c.editor);
5377 this.lookup[c.id] = c;
5381 * The width of columns which have no width specified (defaults to 100)
5384 this.defaultWidth = 100;
5387 * Default sortable of columns which have no sortable specified (defaults to false)
5390 this.defaultSortable = false;
5394 * @event widthchange
5395 * Fires when the width of a column changes.
5396 * @param {ColumnModel} this
5397 * @param {Number} columnIndex The column index
5398 * @param {Number} newWidth The new width
5400 "widthchange": true,
5402 * @event headerchange
5403 * Fires when the text of a header changes.
5404 * @param {ColumnModel} this
5405 * @param {Number} columnIndex The column index
5406 * @param {Number} newText The new header text
5408 "headerchange": true,
5410 * @event hiddenchange
5411 * Fires when a column is hidden or "unhidden".
5412 * @param {ColumnModel} this
5413 * @param {Number} columnIndex The column index
5414 * @param {Boolean} hidden true if hidden, false otherwise
5416 "hiddenchange": true,
5418 * @event columnmoved
5419 * Fires when a column is moved.
5420 * @param {ColumnModel} this
5421 * @param {Number} oldIndex
5422 * @param {Number} newIndex
5424 "columnmoved" : true,
5426 * @event columlockchange
5427 * Fires when a column's locked state is changed
5428 * @param {ColumnModel} this
5429 * @param {Number} colIndex
5430 * @param {Boolean} locked true if locked
5432 "columnlockchange" : true
5434 Roo.grid.ColumnModel.superclass.constructor.call(this);
5436 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5438 * @cfg {String} header The header text to display in the Grid view.
5441 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5442 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5443 * specified, the column's index is used as an index into the Record's data Array.
5446 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5447 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5450 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5451 * Defaults to the value of the {@link #defaultSortable} property.
5452 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5455 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5458 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5461 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5464 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5467 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5468 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5469 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5470 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5473 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5476 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5479 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5482 * @cfg {String} cursor (Optional)
5485 * @cfg {String} tooltip (Optional)
5488 * @cfg {Number} xs (Optional)
5491 * @cfg {Number} sm (Optional)
5494 * @cfg {Number} md (Optional)
5497 * @cfg {Number} lg (Optional)
5500 * Returns the id of the column at the specified index.
5501 * @param {Number} index The column index
5502 * @return {String} the id
5504 getColumnId : function(index){
5505 return this.config[index].id;
5509 * Returns the column for a specified id.
5510 * @param {String} id The column id
5511 * @return {Object} the column
5513 getColumnById : function(id){
5514 return this.lookup[id];
5519 * Returns the column for a specified dataIndex.
5520 * @param {String} dataIndex The column dataIndex
5521 * @return {Object|Boolean} the column or false if not found
5523 getColumnByDataIndex: function(dataIndex){
5524 var index = this.findColumnIndex(dataIndex);
5525 return index > -1 ? this.config[index] : false;
5529 * Returns the index for a specified column id.
5530 * @param {String} id The column id
5531 * @return {Number} the index, or -1 if not found
5533 getIndexById : function(id){
5534 for(var i = 0, len = this.config.length; i < len; i++){
5535 if(this.config[i].id == id){
5543 * Returns the index for a specified column dataIndex.
5544 * @param {String} dataIndex The column dataIndex
5545 * @return {Number} the index, or -1 if not found
5548 findColumnIndex : function(dataIndex){
5549 for(var i = 0, len = this.config.length; i < len; i++){
5550 if(this.config[i].dataIndex == dataIndex){
5558 moveColumn : function(oldIndex, newIndex){
5559 var c = this.config[oldIndex];
5560 this.config.splice(oldIndex, 1);
5561 this.config.splice(newIndex, 0, c);
5562 this.dataMap = null;
5563 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5566 isLocked : function(colIndex){
5567 return this.config[colIndex].locked === true;
5570 setLocked : function(colIndex, value, suppressEvent){
5571 if(this.isLocked(colIndex) == value){
5574 this.config[colIndex].locked = value;
5576 this.fireEvent("columnlockchange", this, colIndex, value);
5580 getTotalLockedWidth : function(){
5582 for(var i = 0; i < this.config.length; i++){
5583 if(this.isLocked(i) && !this.isHidden(i)){
5584 this.totalWidth += this.getColumnWidth(i);
5590 getLockedCount : function(){
5591 for(var i = 0, len = this.config.length; i < len; i++){
5592 if(!this.isLocked(i)){
5597 return this.config.length;
5601 * Returns the number of columns.
5604 getColumnCount : function(visibleOnly){
5605 if(visibleOnly === true){
5607 for(var i = 0, len = this.config.length; i < len; i++){
5608 if(!this.isHidden(i)){
5614 return this.config.length;
5618 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5619 * @param {Function} fn
5620 * @param {Object} scope (optional)
5621 * @return {Array} result
5623 getColumnsBy : function(fn, scope){
5625 for(var i = 0, len = this.config.length; i < len; i++){
5626 var c = this.config[i];
5627 if(fn.call(scope||this, c, i) === true){
5635 * Returns true if the specified column is sortable.
5636 * @param {Number} col The column index
5639 isSortable : function(col){
5640 if(typeof this.config[col].sortable == "undefined"){
5641 return this.defaultSortable;
5643 return this.config[col].sortable;
5647 * Returns the rendering (formatting) function defined for the column.
5648 * @param {Number} col The column index.
5649 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5651 getRenderer : function(col){
5652 if(!this.config[col].renderer){
5653 return Roo.grid.ColumnModel.defaultRenderer;
5655 return this.config[col].renderer;
5659 * Sets the rendering (formatting) function for a column.
5660 * @param {Number} col The column index
5661 * @param {Function} fn The function to use to process the cell's raw data
5662 * to return HTML markup for the grid view. The render function is called with
5663 * the following parameters:<ul>
5664 * <li>Data value.</li>
5665 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5666 * <li>css A CSS style string to apply to the table cell.</li>
5667 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5668 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5669 * <li>Row index</li>
5670 * <li>Column index</li>
5671 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5673 setRenderer : function(col, fn){
5674 this.config[col].renderer = fn;
5678 * Returns the width for the specified column.
5679 * @param {Number} col The column index
5682 getColumnWidth : function(col){
5683 return this.config[col].width * 1 || this.defaultWidth;
5687 * Sets the width for a column.
5688 * @param {Number} col The column index
5689 * @param {Number} width The new width
5691 setColumnWidth : function(col, width, suppressEvent){
5692 this.config[col].width = width;
5693 this.totalWidth = null;
5695 this.fireEvent("widthchange", this, col, width);
5700 * Returns the total width of all columns.
5701 * @param {Boolean} includeHidden True to include hidden column widths
5704 getTotalWidth : function(includeHidden){
5705 if(!this.totalWidth){
5706 this.totalWidth = 0;
5707 for(var i = 0, len = this.config.length; i < len; i++){
5708 if(includeHidden || !this.isHidden(i)){
5709 this.totalWidth += this.getColumnWidth(i);
5713 return this.totalWidth;
5717 * Returns the header for the specified column.
5718 * @param {Number} col The column index
5721 getColumnHeader : function(col){
5722 return this.config[col].header;
5726 * Sets the header for a column.
5727 * @param {Number} col The column index
5728 * @param {String} header The new header
5730 setColumnHeader : function(col, header){
5731 this.config[col].header = header;
5732 this.fireEvent("headerchange", this, col, header);
5736 * Returns the tooltip for the specified column.
5737 * @param {Number} col The column index
5740 getColumnTooltip : function(col){
5741 return this.config[col].tooltip;
5744 * Sets the tooltip for a column.
5745 * @param {Number} col The column index
5746 * @param {String} tooltip The new tooltip
5748 setColumnTooltip : function(col, tooltip){
5749 this.config[col].tooltip = tooltip;
5753 * Returns the dataIndex for the specified column.
5754 * @param {Number} col The column index
5757 getDataIndex : function(col){
5758 return this.config[col].dataIndex;
5762 * Sets the dataIndex for a column.
5763 * @param {Number} col The column index
5764 * @param {Number} dataIndex The new dataIndex
5766 setDataIndex : function(col, dataIndex){
5767 this.config[col].dataIndex = dataIndex;
5773 * Returns true if the cell is editable.
5774 * @param {Number} colIndex The column index
5775 * @param {Number} rowIndex The row index - this is nto actually used..?
5778 isCellEditable : function(colIndex, rowIndex){
5779 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5783 * Returns the editor defined for the cell/column.
5784 * return false or null to disable editing.
5785 * @param {Number} colIndex The column index
5786 * @param {Number} rowIndex The row index
5789 getCellEditor : function(colIndex, rowIndex){
5790 return this.config[colIndex].editor;
5794 * Sets if a column is editable.
5795 * @param {Number} col The column index
5796 * @param {Boolean} editable True if the column is editable
5798 setEditable : function(col, editable){
5799 this.config[col].editable = editable;
5804 * Returns true if the column is hidden.
5805 * @param {Number} colIndex The column index
5808 isHidden : function(colIndex){
5809 return this.config[colIndex].hidden;
5814 * Returns true if the column width cannot be changed
5816 isFixed : function(colIndex){
5817 return this.config[colIndex].fixed;
5821 * Returns true if the column can be resized
5824 isResizable : function(colIndex){
5825 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5828 * Sets if a column is hidden.
5829 * @param {Number} colIndex The column index
5830 * @param {Boolean} hidden True if the column is hidden
5832 setHidden : function(colIndex, hidden){
5833 this.config[colIndex].hidden = hidden;
5834 this.totalWidth = null;
5835 this.fireEvent("hiddenchange", this, colIndex, hidden);
5839 * Sets the editor for a column.
5840 * @param {Number} col The column index
5841 * @param {Object} editor The editor object
5843 setEditor : function(col, editor){
5844 this.config[col].editor = editor;
5848 Roo.grid.ColumnModel.defaultRenderer = function(value)
5850 if(typeof value == "object") {
5853 if(typeof value == "string" && value.length < 1){
5857 return String.format("{0}", value);
5860 // Alias for backwards compatibility
5861 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5864 * Ext JS Library 1.1.1
5865 * Copyright(c) 2006-2007, Ext JS, LLC.
5867 * Originally Released Under LGPL - original licence link has changed is not relivant.
5870 * <script type="text/javascript">
5874 * @class Roo.LoadMask
5875 * A simple utility class for generically masking elements while loading data. If the element being masked has
5876 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5877 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5878 * element's UpdateManager load indicator and will be destroyed after the initial load.
5880 * Create a new LoadMask
5881 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5882 * @param {Object} config The config object
5884 Roo.LoadMask = function(el, config){
5885 this.el = Roo.get(el);
5886 Roo.apply(this, config);
5888 this.store.on('beforeload', this.onBeforeLoad, this);
5889 this.store.on('load', this.onLoad, this);
5890 this.store.on('loadexception', this.onLoadException, this);
5891 this.removeMask = false;
5893 var um = this.el.getUpdateManager();
5894 um.showLoadIndicator = false; // disable the default indicator
5895 um.on('beforeupdate', this.onBeforeLoad, this);
5896 um.on('update', this.onLoad, this);
5897 um.on('failure', this.onLoad, this);
5898 this.removeMask = true;
5902 Roo.LoadMask.prototype = {
5904 * @cfg {Boolean} removeMask
5905 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5906 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5910 * The text to display in a centered loading message box (defaults to 'Loading...')
5914 * @cfg {String} msgCls
5915 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5917 msgCls : 'x-mask-loading',
5920 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5926 * Disables the mask to prevent it from being displayed
5928 disable : function(){
5929 this.disabled = true;
5933 * Enables the mask so that it can be displayed
5935 enable : function(){
5936 this.disabled = false;
5939 onLoadException : function()
5943 if (typeof(arguments[3]) != 'undefined') {
5944 Roo.MessageBox.alert("Error loading",arguments[3]);
5948 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5949 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5956 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5961 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5965 onBeforeLoad : function(){
5967 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5972 destroy : function(){
5974 this.store.un('beforeload', this.onBeforeLoad, this);
5975 this.store.un('load', this.onLoad, this);
5976 this.store.un('loadexception', this.onLoadException, this);
5978 var um = this.el.getUpdateManager();
5979 um.un('beforeupdate', this.onBeforeLoad, this);
5980 um.un('update', this.onLoad, this);
5981 um.un('failure', this.onLoad, this);
5992 * @class Roo.bootstrap.Table
5993 * @extends Roo.bootstrap.Component
5994 * Bootstrap Table class
5995 * @cfg {String} cls table class
5996 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5997 * @cfg {String} bgcolor Specifies the background color for a table
5998 * @cfg {Number} border Specifies whether the table cells should have borders or not
5999 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6000 * @cfg {Number} cellspacing Specifies the space between cells
6001 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6002 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6003 * @cfg {String} sortable Specifies that the table should be sortable
6004 * @cfg {String} summary Specifies a summary of the content of a table
6005 * @cfg {Number} width Specifies the width of a table
6006 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6008 * @cfg {boolean} striped Should the rows be alternative striped
6009 * @cfg {boolean} bordered Add borders to the table
6010 * @cfg {boolean} hover Add hover highlighting
6011 * @cfg {boolean} condensed Format condensed
6012 * @cfg {boolean} responsive Format condensed
6013 * @cfg {Boolean} loadMask (true|false) default false
6014 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6015 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6016 * @cfg {Boolean} rowSelection (true|false) default false
6017 * @cfg {Boolean} cellSelection (true|false) default false
6018 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6019 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6020 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6021 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6025 * Create a new Table
6026 * @param {Object} config The config object
6029 Roo.bootstrap.Table = function(config){
6030 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6035 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6036 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6037 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6038 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6040 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6042 this.sm.grid = this;
6043 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6044 this.sm = this.selModel;
6045 this.sm.xmodule = this.xmodule || false;
6048 if (this.cm && typeof(this.cm.config) == 'undefined') {
6049 this.colModel = new Roo.grid.ColumnModel(this.cm);
6050 this.cm = this.colModel;
6051 this.cm.xmodule = this.xmodule || false;
6054 this.store= Roo.factory(this.store, Roo.data);
6055 this.ds = this.store;
6056 this.ds.xmodule = this.xmodule || false;
6059 if (this.footer && this.store) {
6060 this.footer.dataSource = this.ds;
6061 this.footer = Roo.factory(this.footer);
6068 * Fires when a cell is clicked
6069 * @param {Roo.bootstrap.Table} this
6070 * @param {Roo.Element} el
6071 * @param {Number} rowIndex
6072 * @param {Number} columnIndex
6073 * @param {Roo.EventObject} e
6077 * @event celldblclick
6078 * Fires when a cell is double clicked
6079 * @param {Roo.bootstrap.Table} this
6080 * @param {Roo.Element} el
6081 * @param {Number} rowIndex
6082 * @param {Number} columnIndex
6083 * @param {Roo.EventObject} e
6085 "celldblclick" : true,
6088 * Fires when a row is clicked
6089 * @param {Roo.bootstrap.Table} this
6090 * @param {Roo.Element} el
6091 * @param {Number} rowIndex
6092 * @param {Roo.EventObject} e
6096 * @event rowdblclick
6097 * Fires when a row is double clicked
6098 * @param {Roo.bootstrap.Table} this
6099 * @param {Roo.Element} el
6100 * @param {Number} rowIndex
6101 * @param {Roo.EventObject} e
6103 "rowdblclick" : true,
6106 * Fires when a mouseover occur
6107 * @param {Roo.bootstrap.Table} this
6108 * @param {Roo.Element} el
6109 * @param {Number} rowIndex
6110 * @param {Number} columnIndex
6111 * @param {Roo.EventObject} e
6116 * Fires when a mouseout occur
6117 * @param {Roo.bootstrap.Table} this
6118 * @param {Roo.Element} el
6119 * @param {Number} rowIndex
6120 * @param {Number} columnIndex
6121 * @param {Roo.EventObject} e
6126 * Fires when a row is rendered, so you can change add a style to it.
6127 * @param {Roo.bootstrap.Table} this
6128 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6132 * @event rowsrendered
6133 * Fires when all the rows have been rendered
6134 * @param {Roo.bootstrap.Table} this
6136 'rowsrendered' : true,
6138 * @event contextmenu
6139 * The raw contextmenu event for the entire grid.
6140 * @param {Roo.EventObject} e
6142 "contextmenu" : true,
6144 * @event rowcontextmenu
6145 * Fires when a row is right clicked
6146 * @param {Roo.bootstrap.Table} this
6147 * @param {Number} rowIndex
6148 * @param {Roo.EventObject} e
6150 "rowcontextmenu" : true,
6152 * @event cellcontextmenu
6153 * Fires when a cell is right clicked
6154 * @param {Roo.bootstrap.Table} this
6155 * @param {Number} rowIndex
6156 * @param {Number} cellIndex
6157 * @param {Roo.EventObject} e
6159 "cellcontextmenu" : true,
6161 * @event headercontextmenu
6162 * Fires when a header is right clicked
6163 * @param {Roo.bootstrap.Table} this
6164 * @param {Number} columnIndex
6165 * @param {Roo.EventObject} e
6167 "headercontextmenu" : true
6171 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6197 rowSelection : false,
6198 cellSelection : false,
6201 // Roo.Element - the tbody
6203 // Roo.Element - thead element
6206 container: false, // used by gridpanel...
6212 auto_hide_footer : false,
6214 getAutoCreate : function()
6216 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6223 if (this.scrollBody) {
6224 cfg.cls += ' table-body-fixed';
6227 cfg.cls += ' table-striped';
6231 cfg.cls += ' table-hover';
6233 if (this.bordered) {
6234 cfg.cls += ' table-bordered';
6236 if (this.condensed) {
6237 cfg.cls += ' table-condensed';
6239 if (this.responsive) {
6240 cfg.cls += ' table-responsive';
6244 cfg.cls+= ' ' +this.cls;
6247 // this lot should be simplifed...
6260 ].forEach(function(k) {
6268 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6271 if(this.store || this.cm){
6272 if(this.headerShow){
6273 cfg.cn.push(this.renderHeader());
6276 cfg.cn.push(this.renderBody());
6278 if(this.footerShow){
6279 cfg.cn.push(this.renderFooter());
6281 // where does this come from?
6282 //cfg.cls+= ' TableGrid';
6285 return { cn : [ cfg ] };
6288 initEvents : function()
6290 if(!this.store || !this.cm){
6293 if (this.selModel) {
6294 this.selModel.initEvents();
6298 //Roo.log('initEvents with ds!!!!');
6300 this.mainBody = this.el.select('tbody', true).first();
6301 this.mainHead = this.el.select('thead', true).first();
6302 this.mainFoot = this.el.select('tfoot', true).first();
6308 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6309 e.on('click', _this.sort, _this);
6312 this.mainBody.on("click", this.onClick, this);
6313 this.mainBody.on("dblclick", this.onDblClick, this);
6315 // why is this done????? = it breaks dialogs??
6316 //this.parent().el.setStyle('position', 'relative');
6320 this.footer.parentId = this.id;
6321 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6324 this.el.select('tfoot tr td').first().addClass('hide');
6329 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6332 this.store.on('load', this.onLoad, this);
6333 this.store.on('beforeload', this.onBeforeLoad, this);
6334 this.store.on('update', this.onUpdate, this);
6335 this.store.on('add', this.onAdd, this);
6336 this.store.on("clear", this.clear, this);
6338 this.el.on("contextmenu", this.onContextMenu, this);
6340 this.mainBody.on('scroll', this.onBodyScroll, this);
6342 this.cm.on("headerchange", this.onHeaderChange, this);
6344 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6348 onContextMenu : function(e, t)
6350 this.processEvent("contextmenu", e);
6353 processEvent : function(name, e)
6355 if (name != 'touchstart' ) {
6356 this.fireEvent(name, e);
6359 var t = e.getTarget();
6361 var cell = Roo.get(t);
6367 if(cell.findParent('tfoot', false, true)){
6371 if(cell.findParent('thead', false, true)){
6373 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6374 cell = Roo.get(t).findParent('th', false, true);
6376 Roo.log("failed to find th in thead?");
6377 Roo.log(e.getTarget());
6382 var cellIndex = cell.dom.cellIndex;
6384 var ename = name == 'touchstart' ? 'click' : name;
6385 this.fireEvent("header" + ename, this, cellIndex, e);
6390 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6391 cell = Roo.get(t).findParent('td', false, true);
6393 Roo.log("failed to find th in tbody?");
6394 Roo.log(e.getTarget());
6399 var row = cell.findParent('tr', false, true);
6400 var cellIndex = cell.dom.cellIndex;
6401 var rowIndex = row.dom.rowIndex - 1;
6405 this.fireEvent("row" + name, this, rowIndex, e);
6409 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6415 onMouseover : function(e, el)
6417 var cell = Roo.get(el);
6423 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6424 cell = cell.findParent('td', false, true);
6427 var row = cell.findParent('tr', false, true);
6428 var cellIndex = cell.dom.cellIndex;
6429 var rowIndex = row.dom.rowIndex - 1; // start from 0
6431 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6435 onMouseout : function(e, el)
6437 var cell = Roo.get(el);
6443 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6444 cell = cell.findParent('td', false, true);
6447 var row = cell.findParent('tr', false, true);
6448 var cellIndex = cell.dom.cellIndex;
6449 var rowIndex = row.dom.rowIndex - 1; // start from 0
6451 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6455 onClick : function(e, el)
6457 var cell = Roo.get(el);
6459 if(!cell || (!this.cellSelection && !this.rowSelection)){
6463 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6464 cell = cell.findParent('td', false, true);
6467 if(!cell || typeof(cell) == 'undefined'){
6471 var row = cell.findParent('tr', false, true);
6473 if(!row || typeof(row) == 'undefined'){
6477 var cellIndex = cell.dom.cellIndex;
6478 var rowIndex = this.getRowIndex(row);
6480 // why??? - should these not be based on SelectionModel?
6481 if(this.cellSelection){
6482 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6485 if(this.rowSelection){
6486 this.fireEvent('rowclick', this, row, rowIndex, e);
6492 onDblClick : function(e,el)
6494 var cell = Roo.get(el);
6496 if(!cell || (!this.cellSelection && !this.rowSelection)){
6500 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6501 cell = cell.findParent('td', false, true);
6504 if(!cell || typeof(cell) == 'undefined'){
6508 var row = cell.findParent('tr', false, true);
6510 if(!row || typeof(row) == 'undefined'){
6514 var cellIndex = cell.dom.cellIndex;
6515 var rowIndex = this.getRowIndex(row);
6517 if(this.cellSelection){
6518 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6521 if(this.rowSelection){
6522 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6526 sort : function(e,el)
6528 var col = Roo.get(el);
6530 if(!col.hasClass('sortable')){
6534 var sort = col.attr('sort');
6537 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6541 this.store.sortInfo = {field : sort, direction : dir};
6544 Roo.log("calling footer first");
6545 this.footer.onClick('first');
6548 this.store.load({ params : { start : 0 } });
6552 renderHeader : function()
6560 this.totalWidth = 0;
6562 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6564 var config = cm.config[i];
6568 cls : 'x-hcol-' + i,
6570 html: cm.getColumnHeader(i)
6575 if(typeof(config.sortable) != 'undefined' && config.sortable){
6577 c.html = '<i class="glyphicon"></i>' + c.html;
6580 if(typeof(config.lgHeader) != 'undefined'){
6581 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6584 if(typeof(config.mdHeader) != 'undefined'){
6585 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6588 if(typeof(config.smHeader) != 'undefined'){
6589 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6592 if(typeof(config.xsHeader) != 'undefined'){
6593 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6600 if(typeof(config.tooltip) != 'undefined'){
6601 c.tooltip = config.tooltip;
6604 if(typeof(config.colspan) != 'undefined'){
6605 c.colspan = config.colspan;
6608 if(typeof(config.hidden) != 'undefined' && config.hidden){
6609 c.style += ' display:none;';
6612 if(typeof(config.dataIndex) != 'undefined'){
6613 c.sort = config.dataIndex;
6618 if(typeof(config.align) != 'undefined' && config.align.length){
6619 c.style += ' text-align:' + config.align + ';';
6622 if(typeof(config.width) != 'undefined'){
6623 c.style += ' width:' + config.width + 'px;';
6624 this.totalWidth += config.width;
6626 this.totalWidth += 100; // assume minimum of 100 per column?
6629 if(typeof(config.cls) != 'undefined'){
6630 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6633 ['xs','sm','md','lg'].map(function(size){
6635 if(typeof(config[size]) == 'undefined'){
6639 if (!config[size]) { // 0 = hidden
6640 c.cls += ' hidden-' + size;
6644 c.cls += ' col-' + size + '-' + config[size];
6654 renderBody : function()
6664 colspan : this.cm.getColumnCount()
6674 renderFooter : function()
6684 colspan : this.cm.getColumnCount()
6698 // Roo.log('ds onload');
6703 var ds = this.store;
6705 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6706 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6707 if (_this.store.sortInfo) {
6709 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6710 e.select('i', true).addClass(['glyphicon-arrow-up']);
6713 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6714 e.select('i', true).addClass(['glyphicon-arrow-down']);
6719 var tbody = this.mainBody;
6721 if(ds.getCount() > 0){
6722 ds.data.each(function(d,rowIndex){
6723 var row = this.renderRow(cm, ds, rowIndex);
6725 tbody.createChild(row);
6729 if(row.cellObjects.length){
6730 Roo.each(row.cellObjects, function(r){
6731 _this.renderCellObject(r);
6738 var tfoot = this.el.select('tfoot', true).first();
6740 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6742 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6744 var total = this.ds.getTotalCount();
6746 if(this.footer.pageSize < total){
6747 this.mainFoot.show();
6751 Roo.each(this.el.select('tbody td', true).elements, function(e){
6752 e.on('mouseover', _this.onMouseover, _this);
6755 Roo.each(this.el.select('tbody td', true).elements, function(e){
6756 e.on('mouseout', _this.onMouseout, _this);
6758 this.fireEvent('rowsrendered', this);
6764 onUpdate : function(ds,record)
6766 this.refreshRow(record);
6770 onRemove : function(ds, record, index, isUpdate){
6771 if(isUpdate !== true){
6772 this.fireEvent("beforerowremoved", this, index, record);
6774 var bt = this.mainBody.dom;
6776 var rows = this.el.select('tbody > tr', true).elements;
6778 if(typeof(rows[index]) != 'undefined'){
6779 bt.removeChild(rows[index].dom);
6782 // if(bt.rows[index]){
6783 // bt.removeChild(bt.rows[index]);
6786 if(isUpdate !== true){
6787 //this.stripeRows(index);
6788 //this.syncRowHeights(index, index);
6790 this.fireEvent("rowremoved", this, index, record);
6794 onAdd : function(ds, records, rowIndex)
6796 //Roo.log('on Add called');
6797 // - note this does not handle multiple adding very well..
6798 var bt = this.mainBody.dom;
6799 for (var i =0 ; i < records.length;i++) {
6800 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6801 //Roo.log(records[i]);
6802 //Roo.log(this.store.getAt(rowIndex+i));
6803 this.insertRow(this.store, rowIndex + i, false);
6810 refreshRow : function(record){
6811 var ds = this.store, index;
6812 if(typeof record == 'number'){
6814 record = ds.getAt(index);
6816 index = ds.indexOf(record);
6818 this.insertRow(ds, index, true);
6820 this.onRemove(ds, record, index+1, true);
6822 //this.syncRowHeights(index, index);
6824 this.fireEvent("rowupdated", this, index, record);
6827 insertRow : function(dm, rowIndex, isUpdate){
6830 this.fireEvent("beforerowsinserted", this, rowIndex);
6832 //var s = this.getScrollState();
6833 var row = this.renderRow(this.cm, this.store, rowIndex);
6834 // insert before rowIndex..
6835 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6839 if(row.cellObjects.length){
6840 Roo.each(row.cellObjects, function(r){
6841 _this.renderCellObject(r);
6846 this.fireEvent("rowsinserted", this, rowIndex);
6847 //this.syncRowHeights(firstRow, lastRow);
6848 //this.stripeRows(firstRow);
6855 getRowDom : function(rowIndex)
6857 var rows = this.el.select('tbody > tr', true).elements;
6859 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6862 // returns the object tree for a tr..
6865 renderRow : function(cm, ds, rowIndex)
6867 var d = ds.getAt(rowIndex);
6871 cls : 'x-row-' + rowIndex,
6875 var cellObjects = [];
6877 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6878 var config = cm.config[i];
6880 var renderer = cm.getRenderer(i);
6884 if(typeof(renderer) !== 'undefined'){
6885 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6887 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6888 // and are rendered into the cells after the row is rendered - using the id for the element.
6890 if(typeof(value) === 'object'){
6900 rowIndex : rowIndex,
6905 this.fireEvent('rowclass', this, rowcfg);
6909 cls : rowcfg.rowClass + ' x-col-' + i,
6911 html: (typeof(value) === 'object') ? '' : value
6918 if(typeof(config.colspan) != 'undefined'){
6919 td.colspan = config.colspan;
6922 if(typeof(config.hidden) != 'undefined' && config.hidden){
6923 td.style += ' display:none;';
6926 if(typeof(config.align) != 'undefined' && config.align.length){
6927 td.style += ' text-align:' + config.align + ';';
6929 if(typeof(config.valign) != 'undefined' && config.valign.length){
6930 td.style += ' vertical-align:' + config.valign + ';';
6933 if(typeof(config.width) != 'undefined'){
6934 td.style += ' width:' + config.width + 'px;';
6937 if(typeof(config.cursor) != 'undefined'){
6938 td.style += ' cursor:' + config.cursor + ';';
6941 if(typeof(config.cls) != 'undefined'){
6942 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6945 ['xs','sm','md','lg'].map(function(size){
6947 if(typeof(config[size]) == 'undefined'){
6951 if (!config[size]) { // 0 = hidden
6952 td.cls += ' hidden-' + size;
6956 td.cls += ' col-' + size + '-' + config[size];
6964 row.cellObjects = cellObjects;
6972 onBeforeLoad : function()
6981 this.el.select('tbody', true).first().dom.innerHTML = '';
6984 * Show or hide a row.
6985 * @param {Number} rowIndex to show or hide
6986 * @param {Boolean} state hide
6988 setRowVisibility : function(rowIndex, state)
6990 var bt = this.mainBody.dom;
6992 var rows = this.el.select('tbody > tr', true).elements;
6994 if(typeof(rows[rowIndex]) == 'undefined'){
6997 rows[rowIndex].dom.style.display = state ? '' : 'none';
7001 getSelectionModel : function(){
7003 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7005 return this.selModel;
7008 * Render the Roo.bootstrap object from renderder
7010 renderCellObject : function(r)
7014 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7016 var t = r.cfg.render(r.container);
7019 Roo.each(r.cfg.cn, function(c){
7021 container: t.getChildContainer(),
7024 _this.renderCellObject(child);
7029 getRowIndex : function(row)
7033 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7044 * Returns the grid's underlying element = used by panel.Grid
7045 * @return {Element} The element
7047 getGridEl : function(){
7051 * Forces a resize - used by panel.Grid
7052 * @return {Element} The element
7054 autoSize : function()
7056 //var ctr = Roo.get(this.container.dom.parentElement);
7057 var ctr = Roo.get(this.el.dom);
7059 var thd = this.getGridEl().select('thead',true).first();
7060 var tbd = this.getGridEl().select('tbody', true).first();
7061 var tfd = this.getGridEl().select('tfoot', true).first();
7063 var cw = ctr.getWidth();
7067 tbd.setSize(ctr.getWidth(),
7068 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7070 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7073 cw = Math.max(cw, this.totalWidth);
7074 this.getGridEl().select('tr',true).setWidth(cw);
7075 // resize 'expandable coloumn?
7077 return; // we doe not have a view in this design..
7080 onBodyScroll: function()
7082 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7084 this.mainHead.setStyle({
7085 'position' : 'relative',
7086 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7092 var scrollHeight = this.mainBody.dom.scrollHeight;
7094 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7096 var height = this.mainBody.getHeight();
7098 if(scrollHeight - height == scrollTop) {
7100 var total = this.ds.getTotalCount();
7102 if(this.footer.cursor + this.footer.pageSize < total){
7104 this.footer.ds.load({
7106 start : this.footer.cursor + this.footer.pageSize,
7107 limit : this.footer.pageSize
7117 onHeaderChange : function()
7119 var header = this.renderHeader();
7120 var table = this.el.select('table', true).first();
7122 this.mainHead.remove();
7123 this.mainHead = table.createChild(header, this.mainBody, false);
7126 onHiddenChange : function(colModel, colIndex, hidden)
7128 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7129 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7131 this.CSS.updateRule(thSelector, "display", "");
7132 this.CSS.updateRule(tdSelector, "display", "");
7135 this.CSS.updateRule(thSelector, "display", "none");
7136 this.CSS.updateRule(tdSelector, "display", "none");
7139 this.onHeaderChange();
7143 setColumnWidth: function(col_index, width)
7145 // width = "md-2 xs-2..."
7146 if(!this.colModel.config[col_index]) {
7150 var w = width.split(" ");
7152 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7154 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7157 for(var j = 0; j < w.length; j++) {
7163 var size_cls = w[j].split("-");
7165 if(!Number.isInteger(size_cls[1] * 1)) {
7169 if(!this.colModel.config[col_index][size_cls[0]]) {
7173 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7177 h_row[0].classList.replace(
7178 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7179 "col-"+size_cls[0]+"-"+size_cls[1]
7182 for(var i = 0; i < rows.length; i++) {
7184 var size_cls = w[j].split("-");
7186 if(!Number.isInteger(size_cls[1] * 1)) {
7190 if(!this.colModel.config[col_index][size_cls[0]]) {
7194 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7198 rows[i].classList.replace(
7199 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7200 "col-"+size_cls[0]+"-"+size_cls[1]
7204 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7219 * @class Roo.bootstrap.TableCell
7220 * @extends Roo.bootstrap.Component
7221 * Bootstrap TableCell class
7222 * @cfg {String} html cell contain text
7223 * @cfg {String} cls cell class
7224 * @cfg {String} tag cell tag (td|th) default td
7225 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7226 * @cfg {String} align Aligns the content in a cell
7227 * @cfg {String} axis Categorizes cells
7228 * @cfg {String} bgcolor Specifies the background color of a cell
7229 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7230 * @cfg {Number} colspan Specifies the number of columns a cell should span
7231 * @cfg {String} headers Specifies one or more header cells a cell is related to
7232 * @cfg {Number} height Sets the height of a cell
7233 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7234 * @cfg {Number} rowspan Sets the number of rows a cell should span
7235 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7236 * @cfg {String} valign Vertical aligns the content in a cell
7237 * @cfg {Number} width Specifies the width of a cell
7240 * Create a new TableCell
7241 * @param {Object} config The config object
7244 Roo.bootstrap.TableCell = function(config){
7245 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7248 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7268 getAutoCreate : function(){
7269 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7289 cfg.align=this.align
7295 cfg.bgcolor=this.bgcolor
7298 cfg.charoff=this.charoff
7301 cfg.colspan=this.colspan
7304 cfg.headers=this.headers
7307 cfg.height=this.height
7310 cfg.nowrap=this.nowrap
7313 cfg.rowspan=this.rowspan
7316 cfg.scope=this.scope
7319 cfg.valign=this.valign
7322 cfg.width=this.width
7341 * @class Roo.bootstrap.TableRow
7342 * @extends Roo.bootstrap.Component
7343 * Bootstrap TableRow class
7344 * @cfg {String} cls row class
7345 * @cfg {String} align Aligns the content in a table row
7346 * @cfg {String} bgcolor Specifies a background color for a table row
7347 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7348 * @cfg {String} valign Vertical aligns the content in a table row
7351 * Create a new TableRow
7352 * @param {Object} config The config object
7355 Roo.bootstrap.TableRow = function(config){
7356 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7359 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7367 getAutoCreate : function(){
7368 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7378 cfg.align = this.align;
7381 cfg.bgcolor = this.bgcolor;
7384 cfg.charoff = this.charoff;
7387 cfg.valign = this.valign;
7405 * @class Roo.bootstrap.TableBody
7406 * @extends Roo.bootstrap.Component
7407 * Bootstrap TableBody class
7408 * @cfg {String} cls element class
7409 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7410 * @cfg {String} align Aligns the content inside the element
7411 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7412 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7415 * Create a new TableBody
7416 * @param {Object} config The config object
7419 Roo.bootstrap.TableBody = function(config){
7420 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7423 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7431 getAutoCreate : function(){
7432 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7446 cfg.align = this.align;
7449 cfg.charoff = this.charoff;
7452 cfg.valign = this.valign;
7459 // initEvents : function()
7466 // this.store = Roo.factory(this.store, Roo.data);
7467 // this.store.on('load', this.onLoad, this);
7469 // this.store.load();
7473 // onLoad: function ()
7475 // this.fireEvent('load', this);
7485 * Ext JS Library 1.1.1
7486 * Copyright(c) 2006-2007, Ext JS, LLC.
7488 * Originally Released Under LGPL - original licence link has changed is not relivant.
7491 * <script type="text/javascript">
7494 // as we use this in bootstrap.
7495 Roo.namespace('Roo.form');
7497 * @class Roo.form.Action
7498 * Internal Class used to handle form actions
7500 * @param {Roo.form.BasicForm} el The form element or its id
7501 * @param {Object} config Configuration options
7506 // define the action interface
7507 Roo.form.Action = function(form, options){
7509 this.options = options || {};
7512 * Client Validation Failed
7515 Roo.form.Action.CLIENT_INVALID = 'client';
7517 * Server Validation Failed
7520 Roo.form.Action.SERVER_INVALID = 'server';
7522 * Connect to Server Failed
7525 Roo.form.Action.CONNECT_FAILURE = 'connect';
7527 * Reading Data from Server Failed
7530 Roo.form.Action.LOAD_FAILURE = 'load';
7532 Roo.form.Action.prototype = {
7534 failureType : undefined,
7535 response : undefined,
7539 run : function(options){
7544 success : function(response){
7549 handleResponse : function(response){
7553 // default connection failure
7554 failure : function(response){
7556 this.response = response;
7557 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7558 this.form.afterAction(this, false);
7561 processResponse : function(response){
7562 this.response = response;
7563 if(!response.responseText){
7566 this.result = this.handleResponse(response);
7570 // utility functions used internally
7571 getUrl : function(appendParams){
7572 var url = this.options.url || this.form.url || this.form.el.dom.action;
7574 var p = this.getParams();
7576 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7582 getMethod : function(){
7583 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7586 getParams : function(){
7587 var bp = this.form.baseParams;
7588 var p = this.options.params;
7590 if(typeof p == "object"){
7591 p = Roo.urlEncode(Roo.applyIf(p, bp));
7592 }else if(typeof p == 'string' && bp){
7593 p += '&' + Roo.urlEncode(bp);
7596 p = Roo.urlEncode(bp);
7601 createCallback : function(){
7603 success: this.success,
7604 failure: this.failure,
7606 timeout: (this.form.timeout*1000),
7607 upload: this.form.fileUpload ? this.success : undefined
7612 Roo.form.Action.Submit = function(form, options){
7613 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7616 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7619 haveProgress : false,
7620 uploadComplete : false,
7622 // uploadProgress indicator.
7623 uploadProgress : function()
7625 if (!this.form.progressUrl) {
7629 if (!this.haveProgress) {
7630 Roo.MessageBox.progress("Uploading", "Uploading");
7632 if (this.uploadComplete) {
7633 Roo.MessageBox.hide();
7637 this.haveProgress = true;
7639 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7641 var c = new Roo.data.Connection();
7643 url : this.form.progressUrl,
7648 success : function(req){
7649 //console.log(data);
7653 rdata = Roo.decode(req.responseText)
7655 Roo.log("Invalid data from server..");
7659 if (!rdata || !rdata.success) {
7661 Roo.MessageBox.alert(Roo.encode(rdata));
7664 var data = rdata.data;
7666 if (this.uploadComplete) {
7667 Roo.MessageBox.hide();
7672 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7673 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7676 this.uploadProgress.defer(2000,this);
7679 failure: function(data) {
7680 Roo.log('progress url failed ');
7691 // run get Values on the form, so it syncs any secondary forms.
7692 this.form.getValues();
7694 var o = this.options;
7695 var method = this.getMethod();
7696 var isPost = method == 'POST';
7697 if(o.clientValidation === false || this.form.isValid()){
7699 if (this.form.progressUrl) {
7700 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7701 (new Date() * 1) + '' + Math.random());
7706 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7707 form:this.form.el.dom,
7708 url:this.getUrl(!isPost),
7710 params:isPost ? this.getParams() : null,
7711 isUpload: this.form.fileUpload
7714 this.uploadProgress();
7716 }else if (o.clientValidation !== false){ // client validation failed
7717 this.failureType = Roo.form.Action.CLIENT_INVALID;
7718 this.form.afterAction(this, false);
7722 success : function(response)
7724 this.uploadComplete= true;
7725 if (this.haveProgress) {
7726 Roo.MessageBox.hide();
7730 var result = this.processResponse(response);
7731 if(result === true || result.success){
7732 this.form.afterAction(this, true);
7736 this.form.markInvalid(result.errors);
7737 this.failureType = Roo.form.Action.SERVER_INVALID;
7739 this.form.afterAction(this, false);
7741 failure : function(response)
7743 this.uploadComplete= true;
7744 if (this.haveProgress) {
7745 Roo.MessageBox.hide();
7748 this.response = response;
7749 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7750 this.form.afterAction(this, false);
7753 handleResponse : function(response){
7754 if(this.form.errorReader){
7755 var rs = this.form.errorReader.read(response);
7758 for(var i = 0, len = rs.records.length; i < len; i++) {
7759 var r = rs.records[i];
7763 if(errors.length < 1){
7767 success : rs.success,
7773 ret = Roo.decode(response.responseText);
7777 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7787 Roo.form.Action.Load = function(form, options){
7788 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7789 this.reader = this.form.reader;
7792 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7797 Roo.Ajax.request(Roo.apply(
7798 this.createCallback(), {
7799 method:this.getMethod(),
7800 url:this.getUrl(false),
7801 params:this.getParams()
7805 success : function(response){
7807 var result = this.processResponse(response);
7808 if(result === true || !result.success || !result.data){
7809 this.failureType = Roo.form.Action.LOAD_FAILURE;
7810 this.form.afterAction(this, false);
7813 this.form.clearInvalid();
7814 this.form.setValues(result.data);
7815 this.form.afterAction(this, true);
7818 handleResponse : function(response){
7819 if(this.form.reader){
7820 var rs = this.form.reader.read(response);
7821 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7823 success : rs.success,
7827 return Roo.decode(response.responseText);
7831 Roo.form.Action.ACTION_TYPES = {
7832 'load' : Roo.form.Action.Load,
7833 'submit' : Roo.form.Action.Submit
7842 * @class Roo.bootstrap.Form
7843 * @extends Roo.bootstrap.Component
7844 * Bootstrap Form class
7845 * @cfg {String} method GET | POST (default POST)
7846 * @cfg {String} labelAlign top | left (default top)
7847 * @cfg {String} align left | right - for navbars
7848 * @cfg {Boolean} loadMask load mask when submit (default true)
7853 * @param {Object} config The config object
7857 Roo.bootstrap.Form = function(config){
7859 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7861 Roo.bootstrap.Form.popover.apply();
7865 * @event clientvalidation
7866 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7867 * @param {Form} this
7868 * @param {Boolean} valid true if the form has passed client-side validation
7870 clientvalidation: true,
7872 * @event beforeaction
7873 * Fires before any action is performed. Return false to cancel the action.
7874 * @param {Form} this
7875 * @param {Action} action The action to be performed
7879 * @event actionfailed
7880 * Fires when an action fails.
7881 * @param {Form} this
7882 * @param {Action} action The action that failed
7884 actionfailed : true,
7886 * @event actioncomplete
7887 * Fires when an action is completed.
7888 * @param {Form} this
7889 * @param {Action} action The action that completed
7891 actioncomplete : true
7895 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7898 * @cfg {String} method
7899 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7904 * The URL to use for form actions if one isn't supplied in the action options.
7907 * @cfg {Boolean} fileUpload
7908 * Set to true if this form is a file upload.
7912 * @cfg {Object} baseParams
7913 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7917 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7921 * @cfg {Sting} align (left|right) for navbar forms
7926 activeAction : null,
7929 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7930 * element by passing it or its id or mask the form itself by passing in true.
7933 waitMsgTarget : false,
7938 * @cfg {Boolean} errorMask (true|false) default false
7943 * @cfg {Number} maskOffset Default 100
7948 * @cfg {Boolean} maskBody
7952 getAutoCreate : function(){
7956 method : this.method || 'POST',
7957 id : this.id || Roo.id(),
7960 if (this.parent().xtype.match(/^Nav/)) {
7961 cfg.cls = 'navbar-form navbar-' + this.align;
7965 if (this.labelAlign == 'left' ) {
7966 cfg.cls += ' form-horizontal';
7972 initEvents : function()
7974 this.el.on('submit', this.onSubmit, this);
7975 // this was added as random key presses on the form where triggering form submit.
7976 this.el.on('keypress', function(e) {
7977 if (e.getCharCode() != 13) {
7980 // we might need to allow it for textareas.. and some other items.
7981 // check e.getTarget().
7983 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7987 Roo.log("keypress blocked");
7995 onSubmit : function(e){
8000 * Returns true if client-side validation on the form is successful.
8003 isValid : function(){
8004 var items = this.getItems();
8008 items.each(function(f){
8014 Roo.log('invalid field: ' + f.name);
8018 if(!target && f.el.isVisible(true)){
8024 if(this.errorMask && !valid){
8025 Roo.bootstrap.Form.popover.mask(this, target);
8032 * Returns true if any fields in this form have changed since their original load.
8035 isDirty : function(){
8037 var items = this.getItems();
8038 items.each(function(f){
8048 * Performs a predefined action (submit or load) or custom actions you define on this form.
8049 * @param {String} actionName The name of the action type
8050 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8051 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8052 * accept other config options):
8054 Property Type Description
8055 ---------------- --------------- ----------------------------------------------------------------------------------
8056 url String The url for the action (defaults to the form's url)
8057 method String The form method to use (defaults to the form's method, or POST if not defined)
8058 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8059 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8060 validate the form on the client (defaults to false)
8062 * @return {BasicForm} this
8064 doAction : function(action, options){
8065 if(typeof action == 'string'){
8066 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8068 if(this.fireEvent('beforeaction', this, action) !== false){
8069 this.beforeAction(action);
8070 action.run.defer(100, action);
8076 beforeAction : function(action){
8077 var o = action.options;
8082 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8084 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8087 // not really supported yet.. ??
8089 //if(this.waitMsgTarget === true){
8090 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8091 //}else if(this.waitMsgTarget){
8092 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8093 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8095 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8101 afterAction : function(action, success){
8102 this.activeAction = null;
8103 var o = action.options;
8108 Roo.get(document.body).unmask();
8114 //if(this.waitMsgTarget === true){
8115 // this.el.unmask();
8116 //}else if(this.waitMsgTarget){
8117 // this.waitMsgTarget.unmask();
8119 // Roo.MessageBox.updateProgress(1);
8120 // Roo.MessageBox.hide();
8127 Roo.callback(o.success, o.scope, [this, action]);
8128 this.fireEvent('actioncomplete', this, action);
8132 // failure condition..
8133 // we have a scenario where updates need confirming.
8134 // eg. if a locking scenario exists..
8135 // we look for { errors : { needs_confirm : true }} in the response.
8137 (typeof(action.result) != 'undefined') &&
8138 (typeof(action.result.errors) != 'undefined') &&
8139 (typeof(action.result.errors.needs_confirm) != 'undefined')
8142 Roo.log("not supported yet");
8145 Roo.MessageBox.confirm(
8146 "Change requires confirmation",
8147 action.result.errorMsg,
8152 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8162 Roo.callback(o.failure, o.scope, [this, action]);
8163 // show an error message if no failed handler is set..
8164 if (!this.hasListener('actionfailed')) {
8165 Roo.log("need to add dialog support");
8167 Roo.MessageBox.alert("Error",
8168 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8169 action.result.errorMsg :
8170 "Saving Failed, please check your entries or try again"
8175 this.fireEvent('actionfailed', this, action);
8180 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8181 * @param {String} id The value to search for
8184 findField : function(id){
8185 var items = this.getItems();
8186 var field = items.get(id);
8188 items.each(function(f){
8189 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8196 return field || null;
8199 * Mark fields in this form invalid in bulk.
8200 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8201 * @return {BasicForm} this
8203 markInvalid : function(errors){
8204 if(errors instanceof Array){
8205 for(var i = 0, len = errors.length; i < len; i++){
8206 var fieldError = errors[i];
8207 var f = this.findField(fieldError.id);
8209 f.markInvalid(fieldError.msg);
8215 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8216 field.markInvalid(errors[id]);
8220 //Roo.each(this.childForms || [], function (f) {
8221 // f.markInvalid(errors);
8228 * Set values for fields in this form in bulk.
8229 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8230 * @return {BasicForm} this
8232 setValues : function(values){
8233 if(values instanceof Array){ // array of objects
8234 for(var i = 0, len = values.length; i < len; i++){
8236 var f = this.findField(v.id);
8238 f.setValue(v.value);
8239 if(this.trackResetOnLoad){
8240 f.originalValue = f.getValue();
8244 }else{ // object hash
8247 if(typeof values[id] != 'function' && (field = this.findField(id))){
8249 if (field.setFromData &&
8251 field.displayField &&
8252 // combos' with local stores can
8253 // be queried via setValue()
8254 // to set their value..
8255 (field.store && !field.store.isLocal)
8259 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8260 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8261 field.setFromData(sd);
8263 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8265 field.setFromData(values);
8268 field.setValue(values[id]);
8272 if(this.trackResetOnLoad){
8273 field.originalValue = field.getValue();
8279 //Roo.each(this.childForms || [], function (f) {
8280 // f.setValues(values);
8287 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8288 * they are returned as an array.
8289 * @param {Boolean} asString
8292 getValues : function(asString){
8293 //if (this.childForms) {
8294 // copy values from the child forms
8295 // Roo.each(this.childForms, function (f) {
8296 // this.setValues(f.getValues());
8302 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8303 if(asString === true){
8306 return Roo.urlDecode(fs);
8310 * Returns the fields in this form as an object with key/value pairs.
8311 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8314 getFieldValues : function(with_hidden)
8316 var items = this.getItems();
8318 items.each(function(f){
8324 var v = f.getValue();
8326 if (f.inputType =='radio') {
8327 if (typeof(ret[f.getName()]) == 'undefined') {
8328 ret[f.getName()] = ''; // empty..
8331 if (!f.el.dom.checked) {
8339 if(f.xtype == 'MoneyField'){
8340 ret[f.currencyName] = f.getCurrency();
8343 // not sure if this supported any more..
8344 if ((typeof(v) == 'object') && f.getRawValue) {
8345 v = f.getRawValue() ; // dates..
8347 // combo boxes where name != hiddenName...
8348 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8349 ret[f.name] = f.getRawValue();
8351 ret[f.getName()] = v;
8358 * Clears all invalid messages in this form.
8359 * @return {BasicForm} this
8361 clearInvalid : function(){
8362 var items = this.getItems();
8364 items.each(function(f){
8373 * @return {BasicForm} this
8376 var items = this.getItems();
8377 items.each(function(f){
8381 Roo.each(this.childForms || [], function (f) {
8389 getItems : function()
8391 var r=new Roo.util.MixedCollection(false, function(o){
8392 return o.id || (o.id = Roo.id());
8394 var iter = function(el) {
8401 Roo.each(el.items,function(e) {
8410 hideFields : function(items)
8412 Roo.each(items, function(i){
8414 var f = this.findField(i);
8425 showFields : function(items)
8427 Roo.each(items, function(i){
8429 var f = this.findField(i);
8442 Roo.apply(Roo.bootstrap.Form, {
8469 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8470 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8471 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8472 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8475 this.maskEl.top.enableDisplayMode("block");
8476 this.maskEl.left.enableDisplayMode("block");
8477 this.maskEl.bottom.enableDisplayMode("block");
8478 this.maskEl.right.enableDisplayMode("block");
8480 this.toolTip = new Roo.bootstrap.Tooltip({
8481 cls : 'roo-form-error-popover',
8483 'left' : ['r-l', [-2,0], 'right'],
8484 'right' : ['l-r', [2,0], 'left'],
8485 'bottom' : ['tl-bl', [0,2], 'top'],
8486 'top' : [ 'bl-tl', [0,-2], 'bottom']
8490 this.toolTip.render(Roo.get(document.body));
8492 this.toolTip.el.enableDisplayMode("block");
8494 Roo.get(document.body).on('click', function(){
8498 Roo.get(document.body).on('touchstart', function(){
8502 this.isApplied = true
8505 mask : function(form, target)
8509 this.target = target;
8511 if(!this.form.errorMask || !target.el){
8515 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8517 Roo.log(scrollable);
8519 var ot = this.target.el.calcOffsetsTo(scrollable);
8521 var scrollTo = ot[1] - this.form.maskOffset;
8523 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8525 scrollable.scrollTo('top', scrollTo);
8527 var box = this.target.el.getBox();
8529 var zIndex = Roo.bootstrap.Modal.zIndex++;
8532 this.maskEl.top.setStyle('position', 'absolute');
8533 this.maskEl.top.setStyle('z-index', zIndex);
8534 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8535 this.maskEl.top.setLeft(0);
8536 this.maskEl.top.setTop(0);
8537 this.maskEl.top.show();
8539 this.maskEl.left.setStyle('position', 'absolute');
8540 this.maskEl.left.setStyle('z-index', zIndex);
8541 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8542 this.maskEl.left.setLeft(0);
8543 this.maskEl.left.setTop(box.y - this.padding);
8544 this.maskEl.left.show();
8546 this.maskEl.bottom.setStyle('position', 'absolute');
8547 this.maskEl.bottom.setStyle('z-index', zIndex);
8548 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8549 this.maskEl.bottom.setLeft(0);
8550 this.maskEl.bottom.setTop(box.bottom + this.padding);
8551 this.maskEl.bottom.show();
8553 this.maskEl.right.setStyle('position', 'absolute');
8554 this.maskEl.right.setStyle('z-index', zIndex);
8555 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8556 this.maskEl.right.setLeft(box.right + this.padding);
8557 this.maskEl.right.setTop(box.y - this.padding);
8558 this.maskEl.right.show();
8560 this.toolTip.bindEl = this.target.el;
8562 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8564 var tip = this.target.blankText;
8566 if(this.target.getValue() !== '' ) {
8568 if (this.target.invalidText.length) {
8569 tip = this.target.invalidText;
8570 } else if (this.target.regexText.length){
8571 tip = this.target.regexText;
8575 this.toolTip.show(tip);
8577 this.intervalID = window.setInterval(function() {
8578 Roo.bootstrap.Form.popover.unmask();
8581 window.onwheel = function(){ return false;};
8583 (function(){ this.isMasked = true; }).defer(500, this);
8589 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8593 this.maskEl.top.setStyle('position', 'absolute');
8594 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8595 this.maskEl.top.hide();
8597 this.maskEl.left.setStyle('position', 'absolute');
8598 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8599 this.maskEl.left.hide();
8601 this.maskEl.bottom.setStyle('position', 'absolute');
8602 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8603 this.maskEl.bottom.hide();
8605 this.maskEl.right.setStyle('position', 'absolute');
8606 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8607 this.maskEl.right.hide();
8609 this.toolTip.hide();
8611 this.toolTip.el.hide();
8613 window.onwheel = function(){ return true;};
8615 if(this.intervalID){
8616 window.clearInterval(this.intervalID);
8617 this.intervalID = false;
8620 this.isMasked = false;
8630 * Ext JS Library 1.1.1
8631 * Copyright(c) 2006-2007, Ext JS, LLC.
8633 * Originally Released Under LGPL - original licence link has changed is not relivant.
8636 * <script type="text/javascript">
8639 * @class Roo.form.VTypes
8640 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8643 Roo.form.VTypes = function(){
8644 // closure these in so they are only created once.
8645 var alpha = /^[a-zA-Z_]+$/;
8646 var alphanum = /^[a-zA-Z0-9_]+$/;
8647 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8648 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8650 // All these messages and functions are configurable
8653 * The function used to validate email addresses
8654 * @param {String} value The email address
8656 'email' : function(v){
8657 return email.test(v);
8660 * The error text to display when the email validation function returns false
8663 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8665 * The keystroke filter mask to be applied on email input
8668 'emailMask' : /[a-z0-9_\.\-@]/i,
8671 * The function used to validate URLs
8672 * @param {String} value The URL
8674 'url' : function(v){
8678 * The error text to display when the url validation function returns false
8681 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8684 * The function used to validate alpha values
8685 * @param {String} value The value
8687 'alpha' : function(v){
8688 return alpha.test(v);
8691 * The error text to display when the alpha validation function returns false
8694 'alphaText' : 'This field should only contain letters and _',
8696 * The keystroke filter mask to be applied on alpha input
8699 'alphaMask' : /[a-z_]/i,
8702 * The function used to validate alphanumeric values
8703 * @param {String} value The value
8705 'alphanum' : function(v){
8706 return alphanum.test(v);
8709 * The error text to display when the alphanumeric validation function returns false
8712 'alphanumText' : 'This field should only contain letters, numbers and _',
8714 * The keystroke filter mask to be applied on alphanumeric input
8717 'alphanumMask' : /[a-z0-9_]/i
8727 * @class Roo.bootstrap.Input
8728 * @extends Roo.bootstrap.Component
8729 * Bootstrap Input class
8730 * @cfg {Boolean} disabled is it disabled
8731 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8732 * @cfg {String} name name of the input
8733 * @cfg {string} fieldLabel - the label associated
8734 * @cfg {string} placeholder - placeholder to put in text.
8735 * @cfg {string} before - input group add on before
8736 * @cfg {string} after - input group add on after
8737 * @cfg {string} size - (lg|sm) or leave empty..
8738 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8739 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8740 * @cfg {Number} md colspan out of 12 for computer-sized screens
8741 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8742 * @cfg {string} value default value of the input
8743 * @cfg {Number} labelWidth set the width of label
8744 * @cfg {Number} labellg set the width of label (1-12)
8745 * @cfg {Number} labelmd set the width of label (1-12)
8746 * @cfg {Number} labelsm set the width of label (1-12)
8747 * @cfg {Number} labelxs set the width of label (1-12)
8748 * @cfg {String} labelAlign (top|left)
8749 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8750 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8751 * @cfg {String} indicatorpos (left|right) default left
8752 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8753 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8755 * @cfg {String} align (left|center|right) Default left
8756 * @cfg {Boolean} forceFeedback (true|false) Default false
8759 * Create a new Input
8760 * @param {Object} config The config object
8763 Roo.bootstrap.Input = function(config){
8765 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8770 * Fires when this field receives input focus.
8771 * @param {Roo.form.Field} this
8776 * Fires when this field loses input focus.
8777 * @param {Roo.form.Field} this
8782 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8783 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8784 * @param {Roo.form.Field} this
8785 * @param {Roo.EventObject} e The event object
8790 * Fires just before the field blurs if the field value has changed.
8791 * @param {Roo.form.Field} this
8792 * @param {Mixed} newValue The new value
8793 * @param {Mixed} oldValue The original value
8798 * Fires after the field has been marked as invalid.
8799 * @param {Roo.form.Field} this
8800 * @param {String} msg The validation message
8805 * Fires after the field has been validated with no errors.
8806 * @param {Roo.form.Field} this
8811 * Fires after the key up
8812 * @param {Roo.form.Field} this
8813 * @param {Roo.EventObject} e The event Object
8819 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8821 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8822 automatic validation (defaults to "keyup").
8824 validationEvent : "keyup",
8826 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8828 validateOnBlur : true,
8830 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8832 validationDelay : 250,
8834 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8836 focusClass : "x-form-focus", // not needed???
8840 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8842 invalidClass : "has-warning",
8845 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8847 validClass : "has-success",
8850 * @cfg {Boolean} hasFeedback (true|false) default true
8855 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8857 invalidFeedbackClass : "glyphicon-warning-sign",
8860 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8862 validFeedbackClass : "glyphicon-ok",
8865 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8867 selectOnFocus : false,
8870 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8874 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8879 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8881 disableKeyFilter : false,
8884 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8888 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8892 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8894 blankText : "Please complete this mandatory field",
8897 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8901 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8903 maxLength : Number.MAX_VALUE,
8905 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8907 minLengthText : "The minimum length for this field is {0}",
8909 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8911 maxLengthText : "The maximum length for this field is {0}",
8915 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8916 * If available, this function will be called only after the basic validators all return true, and will be passed the
8917 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8921 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8922 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8923 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8927 * @cfg {String} regexText -- Depricated - use Invalid Text
8932 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8938 autocomplete: false,
8957 formatedValue : false,
8958 forceFeedback : false,
8960 indicatorpos : 'left',
8970 parentLabelAlign : function()
8973 while (parent.parent()) {
8974 parent = parent.parent();
8975 if (typeof(parent.labelAlign) !='undefined') {
8976 return parent.labelAlign;
8983 getAutoCreate : function()
8985 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8991 if(this.inputType != 'hidden'){
8992 cfg.cls = 'form-group' //input-group
8998 type : this.inputType,
9000 cls : 'form-control',
9001 placeholder : this.placeholder || '',
9002 autocomplete : this.autocomplete || 'new-password'
9005 if(this.capture.length){
9006 input.capture = this.capture;
9009 if(this.accept.length){
9010 input.accept = this.accept + "/*";
9014 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9017 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9018 input.maxLength = this.maxLength;
9021 if (this.disabled) {
9022 input.disabled=true;
9025 if (this.readOnly) {
9026 input.readonly=true;
9030 input.name = this.name;
9034 input.cls += ' input-' + this.size;
9038 ['xs','sm','md','lg'].map(function(size){
9039 if (settings[size]) {
9040 cfg.cls += ' col-' + size + '-' + settings[size];
9044 var inputblock = input;
9048 cls: 'glyphicon form-control-feedback'
9051 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9054 cls : 'has-feedback',
9062 if (this.before || this.after) {
9065 cls : 'input-group',
9069 if (this.before && typeof(this.before) == 'string') {
9071 inputblock.cn.push({
9073 cls : 'roo-input-before input-group-addon',
9077 if (this.before && typeof(this.before) == 'object') {
9078 this.before = Roo.factory(this.before);
9080 inputblock.cn.push({
9082 cls : 'roo-input-before input-group-' +
9083 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9087 inputblock.cn.push(input);
9089 if (this.after && typeof(this.after) == 'string') {
9090 inputblock.cn.push({
9092 cls : 'roo-input-after input-group-addon',
9096 if (this.after && typeof(this.after) == 'object') {
9097 this.after = Roo.factory(this.after);
9099 inputblock.cn.push({
9101 cls : 'roo-input-after input-group-' +
9102 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9106 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9107 inputblock.cls += ' has-feedback';
9108 inputblock.cn.push(feedback);
9112 if (align ==='left' && this.fieldLabel.length) {
9114 cfg.cls += ' roo-form-group-label-left';
9119 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9120 tooltip : 'This field is required'
9125 cls : 'control-label',
9126 html : this.fieldLabel
9137 var labelCfg = cfg.cn[1];
9138 var contentCfg = cfg.cn[2];
9140 if(this.indicatorpos == 'right'){
9145 cls : 'control-label',
9149 html : this.fieldLabel
9153 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9154 tooltip : 'This field is required'
9167 labelCfg = cfg.cn[0];
9168 contentCfg = cfg.cn[1];
9172 if(this.labelWidth > 12){
9173 labelCfg.style = "width: " + this.labelWidth + 'px';
9176 if(this.labelWidth < 13 && this.labelmd == 0){
9177 this.labelmd = this.labelWidth;
9180 if(this.labellg > 0){
9181 labelCfg.cls += ' col-lg-' + this.labellg;
9182 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9185 if(this.labelmd > 0){
9186 labelCfg.cls += ' col-md-' + this.labelmd;
9187 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9190 if(this.labelsm > 0){
9191 labelCfg.cls += ' col-sm-' + this.labelsm;
9192 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9195 if(this.labelxs > 0){
9196 labelCfg.cls += ' col-xs-' + this.labelxs;
9197 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9201 } else if ( this.fieldLabel.length) {
9206 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9207 tooltip : 'This field is required'
9211 //cls : 'input-group-addon',
9212 html : this.fieldLabel
9220 if(this.indicatorpos == 'right'){
9225 //cls : 'input-group-addon',
9226 html : this.fieldLabel
9231 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9232 tooltip : 'This field is required'
9252 if (this.parentType === 'Navbar' && this.parent().bar) {
9253 cfg.cls += ' navbar-form';
9256 if (this.parentType === 'NavGroup') {
9257 cfg.cls += ' navbar-form';
9265 * return the real input element.
9267 inputEl: function ()
9269 return this.el.select('input.form-control',true).first();
9272 tooltipEl : function()
9274 return this.inputEl();
9277 indicatorEl : function()
9279 var indicator = this.el.select('i.roo-required-indicator',true).first();
9289 setDisabled : function(v)
9291 var i = this.inputEl().dom;
9293 i.removeAttribute('disabled');
9297 i.setAttribute('disabled','true');
9299 initEvents : function()
9302 this.inputEl().on("keydown" , this.fireKey, this);
9303 this.inputEl().on("focus", this.onFocus, this);
9304 this.inputEl().on("blur", this.onBlur, this);
9306 this.inputEl().relayEvent('keyup', this);
9308 this.indicator = this.indicatorEl();
9311 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9314 // reference to original value for reset
9315 this.originalValue = this.getValue();
9316 //Roo.form.TextField.superclass.initEvents.call(this);
9317 if(this.validationEvent == 'keyup'){
9318 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9319 this.inputEl().on('keyup', this.filterValidation, this);
9321 else if(this.validationEvent !== false){
9322 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9325 if(this.selectOnFocus){
9326 this.on("focus", this.preFocus, this);
9329 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9330 this.inputEl().on("keypress", this.filterKeys, this);
9332 this.inputEl().relayEvent('keypress', this);
9335 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9336 this.el.on("click", this.autoSize, this);
9339 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9340 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9343 if (typeof(this.before) == 'object') {
9344 this.before.render(this.el.select('.roo-input-before',true).first());
9346 if (typeof(this.after) == 'object') {
9347 this.after.render(this.el.select('.roo-input-after',true).first());
9350 this.inputEl().on('change', this.onChange, this);
9353 filterValidation : function(e){
9354 if(!e.isNavKeyPress()){
9355 this.validationTask.delay(this.validationDelay);
9359 * Validates the field value
9360 * @return {Boolean} True if the value is valid, else false
9362 validate : function(){
9363 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9364 if(this.disabled || this.validateValue(this.getRawValue())){
9375 * Validates a value according to the field's validation rules and marks the field as invalid
9376 * if the validation fails
9377 * @param {Mixed} value The value to validate
9378 * @return {Boolean} True if the value is valid, else false
9380 validateValue : function(value)
9382 if(this.getVisibilityEl().hasClass('hidden')){
9386 if(value.length < 1) { // if it's blank
9387 if(this.allowBlank){
9393 if(value.length < this.minLength){
9396 if(value.length > this.maxLength){
9400 var vt = Roo.form.VTypes;
9401 if(!vt[this.vtype](value, this)){
9405 if(typeof this.validator == "function"){
9406 var msg = this.validator(value);
9410 if (typeof(msg) == 'string') {
9411 this.invalidText = msg;
9415 if(this.regex && !this.regex.test(value)){
9423 fireKey : function(e){
9424 //Roo.log('field ' + e.getKey());
9425 if(e.isNavKeyPress()){
9426 this.fireEvent("specialkey", this, e);
9429 focus : function (selectText){
9431 this.inputEl().focus();
9432 if(selectText === true){
9433 this.inputEl().dom.select();
9439 onFocus : function(){
9440 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9441 // this.el.addClass(this.focusClass);
9444 this.hasFocus = true;
9445 this.startValue = this.getValue();
9446 this.fireEvent("focus", this);
9450 beforeBlur : Roo.emptyFn,
9454 onBlur : function(){
9456 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9457 //this.el.removeClass(this.focusClass);
9459 this.hasFocus = false;
9460 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9463 var v = this.getValue();
9464 if(String(v) !== String(this.startValue)){
9465 this.fireEvent('change', this, v, this.startValue);
9467 this.fireEvent("blur", this);
9470 onChange : function(e)
9472 var v = this.getValue();
9473 if(String(v) !== String(this.startValue)){
9474 this.fireEvent('change', this, v, this.startValue);
9480 * Resets the current field value to the originally loaded value and clears any validation messages
9483 this.setValue(this.originalValue);
9487 * Returns the name of the field
9488 * @return {Mixed} name The name field
9490 getName: function(){
9494 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9495 * @return {Mixed} value The field value
9497 getValue : function(){
9499 var v = this.inputEl().getValue();
9504 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9505 * @return {Mixed} value The field value
9507 getRawValue : function(){
9508 var v = this.inputEl().getValue();
9514 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9515 * @param {Mixed} value The value to set
9517 setRawValue : function(v){
9518 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9521 selectText : function(start, end){
9522 var v = this.getRawValue();
9524 start = start === undefined ? 0 : start;
9525 end = end === undefined ? v.length : end;
9526 var d = this.inputEl().dom;
9527 if(d.setSelectionRange){
9528 d.setSelectionRange(start, end);
9529 }else if(d.createTextRange){
9530 var range = d.createTextRange();
9531 range.moveStart("character", start);
9532 range.moveEnd("character", v.length-end);
9539 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9540 * @param {Mixed} value The value to set
9542 setValue : function(v){
9545 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9551 processValue : function(value){
9552 if(this.stripCharsRe){
9553 var newValue = value.replace(this.stripCharsRe, '');
9554 if(newValue !== value){
9555 this.setRawValue(newValue);
9562 preFocus : function(){
9564 if(this.selectOnFocus){
9565 this.inputEl().dom.select();
9568 filterKeys : function(e){
9570 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9573 var c = e.getCharCode(), cc = String.fromCharCode(c);
9574 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9577 if(!this.maskRe.test(cc)){
9582 * Clear any invalid styles/messages for this field
9584 clearInvalid : function(){
9586 if(!this.el || this.preventMark){ // not rendered
9591 this.el.removeClass(this.invalidClass);
9593 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9595 var feedback = this.el.select('.form-control-feedback', true).first();
9598 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9604 this.indicator.removeClass('visible');
9605 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9608 this.fireEvent('valid', this);
9612 * Mark this field as valid
9614 markValid : function()
9616 if(!this.el || this.preventMark){ // not rendered...
9620 this.el.removeClass([this.invalidClass, this.validClass]);
9622 var feedback = this.el.select('.form-control-feedback', true).first();
9625 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9629 this.indicator.removeClass('visible');
9630 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9637 if(this.allowBlank && !this.getRawValue().length){
9641 this.el.addClass(this.validClass);
9643 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9645 var feedback = this.el.select('.form-control-feedback', true).first();
9648 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9649 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9654 this.fireEvent('valid', this);
9658 * Mark this field as invalid
9659 * @param {String} msg The validation message
9661 markInvalid : function(msg)
9663 if(!this.el || this.preventMark){ // not rendered
9667 this.el.removeClass([this.invalidClass, this.validClass]);
9669 var feedback = this.el.select('.form-control-feedback', true).first();
9672 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9679 if(this.allowBlank && !this.getRawValue().length){
9684 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9685 this.indicator.addClass('visible');
9688 this.el.addClass(this.invalidClass);
9690 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9692 var feedback = this.el.select('.form-control-feedback', true).first();
9695 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9697 if(this.getValue().length || this.forceFeedback){
9698 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9705 this.fireEvent('invalid', this, msg);
9708 SafariOnKeyDown : function(event)
9710 // this is a workaround for a password hang bug on chrome/ webkit.
9711 if (this.inputEl().dom.type != 'password') {
9715 var isSelectAll = false;
9717 if(this.inputEl().dom.selectionEnd > 0){
9718 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9720 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9721 event.preventDefault();
9726 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9728 event.preventDefault();
9729 // this is very hacky as keydown always get's upper case.
9731 var cc = String.fromCharCode(event.getCharCode());
9732 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9736 adjustWidth : function(tag, w){
9737 tag = tag.toLowerCase();
9738 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9739 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9743 if(tag == 'textarea'){
9746 }else if(Roo.isOpera){
9750 if(tag == 'textarea'){
9758 setFieldLabel : function(v)
9765 var ar = this.el.select('label > span',true);
9767 if (ar.elements.length) {
9768 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9769 this.fieldLabel = v;
9773 var br = this.el.select('label',true);
9775 if(br.elements.length) {
9776 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9777 this.fieldLabel = v;
9781 Roo.log('Cannot Found any of label > span || label in input');
9785 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9786 this.fieldLabel = v;
9801 * @class Roo.bootstrap.TextArea
9802 * @extends Roo.bootstrap.Input
9803 * Bootstrap TextArea class
9804 * @cfg {Number} cols Specifies the visible width of a text area
9805 * @cfg {Number} rows Specifies the visible number of lines in a text area
9806 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9807 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9808 * @cfg {string} html text
9811 * Create a new TextArea
9812 * @param {Object} config The config object
9815 Roo.bootstrap.TextArea = function(config){
9816 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9820 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9830 getAutoCreate : function(){
9832 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9838 if(this.inputType != 'hidden'){
9839 cfg.cls = 'form-group' //input-group
9847 value : this.value || '',
9848 html: this.html || '',
9849 cls : 'form-control',
9850 placeholder : this.placeholder || ''
9854 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9855 input.maxLength = this.maxLength;
9859 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9863 input.cols = this.cols;
9866 if (this.readOnly) {
9867 input.readonly = true;
9871 input.name = this.name;
9875 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9879 ['xs','sm','md','lg'].map(function(size){
9880 if (settings[size]) {
9881 cfg.cls += ' col-' + size + '-' + settings[size];
9885 var inputblock = input;
9887 if(this.hasFeedback && !this.allowBlank){
9891 cls: 'glyphicon form-control-feedback'
9895 cls : 'has-feedback',
9904 if (this.before || this.after) {
9907 cls : 'input-group',
9911 inputblock.cn.push({
9913 cls : 'input-group-addon',
9918 inputblock.cn.push(input);
9920 if(this.hasFeedback && !this.allowBlank){
9921 inputblock.cls += ' has-feedback';
9922 inputblock.cn.push(feedback);
9926 inputblock.cn.push({
9928 cls : 'input-group-addon',
9935 if (align ==='left' && this.fieldLabel.length) {
9940 cls : 'control-label',
9941 html : this.fieldLabel
9952 if(this.labelWidth > 12){
9953 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9956 if(this.labelWidth < 13 && this.labelmd == 0){
9957 this.labelmd = this.labelWidth;
9960 if(this.labellg > 0){
9961 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9962 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9965 if(this.labelmd > 0){
9966 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9967 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9970 if(this.labelsm > 0){
9971 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9972 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9975 if(this.labelxs > 0){
9976 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9977 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9980 } else if ( this.fieldLabel.length) {
9985 //cls : 'input-group-addon',
9986 html : this.fieldLabel
10004 if (this.disabled) {
10005 input.disabled=true;
10012 * return the real textarea element.
10014 inputEl: function ()
10016 return this.el.select('textarea.form-control',true).first();
10020 * Clear any invalid styles/messages for this field
10022 clearInvalid : function()
10025 if(!this.el || this.preventMark){ // not rendered
10029 var label = this.el.select('label', true).first();
10030 var icon = this.el.select('i.fa-star', true).first();
10036 this.el.removeClass(this.invalidClass);
10038 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10040 var feedback = this.el.select('.form-control-feedback', true).first();
10043 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10048 this.fireEvent('valid', this);
10052 * Mark this field as valid
10054 markValid : function()
10056 if(!this.el || this.preventMark){ // not rendered
10060 this.el.removeClass([this.invalidClass, this.validClass]);
10062 var feedback = this.el.select('.form-control-feedback', true).first();
10065 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10068 if(this.disabled || this.allowBlank){
10072 var label = this.el.select('label', true).first();
10073 var icon = this.el.select('i.fa-star', true).first();
10079 this.el.addClass(this.validClass);
10081 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10083 var feedback = this.el.select('.form-control-feedback', true).first();
10086 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10087 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10092 this.fireEvent('valid', this);
10096 * Mark this field as invalid
10097 * @param {String} msg The validation message
10099 markInvalid : function(msg)
10101 if(!this.el || this.preventMark){ // not rendered
10105 this.el.removeClass([this.invalidClass, this.validClass]);
10107 var feedback = this.el.select('.form-control-feedback', true).first();
10110 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10113 if(this.disabled || this.allowBlank){
10117 var label = this.el.select('label', true).first();
10118 var icon = this.el.select('i.fa-star', true).first();
10120 if(!this.getValue().length && label && !icon){
10121 this.el.createChild({
10123 cls : 'text-danger fa fa-lg fa-star',
10124 tooltip : 'This field is required',
10125 style : 'margin-right:5px;'
10129 this.el.addClass(this.invalidClass);
10131 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10133 var feedback = this.el.select('.form-control-feedback', true).first();
10136 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10138 if(this.getValue().length || this.forceFeedback){
10139 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10146 this.fireEvent('invalid', this, msg);
10154 * trigger field - base class for combo..
10159 * @class Roo.bootstrap.TriggerField
10160 * @extends Roo.bootstrap.Input
10161 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10162 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10163 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10164 * for which you can provide a custom implementation. For example:
10166 var trigger = new Roo.bootstrap.TriggerField();
10167 trigger.onTriggerClick = myTriggerFn;
10168 trigger.applyTo('my-field');
10171 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10172 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10173 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10174 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10175 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10178 * Create a new TriggerField.
10179 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10180 * to the base TextField)
10182 Roo.bootstrap.TriggerField = function(config){
10183 this.mimicing = false;
10184 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10187 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10189 * @cfg {String} triggerClass A CSS class to apply to the trigger
10192 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10197 * @cfg {Boolean} removable (true|false) special filter default false
10201 /** @cfg {Boolean} grow @hide */
10202 /** @cfg {Number} growMin @hide */
10203 /** @cfg {Number} growMax @hide */
10209 autoSize: Roo.emptyFn,
10213 deferHeight : true,
10216 actionMode : 'wrap',
10221 getAutoCreate : function(){
10223 var align = this.labelAlign || this.parentLabelAlign();
10228 cls: 'form-group' //input-group
10235 type : this.inputType,
10236 cls : 'form-control',
10237 autocomplete: 'new-password',
10238 placeholder : this.placeholder || ''
10242 input.name = this.name;
10245 input.cls += ' input-' + this.size;
10248 if (this.disabled) {
10249 input.disabled=true;
10252 var inputblock = input;
10254 if(this.hasFeedback && !this.allowBlank){
10258 cls: 'glyphicon form-control-feedback'
10261 if(this.removable && !this.editable && !this.tickable){
10263 cls : 'has-feedback',
10269 cls : 'roo-combo-removable-btn close'
10276 cls : 'has-feedback',
10285 if(this.removable && !this.editable && !this.tickable){
10287 cls : 'roo-removable',
10293 cls : 'roo-combo-removable-btn close'
10300 if (this.before || this.after) {
10303 cls : 'input-group',
10307 inputblock.cn.push({
10309 cls : 'input-group-addon',
10314 inputblock.cn.push(input);
10316 if(this.hasFeedback && !this.allowBlank){
10317 inputblock.cls += ' has-feedback';
10318 inputblock.cn.push(feedback);
10322 inputblock.cn.push({
10324 cls : 'input-group-addon',
10337 cls: 'form-hidden-field'
10351 cls: 'form-hidden-field'
10355 cls: 'roo-select2-choices',
10359 cls: 'roo-select2-search-field',
10372 cls: 'roo-select2-container input-group',
10377 // cls: 'typeahead typeahead-long dropdown-menu',
10378 // style: 'display:none'
10383 if(!this.multiple && this.showToggleBtn){
10389 if (this.caret != false) {
10392 cls: 'fa fa-' + this.caret
10399 cls : 'input-group-addon btn dropdown-toggle',
10404 cls: 'combobox-clear',
10418 combobox.cls += ' roo-select2-container-multi';
10421 if (align ==='left' && this.fieldLabel.length) {
10423 cfg.cls += ' roo-form-group-label-left';
10428 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10429 tooltip : 'This field is required'
10434 cls : 'control-label',
10435 html : this.fieldLabel
10447 var labelCfg = cfg.cn[1];
10448 var contentCfg = cfg.cn[2];
10450 if(this.indicatorpos == 'right'){
10455 cls : 'control-label',
10459 html : this.fieldLabel
10463 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10464 tooltip : 'This field is required'
10477 labelCfg = cfg.cn[0];
10478 contentCfg = cfg.cn[1];
10481 if(this.labelWidth > 12){
10482 labelCfg.style = "width: " + this.labelWidth + 'px';
10485 if(this.labelWidth < 13 && this.labelmd == 0){
10486 this.labelmd = this.labelWidth;
10489 if(this.labellg > 0){
10490 labelCfg.cls += ' col-lg-' + this.labellg;
10491 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10494 if(this.labelmd > 0){
10495 labelCfg.cls += ' col-md-' + this.labelmd;
10496 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10499 if(this.labelsm > 0){
10500 labelCfg.cls += ' col-sm-' + this.labelsm;
10501 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10504 if(this.labelxs > 0){
10505 labelCfg.cls += ' col-xs-' + this.labelxs;
10506 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10509 } else if ( this.fieldLabel.length) {
10510 // Roo.log(" label");
10514 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10515 tooltip : 'This field is required'
10519 //cls : 'input-group-addon',
10520 html : this.fieldLabel
10528 if(this.indicatorpos == 'right'){
10536 html : this.fieldLabel
10540 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10541 tooltip : 'This field is required'
10554 // Roo.log(" no label && no align");
10561 ['xs','sm','md','lg'].map(function(size){
10562 if (settings[size]) {
10563 cfg.cls += ' col-' + size + '-' + settings[size];
10574 onResize : function(w, h){
10575 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10576 // if(typeof w == 'number'){
10577 // var x = w - this.trigger.getWidth();
10578 // this.inputEl().setWidth(this.adjustWidth('input', x));
10579 // this.trigger.setStyle('left', x+'px');
10584 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10587 getResizeEl : function(){
10588 return this.inputEl();
10592 getPositionEl : function(){
10593 return this.inputEl();
10597 alignErrorIcon : function(){
10598 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10602 initEvents : function(){
10606 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10607 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10608 if(!this.multiple && this.showToggleBtn){
10609 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10610 if(this.hideTrigger){
10611 this.trigger.setDisplayed(false);
10613 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10617 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10620 if(this.removable && !this.editable && !this.tickable){
10621 var close = this.closeTriggerEl();
10624 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10625 close.on('click', this.removeBtnClick, this, close);
10629 //this.trigger.addClassOnOver('x-form-trigger-over');
10630 //this.trigger.addClassOnClick('x-form-trigger-click');
10633 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10637 closeTriggerEl : function()
10639 var close = this.el.select('.roo-combo-removable-btn', true).first();
10640 return close ? close : false;
10643 removeBtnClick : function(e, h, el)
10645 e.preventDefault();
10647 if(this.fireEvent("remove", this) !== false){
10649 this.fireEvent("afterremove", this)
10653 createList : function()
10655 this.list = Roo.get(document.body).createChild({
10657 cls: 'typeahead typeahead-long dropdown-menu',
10658 style: 'display:none'
10661 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10666 initTrigger : function(){
10671 onDestroy : function(){
10673 this.trigger.removeAllListeners();
10674 // this.trigger.remove();
10677 // this.wrap.remove();
10679 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10683 onFocus : function(){
10684 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10686 if(!this.mimicing){
10687 this.wrap.addClass('x-trigger-wrap-focus');
10688 this.mimicing = true;
10689 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10690 if(this.monitorTab){
10691 this.el.on("keydown", this.checkTab, this);
10698 checkTab : function(e){
10699 if(e.getKey() == e.TAB){
10700 this.triggerBlur();
10705 onBlur : function(){
10710 mimicBlur : function(e, t){
10712 if(!this.wrap.contains(t) && this.validateBlur()){
10713 this.triggerBlur();
10719 triggerBlur : function(){
10720 this.mimicing = false;
10721 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10722 if(this.monitorTab){
10723 this.el.un("keydown", this.checkTab, this);
10725 //this.wrap.removeClass('x-trigger-wrap-focus');
10726 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10730 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10731 validateBlur : function(e, t){
10736 onDisable : function(){
10737 this.inputEl().dom.disabled = true;
10738 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10740 // this.wrap.addClass('x-item-disabled');
10745 onEnable : function(){
10746 this.inputEl().dom.disabled = false;
10747 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10749 // this.el.removeClass('x-item-disabled');
10754 onShow : function(){
10755 var ae = this.getActionEl();
10758 ae.dom.style.display = '';
10759 ae.dom.style.visibility = 'visible';
10765 onHide : function(){
10766 var ae = this.getActionEl();
10767 ae.dom.style.display = 'none';
10771 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10772 * by an implementing function.
10774 * @param {EventObject} e
10776 onTriggerClick : Roo.emptyFn
10780 * Ext JS Library 1.1.1
10781 * Copyright(c) 2006-2007, Ext JS, LLC.
10783 * Originally Released Under LGPL - original licence link has changed is not relivant.
10786 * <script type="text/javascript">
10791 * @class Roo.data.SortTypes
10793 * Defines the default sorting (casting?) comparison functions used when sorting data.
10795 Roo.data.SortTypes = {
10797 * Default sort that does nothing
10798 * @param {Mixed} s The value being converted
10799 * @return {Mixed} The comparison value
10801 none : function(s){
10806 * The regular expression used to strip tags
10810 stripTagsRE : /<\/?[^>]+>/gi,
10813 * Strips all HTML tags to sort on text only
10814 * @param {Mixed} s The value being converted
10815 * @return {String} The comparison value
10817 asText : function(s){
10818 return String(s).replace(this.stripTagsRE, "");
10822 * Strips all HTML tags to sort on text only - Case insensitive
10823 * @param {Mixed} s The value being converted
10824 * @return {String} The comparison value
10826 asUCText : function(s){
10827 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10831 * Case insensitive string
10832 * @param {Mixed} s The value being converted
10833 * @return {String} The comparison value
10835 asUCString : function(s) {
10836 return String(s).toUpperCase();
10841 * @param {Mixed} s The value being converted
10842 * @return {Number} The comparison value
10844 asDate : function(s) {
10848 if(s instanceof Date){
10849 return s.getTime();
10851 return Date.parse(String(s));
10856 * @param {Mixed} s The value being converted
10857 * @return {Float} The comparison value
10859 asFloat : function(s) {
10860 var val = parseFloat(String(s).replace(/,/g, ""));
10869 * @param {Mixed} s The value being converted
10870 * @return {Number} The comparison value
10872 asInt : function(s) {
10873 var val = parseInt(String(s).replace(/,/g, ""));
10881 * Ext JS Library 1.1.1
10882 * Copyright(c) 2006-2007, Ext JS, LLC.
10884 * Originally Released Under LGPL - original licence link has changed is not relivant.
10887 * <script type="text/javascript">
10891 * @class Roo.data.Record
10892 * Instances of this class encapsulate both record <em>definition</em> information, and record
10893 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10894 * to access Records cached in an {@link Roo.data.Store} object.<br>
10896 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10897 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10900 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10902 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10903 * {@link #create}. The parameters are the same.
10904 * @param {Array} data An associative Array of data values keyed by the field name.
10905 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10906 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10907 * not specified an integer id is generated.
10909 Roo.data.Record = function(data, id){
10910 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10915 * Generate a constructor for a specific record layout.
10916 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10917 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10918 * Each field definition object may contain the following properties: <ul>
10919 * <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,
10920 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10921 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10922 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10923 * is being used, then this is a string containing the javascript expression to reference the data relative to
10924 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10925 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10926 * this may be omitted.</p></li>
10927 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10928 * <ul><li>auto (Default, implies no conversion)</li>
10933 * <li>date</li></ul></p></li>
10934 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10935 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10936 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10937 * by the Reader into an object that will be stored in the Record. It is passed the
10938 * following parameters:<ul>
10939 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10941 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10943 * <br>usage:<br><pre><code>
10944 var TopicRecord = Roo.data.Record.create(
10945 {name: 'title', mapping: 'topic_title'},
10946 {name: 'author', mapping: 'username'},
10947 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10948 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10949 {name: 'lastPoster', mapping: 'user2'},
10950 {name: 'excerpt', mapping: 'post_text'}
10953 var myNewRecord = new TopicRecord({
10954 title: 'Do my job please',
10957 lastPost: new Date(),
10958 lastPoster: 'Animal',
10959 excerpt: 'No way dude!'
10961 myStore.add(myNewRecord);
10966 Roo.data.Record.create = function(o){
10967 var f = function(){
10968 f.superclass.constructor.apply(this, arguments);
10970 Roo.extend(f, Roo.data.Record);
10971 var p = f.prototype;
10972 p.fields = new Roo.util.MixedCollection(false, function(field){
10975 for(var i = 0, len = o.length; i < len; i++){
10976 p.fields.add(new Roo.data.Field(o[i]));
10978 f.getField = function(name){
10979 return p.fields.get(name);
10984 Roo.data.Record.AUTO_ID = 1000;
10985 Roo.data.Record.EDIT = 'edit';
10986 Roo.data.Record.REJECT = 'reject';
10987 Roo.data.Record.COMMIT = 'commit';
10989 Roo.data.Record.prototype = {
10991 * Readonly flag - true if this record has been modified.
11000 join : function(store){
11001 this.store = store;
11005 * Set the named field to the specified value.
11006 * @param {String} name The name of the field to set.
11007 * @param {Object} value The value to set the field to.
11009 set : function(name, value){
11010 if(this.data[name] == value){
11014 if(!this.modified){
11015 this.modified = {};
11017 if(typeof this.modified[name] == 'undefined'){
11018 this.modified[name] = this.data[name];
11020 this.data[name] = value;
11021 if(!this.editing && this.store){
11022 this.store.afterEdit(this);
11027 * Get the value of the named field.
11028 * @param {String} name The name of the field to get the value of.
11029 * @return {Object} The value of the field.
11031 get : function(name){
11032 return this.data[name];
11036 beginEdit : function(){
11037 this.editing = true;
11038 this.modified = {};
11042 cancelEdit : function(){
11043 this.editing = false;
11044 delete this.modified;
11048 endEdit : function(){
11049 this.editing = false;
11050 if(this.dirty && this.store){
11051 this.store.afterEdit(this);
11056 * Usually called by the {@link Roo.data.Store} which owns the Record.
11057 * Rejects all changes made to the Record since either creation, or the last commit operation.
11058 * Modified fields are reverted to their original values.
11060 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11061 * of reject operations.
11063 reject : function(){
11064 var m = this.modified;
11066 if(typeof m[n] != "function"){
11067 this.data[n] = m[n];
11070 this.dirty = false;
11071 delete this.modified;
11072 this.editing = false;
11074 this.store.afterReject(this);
11079 * Usually called by the {@link Roo.data.Store} which owns the Record.
11080 * Commits all changes made to the Record since either creation, or the last commit operation.
11082 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11083 * of commit operations.
11085 commit : function(){
11086 this.dirty = false;
11087 delete this.modified;
11088 this.editing = false;
11090 this.store.afterCommit(this);
11095 hasError : function(){
11096 return this.error != null;
11100 clearError : function(){
11105 * Creates a copy of this record.
11106 * @param {String} id (optional) A new record id if you don't want to use this record's id
11109 copy : function(newId) {
11110 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11114 * Ext JS Library 1.1.1
11115 * Copyright(c) 2006-2007, Ext JS, LLC.
11117 * Originally Released Under LGPL - original licence link has changed is not relivant.
11120 * <script type="text/javascript">
11126 * @class Roo.data.Store
11127 * @extends Roo.util.Observable
11128 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11129 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11131 * 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
11132 * has no knowledge of the format of the data returned by the Proxy.<br>
11134 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11135 * instances from the data object. These records are cached and made available through accessor functions.
11137 * Creates a new Store.
11138 * @param {Object} config A config object containing the objects needed for the Store to access data,
11139 * and read the data into Records.
11141 Roo.data.Store = function(config){
11142 this.data = new Roo.util.MixedCollection(false);
11143 this.data.getKey = function(o){
11146 this.baseParams = {};
11148 this.paramNames = {
11153 "multisort" : "_multisort"
11156 if(config && config.data){
11157 this.inlineData = config.data;
11158 delete config.data;
11161 Roo.apply(this, config);
11163 if(this.reader){ // reader passed
11164 this.reader = Roo.factory(this.reader, Roo.data);
11165 this.reader.xmodule = this.xmodule || false;
11166 if(!this.recordType){
11167 this.recordType = this.reader.recordType;
11169 if(this.reader.onMetaChange){
11170 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11174 if(this.recordType){
11175 this.fields = this.recordType.prototype.fields;
11177 this.modified = [];
11181 * @event datachanged
11182 * Fires when the data cache has changed, and a widget which is using this Store
11183 * as a Record cache should refresh its view.
11184 * @param {Store} this
11186 datachanged : true,
11188 * @event metachange
11189 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11190 * @param {Store} this
11191 * @param {Object} meta The JSON metadata
11196 * Fires when Records have been added to the Store
11197 * @param {Store} this
11198 * @param {Roo.data.Record[]} records The array of Records added
11199 * @param {Number} index The index at which the record(s) were added
11204 * Fires when a Record has been removed from the Store
11205 * @param {Store} this
11206 * @param {Roo.data.Record} record The Record that was removed
11207 * @param {Number} index The index at which the record was removed
11212 * Fires when a Record has been updated
11213 * @param {Store} this
11214 * @param {Roo.data.Record} record The Record that was updated
11215 * @param {String} operation The update operation being performed. Value may be one of:
11217 Roo.data.Record.EDIT
11218 Roo.data.Record.REJECT
11219 Roo.data.Record.COMMIT
11225 * Fires when the data cache has been cleared.
11226 * @param {Store} this
11230 * @event beforeload
11231 * Fires before a request is made for a new data object. If the beforeload handler returns false
11232 * the load action will be canceled.
11233 * @param {Store} this
11234 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11238 * @event beforeloadadd
11239 * Fires after a new set of Records has been loaded.
11240 * @param {Store} this
11241 * @param {Roo.data.Record[]} records The Records that were loaded
11242 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11244 beforeloadadd : true,
11247 * Fires after a new set of Records has been loaded, before they are added to the store.
11248 * @param {Store} this
11249 * @param {Roo.data.Record[]} records The Records that were loaded
11250 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11251 * @params {Object} return from reader
11255 * @event loadexception
11256 * Fires if an exception occurs in the Proxy during loading.
11257 * Called with the signature of the Proxy's "loadexception" event.
11258 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11261 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11262 * @param {Object} load options
11263 * @param {Object} jsonData from your request (normally this contains the Exception)
11265 loadexception : true
11269 this.proxy = Roo.factory(this.proxy, Roo.data);
11270 this.proxy.xmodule = this.xmodule || false;
11271 this.relayEvents(this.proxy, ["loadexception"]);
11273 this.sortToggle = {};
11274 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11276 Roo.data.Store.superclass.constructor.call(this);
11278 if(this.inlineData){
11279 this.loadData(this.inlineData);
11280 delete this.inlineData;
11284 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11286 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11287 * without a remote query - used by combo/forms at present.
11291 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11294 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11297 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11298 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11301 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11302 * on any HTTP request
11305 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11308 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11312 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11313 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11315 remoteSort : false,
11318 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11319 * loaded or when a record is removed. (defaults to false).
11321 pruneModifiedRecords : false,
11324 lastOptions : null,
11327 * Add Records to the Store and fires the add event.
11328 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11330 add : function(records){
11331 records = [].concat(records);
11332 for(var i = 0, len = records.length; i < len; i++){
11333 records[i].join(this);
11335 var index = this.data.length;
11336 this.data.addAll(records);
11337 this.fireEvent("add", this, records, index);
11341 * Remove a Record from the Store and fires the remove event.
11342 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11344 remove : function(record){
11345 var index = this.data.indexOf(record);
11346 this.data.removeAt(index);
11348 if(this.pruneModifiedRecords){
11349 this.modified.remove(record);
11351 this.fireEvent("remove", this, record, index);
11355 * Remove all Records from the Store and fires the clear event.
11357 removeAll : function(){
11359 if(this.pruneModifiedRecords){
11360 this.modified = [];
11362 this.fireEvent("clear", this);
11366 * Inserts Records to the Store at the given index and fires the add event.
11367 * @param {Number} index The start index at which to insert the passed Records.
11368 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11370 insert : function(index, records){
11371 records = [].concat(records);
11372 for(var i = 0, len = records.length; i < len; i++){
11373 this.data.insert(index, records[i]);
11374 records[i].join(this);
11376 this.fireEvent("add", this, records, index);
11380 * Get the index within the cache of the passed Record.
11381 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11382 * @return {Number} The index of the passed Record. Returns -1 if not found.
11384 indexOf : function(record){
11385 return this.data.indexOf(record);
11389 * Get the index within the cache of the Record with the passed id.
11390 * @param {String} id The id of the Record to find.
11391 * @return {Number} The index of the Record. Returns -1 if not found.
11393 indexOfId : function(id){
11394 return this.data.indexOfKey(id);
11398 * Get the Record with the specified id.
11399 * @param {String} id The id of the Record to find.
11400 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11402 getById : function(id){
11403 return this.data.key(id);
11407 * Get the Record at the specified index.
11408 * @param {Number} index The index of the Record to find.
11409 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11411 getAt : function(index){
11412 return this.data.itemAt(index);
11416 * Returns a range of Records between specified indices.
11417 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11418 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11419 * @return {Roo.data.Record[]} An array of Records
11421 getRange : function(start, end){
11422 return this.data.getRange(start, end);
11426 storeOptions : function(o){
11427 o = Roo.apply({}, o);
11430 this.lastOptions = o;
11434 * Loads the Record cache from the configured Proxy using the configured Reader.
11436 * If using remote paging, then the first load call must specify the <em>start</em>
11437 * and <em>limit</em> properties in the options.params property to establish the initial
11438 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11440 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11441 * and this call will return before the new data has been loaded. Perform any post-processing
11442 * in a callback function, or in a "load" event handler.</strong>
11444 * @param {Object} options An object containing properties which control loading options:<ul>
11445 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11446 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11447 * passed the following arguments:<ul>
11448 * <li>r : Roo.data.Record[]</li>
11449 * <li>options: Options object from the load call</li>
11450 * <li>success: Boolean success indicator</li></ul></li>
11451 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11452 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11455 load : function(options){
11456 options = options || {};
11457 if(this.fireEvent("beforeload", this, options) !== false){
11458 this.storeOptions(options);
11459 var p = Roo.apply(options.params || {}, this.baseParams);
11460 // if meta was not loaded from remote source.. try requesting it.
11461 if (!this.reader.metaFromRemote) {
11462 p._requestMeta = 1;
11464 if(this.sortInfo && this.remoteSort){
11465 var pn = this.paramNames;
11466 p[pn["sort"]] = this.sortInfo.field;
11467 p[pn["dir"]] = this.sortInfo.direction;
11469 if (this.multiSort) {
11470 var pn = this.paramNames;
11471 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11474 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11479 * Reloads the Record cache from the configured Proxy using the configured Reader and
11480 * the options from the last load operation performed.
11481 * @param {Object} options (optional) An object containing properties which may override the options
11482 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11483 * the most recently used options are reused).
11485 reload : function(options){
11486 this.load(Roo.applyIf(options||{}, this.lastOptions));
11490 // Called as a callback by the Reader during a load operation.
11491 loadRecords : function(o, options, success){
11492 if(!o || success === false){
11493 if(success !== false){
11494 this.fireEvent("load", this, [], options, o);
11496 if(options.callback){
11497 options.callback.call(options.scope || this, [], options, false);
11501 // if data returned failure - throw an exception.
11502 if (o.success === false) {
11503 // show a message if no listener is registered.
11504 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11505 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11507 // loadmask wil be hooked into this..
11508 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11511 var r = o.records, t = o.totalRecords || r.length;
11513 this.fireEvent("beforeloadadd", this, r, options, o);
11515 if(!options || options.add !== true){
11516 if(this.pruneModifiedRecords){
11517 this.modified = [];
11519 for(var i = 0, len = r.length; i < len; i++){
11523 this.data = this.snapshot;
11524 delete this.snapshot;
11527 this.data.addAll(r);
11528 this.totalLength = t;
11530 this.fireEvent("datachanged", this);
11532 this.totalLength = Math.max(t, this.data.length+r.length);
11536 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11538 var e = new Roo.data.Record({});
11540 e.set(this.parent.displayField, this.parent.emptyTitle);
11541 e.set(this.parent.valueField, '');
11546 this.fireEvent("load", this, r, options, o);
11547 if(options.callback){
11548 options.callback.call(options.scope || this, r, options, true);
11554 * Loads data from a passed data block. A Reader which understands the format of the data
11555 * must have been configured in the constructor.
11556 * @param {Object} data The data block from which to read the Records. The format of the data expected
11557 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11558 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11560 loadData : function(o, append){
11561 var r = this.reader.readRecords(o);
11562 this.loadRecords(r, {add: append}, true);
11566 * Gets the number of cached records.
11568 * <em>If using paging, this may not be the total size of the dataset. If the data object
11569 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11570 * the data set size</em>
11572 getCount : function(){
11573 return this.data.length || 0;
11577 * Gets the total number of records in the dataset as returned by the server.
11579 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11580 * the dataset size</em>
11582 getTotalCount : function(){
11583 return this.totalLength || 0;
11587 * Returns the sort state of the Store as an object with two properties:
11589 field {String} The name of the field by which the Records are sorted
11590 direction {String} The sort order, "ASC" or "DESC"
11593 getSortState : function(){
11594 return this.sortInfo;
11598 applySort : function(){
11599 if(this.sortInfo && !this.remoteSort){
11600 var s = this.sortInfo, f = s.field;
11601 var st = this.fields.get(f).sortType;
11602 var fn = function(r1, r2){
11603 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11604 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11606 this.data.sort(s.direction, fn);
11607 if(this.snapshot && this.snapshot != this.data){
11608 this.snapshot.sort(s.direction, fn);
11614 * Sets the default sort column and order to be used by the next load operation.
11615 * @param {String} fieldName The name of the field to sort by.
11616 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11618 setDefaultSort : function(field, dir){
11619 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11623 * Sort the Records.
11624 * If remote sorting is used, the sort is performed on the server, and the cache is
11625 * reloaded. If local sorting is used, the cache is sorted internally.
11626 * @param {String} fieldName The name of the field to sort by.
11627 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11629 sort : function(fieldName, dir){
11630 var f = this.fields.get(fieldName);
11632 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11634 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11635 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11640 this.sortToggle[f.name] = dir;
11641 this.sortInfo = {field: f.name, direction: dir};
11642 if(!this.remoteSort){
11644 this.fireEvent("datachanged", this);
11646 this.load(this.lastOptions);
11651 * Calls the specified function for each of the Records in the cache.
11652 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11653 * Returning <em>false</em> aborts and exits the iteration.
11654 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11656 each : function(fn, scope){
11657 this.data.each(fn, scope);
11661 * Gets all records modified since the last commit. Modified records are persisted across load operations
11662 * (e.g., during paging).
11663 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11665 getModifiedRecords : function(){
11666 return this.modified;
11670 createFilterFn : function(property, value, anyMatch){
11671 if(!value.exec){ // not a regex
11672 value = String(value);
11673 if(value.length == 0){
11676 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11678 return function(r){
11679 return value.test(r.data[property]);
11684 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11685 * @param {String} property A field on your records
11686 * @param {Number} start The record index to start at (defaults to 0)
11687 * @param {Number} end The last record index to include (defaults to length - 1)
11688 * @return {Number} The sum
11690 sum : function(property, start, end){
11691 var rs = this.data.items, v = 0;
11692 start = start || 0;
11693 end = (end || end === 0) ? end : rs.length-1;
11695 for(var i = start; i <= end; i++){
11696 v += (rs[i].data[property] || 0);
11702 * Filter the records by a specified property.
11703 * @param {String} field A field on your records
11704 * @param {String/RegExp} value Either a string that the field
11705 * should start with or a RegExp to test against the field
11706 * @param {Boolean} anyMatch True to match any part not just the beginning
11708 filter : function(property, value, anyMatch){
11709 var fn = this.createFilterFn(property, value, anyMatch);
11710 return fn ? this.filterBy(fn) : this.clearFilter();
11714 * Filter by a function. The specified function will be called with each
11715 * record in this data source. If the function returns true the record is included,
11716 * otherwise it is filtered.
11717 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11718 * @param {Object} scope (optional) The scope of the function (defaults to this)
11720 filterBy : function(fn, scope){
11721 this.snapshot = this.snapshot || this.data;
11722 this.data = this.queryBy(fn, scope||this);
11723 this.fireEvent("datachanged", this);
11727 * Query the records by a specified property.
11728 * @param {String} field A field on your records
11729 * @param {String/RegExp} value Either a string that the field
11730 * should start with or a RegExp to test against the field
11731 * @param {Boolean} anyMatch True to match any part not just the beginning
11732 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11734 query : function(property, value, anyMatch){
11735 var fn = this.createFilterFn(property, value, anyMatch);
11736 return fn ? this.queryBy(fn) : this.data.clone();
11740 * Query by a function. The specified function will be called with each
11741 * record in this data source. If the function returns true the record is included
11743 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11744 * @param {Object} scope (optional) The scope of the function (defaults to this)
11745 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11747 queryBy : function(fn, scope){
11748 var data = this.snapshot || this.data;
11749 return data.filterBy(fn, scope||this);
11753 * Collects unique values for a particular dataIndex from this store.
11754 * @param {String} dataIndex The property to collect
11755 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11756 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11757 * @return {Array} An array of the unique values
11759 collect : function(dataIndex, allowNull, bypassFilter){
11760 var d = (bypassFilter === true && this.snapshot) ?
11761 this.snapshot.items : this.data.items;
11762 var v, sv, r = [], l = {};
11763 for(var i = 0, len = d.length; i < len; i++){
11764 v = d[i].data[dataIndex];
11766 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11775 * Revert to a view of the Record cache with no filtering applied.
11776 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11778 clearFilter : function(suppressEvent){
11779 if(this.snapshot && this.snapshot != this.data){
11780 this.data = this.snapshot;
11781 delete this.snapshot;
11782 if(suppressEvent !== true){
11783 this.fireEvent("datachanged", this);
11789 afterEdit : function(record){
11790 if(this.modified.indexOf(record) == -1){
11791 this.modified.push(record);
11793 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11797 afterReject : function(record){
11798 this.modified.remove(record);
11799 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11803 afterCommit : function(record){
11804 this.modified.remove(record);
11805 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11809 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11810 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11812 commitChanges : function(){
11813 var m = this.modified.slice(0);
11814 this.modified = [];
11815 for(var i = 0, len = m.length; i < len; i++){
11821 * Cancel outstanding changes on all changed records.
11823 rejectChanges : function(){
11824 var m = this.modified.slice(0);
11825 this.modified = [];
11826 for(var i = 0, len = m.length; i < len; i++){
11831 onMetaChange : function(meta, rtype, o){
11832 this.recordType = rtype;
11833 this.fields = rtype.prototype.fields;
11834 delete this.snapshot;
11835 this.sortInfo = meta.sortInfo || this.sortInfo;
11836 this.modified = [];
11837 this.fireEvent('metachange', this, this.reader.meta);
11840 moveIndex : function(data, type)
11842 var index = this.indexOf(data);
11844 var newIndex = index + type;
11848 this.insert(newIndex, data);
11853 * Ext JS Library 1.1.1
11854 * Copyright(c) 2006-2007, Ext JS, LLC.
11856 * Originally Released Under LGPL - original licence link has changed is not relivant.
11859 * <script type="text/javascript">
11863 * @class Roo.data.SimpleStore
11864 * @extends Roo.data.Store
11865 * Small helper class to make creating Stores from Array data easier.
11866 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11867 * @cfg {Array} fields An array of field definition objects, or field name strings.
11868 * @cfg {Array} data The multi-dimensional array of data
11870 * @param {Object} config
11872 Roo.data.SimpleStore = function(config){
11873 Roo.data.SimpleStore.superclass.constructor.call(this, {
11875 reader: new Roo.data.ArrayReader({
11878 Roo.data.Record.create(config.fields)
11880 proxy : new Roo.data.MemoryProxy(config.data)
11884 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11886 * Ext JS Library 1.1.1
11887 * Copyright(c) 2006-2007, Ext JS, LLC.
11889 * Originally Released Under LGPL - original licence link has changed is not relivant.
11892 * <script type="text/javascript">
11897 * @extends Roo.data.Store
11898 * @class Roo.data.JsonStore
11899 * Small helper class to make creating Stores for JSON data easier. <br/>
11901 var store = new Roo.data.JsonStore({
11902 url: 'get-images.php',
11904 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11907 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11908 * JsonReader and HttpProxy (unless inline data is provided).</b>
11909 * @cfg {Array} fields An array of field definition objects, or field name strings.
11911 * @param {Object} config
11913 Roo.data.JsonStore = function(c){
11914 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11915 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11916 reader: new Roo.data.JsonReader(c, c.fields)
11919 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11921 * Ext JS Library 1.1.1
11922 * Copyright(c) 2006-2007, Ext JS, LLC.
11924 * Originally Released Under LGPL - original licence link has changed is not relivant.
11927 * <script type="text/javascript">
11931 Roo.data.Field = function(config){
11932 if(typeof config == "string"){
11933 config = {name: config};
11935 Roo.apply(this, config);
11938 this.type = "auto";
11941 var st = Roo.data.SortTypes;
11942 // named sortTypes are supported, here we look them up
11943 if(typeof this.sortType == "string"){
11944 this.sortType = st[this.sortType];
11947 // set default sortType for strings and dates
11948 if(!this.sortType){
11951 this.sortType = st.asUCString;
11954 this.sortType = st.asDate;
11957 this.sortType = st.none;
11962 var stripRe = /[\$,%]/g;
11964 // prebuilt conversion function for this field, instead of
11965 // switching every time we're reading a value
11967 var cv, dateFormat = this.dateFormat;
11972 cv = function(v){ return v; };
11975 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11979 return v !== undefined && v !== null && v !== '' ?
11980 parseInt(String(v).replace(stripRe, ""), 10) : '';
11985 return v !== undefined && v !== null && v !== '' ?
11986 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11991 cv = function(v){ return v === true || v === "true" || v == 1; };
11998 if(v instanceof Date){
12002 if(dateFormat == "timestamp"){
12003 return new Date(v*1000);
12005 return Date.parseDate(v, dateFormat);
12007 var parsed = Date.parse(v);
12008 return parsed ? new Date(parsed) : null;
12017 Roo.data.Field.prototype = {
12025 * Ext JS Library 1.1.1
12026 * Copyright(c) 2006-2007, Ext JS, LLC.
12028 * Originally Released Under LGPL - original licence link has changed is not relivant.
12031 * <script type="text/javascript">
12034 // Base class for reading structured data from a data source. This class is intended to be
12035 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12038 * @class Roo.data.DataReader
12039 * Base class for reading structured data from a data source. This class is intended to be
12040 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12043 Roo.data.DataReader = function(meta, recordType){
12047 this.recordType = recordType instanceof Array ?
12048 Roo.data.Record.create(recordType) : recordType;
12051 Roo.data.DataReader.prototype = {
12053 * Create an empty record
12054 * @param {Object} data (optional) - overlay some values
12055 * @return {Roo.data.Record} record created.
12057 newRow : function(d) {
12059 this.recordType.prototype.fields.each(function(c) {
12061 case 'int' : da[c.name] = 0; break;
12062 case 'date' : da[c.name] = new Date(); break;
12063 case 'float' : da[c.name] = 0.0; break;
12064 case 'boolean' : da[c.name] = false; break;
12065 default : da[c.name] = ""; break;
12069 return new this.recordType(Roo.apply(da, d));
12074 * Ext JS Library 1.1.1
12075 * Copyright(c) 2006-2007, Ext JS, LLC.
12077 * Originally Released Under LGPL - original licence link has changed is not relivant.
12080 * <script type="text/javascript">
12084 * @class Roo.data.DataProxy
12085 * @extends Roo.data.Observable
12086 * This class is an abstract base class for implementations which provide retrieval of
12087 * unformatted data objects.<br>
12089 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12090 * (of the appropriate type which knows how to parse the data object) to provide a block of
12091 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12093 * Custom implementations must implement the load method as described in
12094 * {@link Roo.data.HttpProxy#load}.
12096 Roo.data.DataProxy = function(){
12099 * @event beforeload
12100 * Fires before a network request is made to retrieve a data object.
12101 * @param {Object} This DataProxy object.
12102 * @param {Object} params The params parameter to the load function.
12107 * Fires before the load method's callback is called.
12108 * @param {Object} This DataProxy object.
12109 * @param {Object} o The data object.
12110 * @param {Object} arg The callback argument object passed to the load function.
12114 * @event loadexception
12115 * Fires if an Exception occurs during data retrieval.
12116 * @param {Object} This DataProxy object.
12117 * @param {Object} o The data object.
12118 * @param {Object} arg The callback argument object passed to the load function.
12119 * @param {Object} e The Exception.
12121 loadexception : true
12123 Roo.data.DataProxy.superclass.constructor.call(this);
12126 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12129 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12133 * Ext JS Library 1.1.1
12134 * Copyright(c) 2006-2007, Ext JS, LLC.
12136 * Originally Released Under LGPL - original licence link has changed is not relivant.
12139 * <script type="text/javascript">
12142 * @class Roo.data.MemoryProxy
12143 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12144 * to the Reader when its load method is called.
12146 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12148 Roo.data.MemoryProxy = function(data){
12152 Roo.data.MemoryProxy.superclass.constructor.call(this);
12156 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12159 * Load data from the requested source (in this case an in-memory
12160 * data object passed to the constructor), read the data object into
12161 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12162 * process that block using the passed callback.
12163 * @param {Object} params This parameter is not used by the MemoryProxy class.
12164 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12165 * object into a block of Roo.data.Records.
12166 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12167 * The function must be passed <ul>
12168 * <li>The Record block object</li>
12169 * <li>The "arg" argument from the load function</li>
12170 * <li>A boolean success indicator</li>
12172 * @param {Object} scope The scope in which to call the callback
12173 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12175 load : function(params, reader, callback, scope, arg){
12176 params = params || {};
12179 result = reader.readRecords(this.data);
12181 this.fireEvent("loadexception", this, arg, null, e);
12182 callback.call(scope, null, arg, false);
12185 callback.call(scope, result, arg, true);
12189 update : function(params, records){
12194 * Ext JS Library 1.1.1
12195 * Copyright(c) 2006-2007, Ext JS, LLC.
12197 * Originally Released Under LGPL - original licence link has changed is not relivant.
12200 * <script type="text/javascript">
12203 * @class Roo.data.HttpProxy
12204 * @extends Roo.data.DataProxy
12205 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12206 * configured to reference a certain URL.<br><br>
12208 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12209 * from which the running page was served.<br><br>
12211 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12213 * Be aware that to enable the browser to parse an XML document, the server must set
12214 * the Content-Type header in the HTTP response to "text/xml".
12216 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12217 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12218 * will be used to make the request.
12220 Roo.data.HttpProxy = function(conn){
12221 Roo.data.HttpProxy.superclass.constructor.call(this);
12222 // is conn a conn config or a real conn?
12224 this.useAjax = !conn || !conn.events;
12228 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12229 // thse are take from connection...
12232 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12235 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12236 * extra parameters to each request made by this object. (defaults to undefined)
12239 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12240 * to each request made by this object. (defaults to undefined)
12243 * @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)
12246 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12249 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12255 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12259 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12260 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12261 * a finer-grained basis than the DataProxy events.
12263 getConnection : function(){
12264 return this.useAjax ? Roo.Ajax : this.conn;
12268 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12269 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12270 * process that block using the passed callback.
12271 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12272 * for the request to the remote server.
12273 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12274 * object into a block of Roo.data.Records.
12275 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12276 * The function must be passed <ul>
12277 * <li>The Record block object</li>
12278 * <li>The "arg" argument from the load function</li>
12279 * <li>A boolean success indicator</li>
12281 * @param {Object} scope The scope in which to call the callback
12282 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12284 load : function(params, reader, callback, scope, arg){
12285 if(this.fireEvent("beforeload", this, params) !== false){
12287 params : params || {},
12289 callback : callback,
12294 callback : this.loadResponse,
12298 Roo.applyIf(o, this.conn);
12299 if(this.activeRequest){
12300 Roo.Ajax.abort(this.activeRequest);
12302 this.activeRequest = Roo.Ajax.request(o);
12304 this.conn.request(o);
12307 callback.call(scope||this, null, arg, false);
12312 loadResponse : function(o, success, response){
12313 delete this.activeRequest;
12315 this.fireEvent("loadexception", this, o, response);
12316 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12321 result = o.reader.read(response);
12323 this.fireEvent("loadexception", this, o, response, e);
12324 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12328 this.fireEvent("load", this, o, o.request.arg);
12329 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12333 update : function(dataSet){
12338 updateResponse : function(dataSet){
12343 * Ext JS Library 1.1.1
12344 * Copyright(c) 2006-2007, Ext JS, LLC.
12346 * Originally Released Under LGPL - original licence link has changed is not relivant.
12349 * <script type="text/javascript">
12353 * @class Roo.data.ScriptTagProxy
12354 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12355 * other than the originating domain of the running page.<br><br>
12357 * <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
12358 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12360 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12361 * source code that is used as the source inside a <script> tag.<br><br>
12363 * In order for the browser to process the returned data, the server must wrap the data object
12364 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12365 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12366 * depending on whether the callback name was passed:
12369 boolean scriptTag = false;
12370 String cb = request.getParameter("callback");
12373 response.setContentType("text/javascript");
12375 response.setContentType("application/x-json");
12377 Writer out = response.getWriter();
12379 out.write(cb + "(");
12381 out.print(dataBlock.toJsonString());
12388 * @param {Object} config A configuration object.
12390 Roo.data.ScriptTagProxy = function(config){
12391 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12392 Roo.apply(this, config);
12393 this.head = document.getElementsByTagName("head")[0];
12396 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12398 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12400 * @cfg {String} url The URL from which to request the data object.
12403 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12407 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12408 * the server the name of the callback function set up by the load call to process the returned data object.
12409 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12410 * javascript output which calls this named function passing the data object as its only parameter.
12412 callbackParam : "callback",
12414 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12415 * name to the request.
12420 * Load data from the configured URL, read the data object into
12421 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12422 * process that block using the passed callback.
12423 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12424 * for the request to the remote server.
12425 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12426 * object into a block of Roo.data.Records.
12427 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12428 * The function must be passed <ul>
12429 * <li>The Record block object</li>
12430 * <li>The "arg" argument from the load function</li>
12431 * <li>A boolean success indicator</li>
12433 * @param {Object} scope The scope in which to call the callback
12434 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12436 load : function(params, reader, callback, scope, arg){
12437 if(this.fireEvent("beforeload", this, params) !== false){
12439 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12441 var url = this.url;
12442 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12444 url += "&_dc=" + (new Date().getTime());
12446 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12449 cb : "stcCallback"+transId,
12450 scriptId : "stcScript"+transId,
12454 callback : callback,
12460 window[trans.cb] = function(o){
12461 conn.handleResponse(o, trans);
12464 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12466 if(this.autoAbort !== false){
12470 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12472 var script = document.createElement("script");
12473 script.setAttribute("src", url);
12474 script.setAttribute("type", "text/javascript");
12475 script.setAttribute("id", trans.scriptId);
12476 this.head.appendChild(script);
12478 this.trans = trans;
12480 callback.call(scope||this, null, arg, false);
12485 isLoading : function(){
12486 return this.trans ? true : false;
12490 * Abort the current server request.
12492 abort : function(){
12493 if(this.isLoading()){
12494 this.destroyTrans(this.trans);
12499 destroyTrans : function(trans, isLoaded){
12500 this.head.removeChild(document.getElementById(trans.scriptId));
12501 clearTimeout(trans.timeoutId);
12503 window[trans.cb] = undefined;
12505 delete window[trans.cb];
12508 // if hasn't been loaded, wait for load to remove it to prevent script error
12509 window[trans.cb] = function(){
12510 window[trans.cb] = undefined;
12512 delete window[trans.cb];
12519 handleResponse : function(o, trans){
12520 this.trans = false;
12521 this.destroyTrans(trans, true);
12524 result = trans.reader.readRecords(o);
12526 this.fireEvent("loadexception", this, o, trans.arg, e);
12527 trans.callback.call(trans.scope||window, null, trans.arg, false);
12530 this.fireEvent("load", this, o, trans.arg);
12531 trans.callback.call(trans.scope||window, result, trans.arg, true);
12535 handleFailure : function(trans){
12536 this.trans = false;
12537 this.destroyTrans(trans, false);
12538 this.fireEvent("loadexception", this, null, trans.arg);
12539 trans.callback.call(trans.scope||window, null, trans.arg, false);
12543 * Ext JS Library 1.1.1
12544 * Copyright(c) 2006-2007, Ext JS, LLC.
12546 * Originally Released Under LGPL - original licence link has changed is not relivant.
12549 * <script type="text/javascript">
12553 * @class Roo.data.JsonReader
12554 * @extends Roo.data.DataReader
12555 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12556 * based on mappings in a provided Roo.data.Record constructor.
12558 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12559 * in the reply previously.
12564 var RecordDef = Roo.data.Record.create([
12565 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12566 {name: 'occupation'} // This field will use "occupation" as the mapping.
12568 var myReader = new Roo.data.JsonReader({
12569 totalProperty: "results", // The property which contains the total dataset size (optional)
12570 root: "rows", // The property which contains an Array of row objects
12571 id: "id" // The property within each row object that provides an ID for the record (optional)
12575 * This would consume a JSON file like this:
12577 { 'results': 2, 'rows': [
12578 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12579 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12582 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12583 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12584 * paged from the remote server.
12585 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12586 * @cfg {String} root name of the property which contains the Array of row objects.
12587 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12588 * @cfg {Array} fields Array of field definition objects
12590 * Create a new JsonReader
12591 * @param {Object} meta Metadata configuration options
12592 * @param {Object} recordType Either an Array of field definition objects,
12593 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12595 Roo.data.JsonReader = function(meta, recordType){
12598 // set some defaults:
12599 Roo.applyIf(meta, {
12600 totalProperty: 'total',
12601 successProperty : 'success',
12606 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12608 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12611 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12612 * Used by Store query builder to append _requestMeta to params.
12615 metaFromRemote : false,
12617 * This method is only used by a DataProxy which has retrieved data from a remote server.
12618 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12619 * @return {Object} data A data block which is used by an Roo.data.Store object as
12620 * a cache of Roo.data.Records.
12622 read : function(response){
12623 var json = response.responseText;
12625 var o = /* eval:var:o */ eval("("+json+")");
12627 throw {message: "JsonReader.read: Json object not found"};
12633 this.metaFromRemote = true;
12634 this.meta = o.metaData;
12635 this.recordType = Roo.data.Record.create(o.metaData.fields);
12636 this.onMetaChange(this.meta, this.recordType, o);
12638 return this.readRecords(o);
12641 // private function a store will implement
12642 onMetaChange : function(meta, recordType, o){
12649 simpleAccess: function(obj, subsc) {
12656 getJsonAccessor: function(){
12658 return function(expr) {
12660 return(re.test(expr))
12661 ? new Function("obj", "return obj." + expr)
12666 return Roo.emptyFn;
12671 * Create a data block containing Roo.data.Records from an XML document.
12672 * @param {Object} o An object which contains an Array of row objects in the property specified
12673 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12674 * which contains the total size of the dataset.
12675 * @return {Object} data A data block which is used by an Roo.data.Store object as
12676 * a cache of Roo.data.Records.
12678 readRecords : function(o){
12680 * After any data loads, the raw JSON data is available for further custom processing.
12684 var s = this.meta, Record = this.recordType,
12685 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12687 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12689 if(s.totalProperty) {
12690 this.getTotal = this.getJsonAccessor(s.totalProperty);
12692 if(s.successProperty) {
12693 this.getSuccess = this.getJsonAccessor(s.successProperty);
12695 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12697 var g = this.getJsonAccessor(s.id);
12698 this.getId = function(rec) {
12700 return (r === undefined || r === "") ? null : r;
12703 this.getId = function(){return null;};
12706 for(var jj = 0; jj < fl; jj++){
12708 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12709 this.ef[jj] = this.getJsonAccessor(map);
12713 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12714 if(s.totalProperty){
12715 var vt = parseInt(this.getTotal(o), 10);
12720 if(s.successProperty){
12721 var vs = this.getSuccess(o);
12722 if(vs === false || vs === 'false'){
12727 for(var i = 0; i < c; i++){
12730 var id = this.getId(n);
12731 for(var j = 0; j < fl; j++){
12733 var v = this.ef[j](n);
12735 Roo.log('missing convert for ' + f.name);
12739 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12741 var record = new Record(values, id);
12743 records[i] = record;
12749 totalRecords : totalRecords
12754 * Ext JS Library 1.1.1
12755 * Copyright(c) 2006-2007, Ext JS, LLC.
12757 * Originally Released Under LGPL - original licence link has changed is not relivant.
12760 * <script type="text/javascript">
12764 * @class Roo.data.ArrayReader
12765 * @extends Roo.data.DataReader
12766 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12767 * Each element of that Array represents a row of data fields. The
12768 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12769 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12773 var RecordDef = Roo.data.Record.create([
12774 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12775 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12777 var myReader = new Roo.data.ArrayReader({
12778 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12782 * This would consume an Array like this:
12784 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12786 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12788 * Create a new JsonReader
12789 * @param {Object} meta Metadata configuration options.
12790 * @param {Object} recordType Either an Array of field definition objects
12791 * as specified to {@link Roo.data.Record#create},
12792 * or an {@link Roo.data.Record} object
12793 * created using {@link Roo.data.Record#create}.
12795 Roo.data.ArrayReader = function(meta, recordType){
12796 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12799 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12801 * Create a data block containing Roo.data.Records from an XML document.
12802 * @param {Object} o An Array of row objects which represents the dataset.
12803 * @return {Object} data A data block which is used by an Roo.data.Store object as
12804 * a cache of Roo.data.Records.
12806 readRecords : function(o){
12807 var sid = this.meta ? this.meta.id : null;
12808 var recordType = this.recordType, fields = recordType.prototype.fields;
12811 for(var i = 0; i < root.length; i++){
12814 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12815 for(var j = 0, jlen = fields.length; j < jlen; j++){
12816 var f = fields.items[j];
12817 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12818 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12820 values[f.name] = v;
12822 var record = new recordType(values, id);
12824 records[records.length] = record;
12828 totalRecords : records.length
12837 * @class Roo.bootstrap.ComboBox
12838 * @extends Roo.bootstrap.TriggerField
12839 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12840 * @cfg {Boolean} append (true|false) default false
12841 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12842 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12843 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12844 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12845 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12846 * @cfg {Boolean} animate default true
12847 * @cfg {Boolean} emptyResultText only for touch device
12848 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12849 * @cfg {String} emptyTitle default ''
12851 * Create a new ComboBox.
12852 * @param {Object} config Configuration options
12854 Roo.bootstrap.ComboBox = function(config){
12855 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12859 * Fires when the dropdown list is expanded
12860 * @param {Roo.bootstrap.ComboBox} combo This combo box
12865 * Fires when the dropdown list is collapsed
12866 * @param {Roo.bootstrap.ComboBox} combo This combo box
12870 * @event beforeselect
12871 * Fires before a list item is selected. Return false to cancel the selection.
12872 * @param {Roo.bootstrap.ComboBox} combo This combo box
12873 * @param {Roo.data.Record} record The data record returned from the underlying store
12874 * @param {Number} index The index of the selected item in the dropdown list
12876 'beforeselect' : true,
12879 * Fires when a list item is selected
12880 * @param {Roo.bootstrap.ComboBox} combo This combo box
12881 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12882 * @param {Number} index The index of the selected item in the dropdown list
12886 * @event beforequery
12887 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12888 * The event object passed has these properties:
12889 * @param {Roo.bootstrap.ComboBox} combo This combo box
12890 * @param {String} query The query
12891 * @param {Boolean} forceAll true to force "all" query
12892 * @param {Boolean} cancel true to cancel the query
12893 * @param {Object} e The query event object
12895 'beforequery': true,
12898 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12899 * @param {Roo.bootstrap.ComboBox} combo This combo box
12904 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12905 * @param {Roo.bootstrap.ComboBox} combo This combo box
12906 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12911 * Fires when the remove value from the combobox array
12912 * @param {Roo.bootstrap.ComboBox} combo This combo box
12916 * @event afterremove
12917 * Fires when the remove value from the combobox array
12918 * @param {Roo.bootstrap.ComboBox} combo This combo box
12920 'afterremove' : true,
12922 * @event specialfilter
12923 * Fires when specialfilter
12924 * @param {Roo.bootstrap.ComboBox} combo This combo box
12926 'specialfilter' : true,
12929 * Fires when tick the element
12930 * @param {Roo.bootstrap.ComboBox} combo This combo box
12934 * @event touchviewdisplay
12935 * Fires when touch view require special display (default is using displayField)
12936 * @param {Roo.bootstrap.ComboBox} combo This combo box
12937 * @param {Object} cfg set html .
12939 'touchviewdisplay' : true
12944 this.tickItems = [];
12946 this.selectedIndex = -1;
12947 if(this.mode == 'local'){
12948 if(config.queryDelay === undefined){
12949 this.queryDelay = 10;
12951 if(config.minChars === undefined){
12957 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12960 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12961 * rendering into an Roo.Editor, defaults to false)
12964 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12965 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12968 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12971 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12972 * the dropdown list (defaults to undefined, with no header element)
12976 * @cfg {String/Roo.Template} tpl The template to use to render the output
12980 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12982 listWidth: undefined,
12984 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12985 * mode = 'remote' or 'text' if mode = 'local')
12987 displayField: undefined,
12990 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12991 * mode = 'remote' or 'value' if mode = 'local').
12992 * Note: use of a valueField requires the user make a selection
12993 * in order for a value to be mapped.
12995 valueField: undefined,
12997 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13002 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13003 * field's data value (defaults to the underlying DOM element's name)
13005 hiddenName: undefined,
13007 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13011 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13013 selectedClass: 'active',
13016 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13020 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13021 * anchor positions (defaults to 'tl-bl')
13023 listAlign: 'tl-bl?',
13025 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13029 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13030 * query specified by the allQuery config option (defaults to 'query')
13032 triggerAction: 'query',
13034 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13035 * (defaults to 4, does not apply if editable = false)
13039 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13040 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13044 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13045 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13049 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13050 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13054 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13055 * when editable = true (defaults to false)
13057 selectOnFocus:false,
13059 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13061 queryParam: 'query',
13063 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13064 * when mode = 'remote' (defaults to 'Loading...')
13066 loadingText: 'Loading...',
13068 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13072 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13076 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13077 * traditional select (defaults to true)
13081 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13085 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13089 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13090 * listWidth has a higher value)
13094 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13095 * allow the user to set arbitrary text into the field (defaults to false)
13097 forceSelection:false,
13099 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13100 * if typeAhead = true (defaults to 250)
13102 typeAheadDelay : 250,
13104 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13105 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13107 valueNotFoundText : undefined,
13109 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13111 blockFocus : false,
13114 * @cfg {Boolean} disableClear Disable showing of clear button.
13116 disableClear : false,
13118 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13120 alwaysQuery : false,
13123 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13128 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13130 invalidClass : "has-warning",
13133 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13135 validClass : "has-success",
13138 * @cfg {Boolean} specialFilter (true|false) special filter default false
13140 specialFilter : false,
13143 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13145 mobileTouchView : true,
13148 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13150 useNativeIOS : false,
13153 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13155 mobile_restrict_height : false,
13157 ios_options : false,
13169 btnPosition : 'right',
13170 triggerList : true,
13171 showToggleBtn : true,
13173 emptyResultText: 'Empty',
13174 triggerText : 'Select',
13177 // element that contains real text value.. (when hidden is used..)
13179 getAutoCreate : function()
13184 * Render classic select for iso
13187 if(Roo.isIOS && this.useNativeIOS){
13188 cfg = this.getAutoCreateNativeIOS();
13196 if(Roo.isTouch && this.mobileTouchView){
13197 cfg = this.getAutoCreateTouchView();
13204 if(!this.tickable){
13205 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13210 * ComboBox with tickable selections
13213 var align = this.labelAlign || this.parentLabelAlign();
13216 cls : 'form-group roo-combobox-tickable' //input-group
13219 var btn_text_select = '';
13220 var btn_text_done = '';
13221 var btn_text_cancel = '';
13223 if (this.btn_text_show) {
13224 btn_text_select = 'Select';
13225 btn_text_done = 'Done';
13226 btn_text_cancel = 'Cancel';
13231 cls : 'tickable-buttons',
13236 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13237 //html : this.triggerText
13238 html: btn_text_select
13244 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13246 html: btn_text_done
13252 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13254 html: btn_text_cancel
13260 buttons.cn.unshift({
13262 cls: 'roo-select2-search-field-input'
13268 Roo.each(buttons.cn, function(c){
13270 c.cls += ' btn-' + _this.size;
13273 if (_this.disabled) {
13284 cls: 'form-hidden-field'
13288 cls: 'roo-select2-choices',
13292 cls: 'roo-select2-search-field',
13303 cls: 'roo-select2-container input-group roo-select2-container-multi',
13308 // cls: 'typeahead typeahead-long dropdown-menu',
13309 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13314 if(this.hasFeedback && !this.allowBlank){
13318 cls: 'glyphicon form-control-feedback'
13321 combobox.cn.push(feedback);
13325 if (align ==='left' && this.fieldLabel.length) {
13327 cfg.cls += ' roo-form-group-label-left';
13332 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13333 tooltip : 'This field is required'
13338 cls : 'control-label',
13339 html : this.fieldLabel
13351 var labelCfg = cfg.cn[1];
13352 var contentCfg = cfg.cn[2];
13355 if(this.indicatorpos == 'right'){
13361 cls : 'control-label',
13365 html : this.fieldLabel
13369 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13370 tooltip : 'This field is required'
13385 labelCfg = cfg.cn[0];
13386 contentCfg = cfg.cn[1];
13390 if(this.labelWidth > 12){
13391 labelCfg.style = "width: " + this.labelWidth + 'px';
13394 if(this.labelWidth < 13 && this.labelmd == 0){
13395 this.labelmd = this.labelWidth;
13398 if(this.labellg > 0){
13399 labelCfg.cls += ' col-lg-' + this.labellg;
13400 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13403 if(this.labelmd > 0){
13404 labelCfg.cls += ' col-md-' + this.labelmd;
13405 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13408 if(this.labelsm > 0){
13409 labelCfg.cls += ' col-sm-' + this.labelsm;
13410 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13413 if(this.labelxs > 0){
13414 labelCfg.cls += ' col-xs-' + this.labelxs;
13415 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13419 } else if ( this.fieldLabel.length) {
13420 // Roo.log(" label");
13424 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13425 tooltip : 'This field is required'
13429 //cls : 'input-group-addon',
13430 html : this.fieldLabel
13435 if(this.indicatorpos == 'right'){
13439 //cls : 'input-group-addon',
13440 html : this.fieldLabel
13444 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13445 tooltip : 'This field is required'
13454 // Roo.log(" no label && no align");
13461 ['xs','sm','md','lg'].map(function(size){
13462 if (settings[size]) {
13463 cfg.cls += ' col-' + size + '-' + settings[size];
13471 _initEventsCalled : false,
13474 initEvents: function()
13476 if (this._initEventsCalled) { // as we call render... prevent looping...
13479 this._initEventsCalled = true;
13482 throw "can not find store for combo";
13485 this.indicator = this.indicatorEl();
13487 this.store = Roo.factory(this.store, Roo.data);
13488 this.store.parent = this;
13490 // if we are building from html. then this element is so complex, that we can not really
13491 // use the rendered HTML.
13492 // so we have to trash and replace the previous code.
13493 if (Roo.XComponent.build_from_html) {
13494 // remove this element....
13495 var e = this.el.dom, k=0;
13496 while (e ) { e = e.previousSibling; ++k;}
13501 this.rendered = false;
13503 this.render(this.parent().getChildContainer(true), k);
13506 if(Roo.isIOS && this.useNativeIOS){
13507 this.initIOSView();
13515 if(Roo.isTouch && this.mobileTouchView){
13516 this.initTouchView();
13521 this.initTickableEvents();
13525 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13527 if(this.hiddenName){
13529 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13531 this.hiddenField.dom.value =
13532 this.hiddenValue !== undefined ? this.hiddenValue :
13533 this.value !== undefined ? this.value : '';
13535 // prevent input submission
13536 this.el.dom.removeAttribute('name');
13537 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13542 // this.el.dom.setAttribute('autocomplete', 'off');
13545 var cls = 'x-combo-list';
13547 //this.list = new Roo.Layer({
13548 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13554 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13555 _this.list.setWidth(lw);
13558 this.list.on('mouseover', this.onViewOver, this);
13559 this.list.on('mousemove', this.onViewMove, this);
13560 this.list.on('scroll', this.onViewScroll, this);
13563 this.list.swallowEvent('mousewheel');
13564 this.assetHeight = 0;
13567 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13568 this.assetHeight += this.header.getHeight();
13571 this.innerList = this.list.createChild({cls:cls+'-inner'});
13572 this.innerList.on('mouseover', this.onViewOver, this);
13573 this.innerList.on('mousemove', this.onViewMove, this);
13574 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13576 if(this.allowBlank && !this.pageSize && !this.disableClear){
13577 this.footer = this.list.createChild({cls:cls+'-ft'});
13578 this.pageTb = new Roo.Toolbar(this.footer);
13582 this.footer = this.list.createChild({cls:cls+'-ft'});
13583 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13584 {pageSize: this.pageSize});
13588 if (this.pageTb && this.allowBlank && !this.disableClear) {
13590 this.pageTb.add(new Roo.Toolbar.Fill(), {
13591 cls: 'x-btn-icon x-btn-clear',
13593 handler: function()
13596 _this.clearValue();
13597 _this.onSelect(false, -1);
13602 this.assetHeight += this.footer.getHeight();
13607 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13610 this.view = new Roo.View(this.list, this.tpl, {
13611 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13613 //this.view.wrapEl.setDisplayed(false);
13614 this.view.on('click', this.onViewClick, this);
13617 this.store.on('beforeload', this.onBeforeLoad, this);
13618 this.store.on('load', this.onLoad, this);
13619 this.store.on('loadexception', this.onLoadException, this);
13621 if(this.resizable){
13622 this.resizer = new Roo.Resizable(this.list, {
13623 pinned:true, handles:'se'
13625 this.resizer.on('resize', function(r, w, h){
13626 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13627 this.listWidth = w;
13628 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13629 this.restrictHeight();
13631 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13634 if(!this.editable){
13635 this.editable = true;
13636 this.setEditable(false);
13641 if (typeof(this.events.add.listeners) != 'undefined') {
13643 this.addicon = this.wrap.createChild(
13644 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13646 this.addicon.on('click', function(e) {
13647 this.fireEvent('add', this);
13650 if (typeof(this.events.edit.listeners) != 'undefined') {
13652 this.editicon = this.wrap.createChild(
13653 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13654 if (this.addicon) {
13655 this.editicon.setStyle('margin-left', '40px');
13657 this.editicon.on('click', function(e) {
13659 // we fire even if inothing is selected..
13660 this.fireEvent('edit', this, this.lastData );
13666 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13667 "up" : function(e){
13668 this.inKeyMode = true;
13672 "down" : function(e){
13673 if(!this.isExpanded()){
13674 this.onTriggerClick();
13676 this.inKeyMode = true;
13681 "enter" : function(e){
13682 // this.onViewClick();
13686 if(this.fireEvent("specialkey", this, e)){
13687 this.onViewClick(false);
13693 "esc" : function(e){
13697 "tab" : function(e){
13700 if(this.fireEvent("specialkey", this, e)){
13701 this.onViewClick(false);
13709 doRelay : function(foo, bar, hname){
13710 if(hname == 'down' || this.scope.isExpanded()){
13711 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13720 this.queryDelay = Math.max(this.queryDelay || 10,
13721 this.mode == 'local' ? 10 : 250);
13724 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13726 if(this.typeAhead){
13727 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13729 if(this.editable !== false){
13730 this.inputEl().on("keyup", this.onKeyUp, this);
13732 if(this.forceSelection){
13733 this.inputEl().on('blur', this.doForce, this);
13737 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13738 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13742 initTickableEvents: function()
13746 if(this.hiddenName){
13748 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13750 this.hiddenField.dom.value =
13751 this.hiddenValue !== undefined ? this.hiddenValue :
13752 this.value !== undefined ? this.value : '';
13754 // prevent input submission
13755 this.el.dom.removeAttribute('name');
13756 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13761 // this.list = this.el.select('ul.dropdown-menu',true).first();
13763 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13764 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13765 if(this.triggerList){
13766 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13769 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13770 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13772 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13773 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13775 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13776 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13778 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13779 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13780 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13783 this.cancelBtn.hide();
13788 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13789 _this.list.setWidth(lw);
13792 this.list.on('mouseover', this.onViewOver, this);
13793 this.list.on('mousemove', this.onViewMove, this);
13795 this.list.on('scroll', this.onViewScroll, this);
13798 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13799 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13802 this.view = new Roo.View(this.list, this.tpl, {
13807 selectedClass: this.selectedClass
13810 //this.view.wrapEl.setDisplayed(false);
13811 this.view.on('click', this.onViewClick, this);
13815 this.store.on('beforeload', this.onBeforeLoad, this);
13816 this.store.on('load', this.onLoad, this);
13817 this.store.on('loadexception', this.onLoadException, this);
13820 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13821 "up" : function(e){
13822 this.inKeyMode = true;
13826 "down" : function(e){
13827 this.inKeyMode = true;
13831 "enter" : function(e){
13832 if(this.fireEvent("specialkey", this, e)){
13833 this.onViewClick(false);
13839 "esc" : function(e){
13840 this.onTickableFooterButtonClick(e, false, false);
13843 "tab" : function(e){
13844 this.fireEvent("specialkey", this, e);
13846 this.onTickableFooterButtonClick(e, false, false);
13853 doRelay : function(e, fn, key){
13854 if(this.scope.isExpanded()){
13855 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13864 this.queryDelay = Math.max(this.queryDelay || 10,
13865 this.mode == 'local' ? 10 : 250);
13868 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13870 if(this.typeAhead){
13871 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13874 if(this.editable !== false){
13875 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13878 this.indicator = this.indicatorEl();
13880 if(this.indicator){
13881 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13882 this.indicator.hide();
13887 onDestroy : function(){
13889 this.view.setStore(null);
13890 this.view.el.removeAllListeners();
13891 this.view.el.remove();
13892 this.view.purgeListeners();
13895 this.list.dom.innerHTML = '';
13899 this.store.un('beforeload', this.onBeforeLoad, this);
13900 this.store.un('load', this.onLoad, this);
13901 this.store.un('loadexception', this.onLoadException, this);
13903 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13907 fireKey : function(e){
13908 if(e.isNavKeyPress() && !this.list.isVisible()){
13909 this.fireEvent("specialkey", this, e);
13914 onResize: function(w, h){
13915 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13917 // if(typeof w != 'number'){
13918 // // we do not handle it!?!?
13921 // var tw = this.trigger.getWidth();
13922 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13923 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13925 // this.inputEl().setWidth( this.adjustWidth('input', x));
13927 // //this.trigger.setStyle('left', x+'px');
13929 // if(this.list && this.listWidth === undefined){
13930 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13931 // this.list.setWidth(lw);
13932 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13940 * Allow or prevent the user from directly editing the field text. If false is passed,
13941 * the user will only be able to select from the items defined in the dropdown list. This method
13942 * is the runtime equivalent of setting the 'editable' config option at config time.
13943 * @param {Boolean} value True to allow the user to directly edit the field text
13945 setEditable : function(value){
13946 if(value == this.editable){
13949 this.editable = value;
13951 this.inputEl().dom.setAttribute('readOnly', true);
13952 this.inputEl().on('mousedown', this.onTriggerClick, this);
13953 this.inputEl().addClass('x-combo-noedit');
13955 this.inputEl().dom.setAttribute('readOnly', false);
13956 this.inputEl().un('mousedown', this.onTriggerClick, this);
13957 this.inputEl().removeClass('x-combo-noedit');
13963 onBeforeLoad : function(combo,opts){
13964 if(!this.hasFocus){
13968 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13970 this.restrictHeight();
13971 this.selectedIndex = -1;
13975 onLoad : function(){
13977 this.hasQuery = false;
13979 if(!this.hasFocus){
13983 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13984 this.loading.hide();
13987 if(this.store.getCount() > 0){
13990 this.restrictHeight();
13991 if(this.lastQuery == this.allQuery){
13992 if(this.editable && !this.tickable){
13993 this.inputEl().dom.select();
13997 !this.selectByValue(this.value, true) &&
14000 !this.store.lastOptions ||
14001 typeof(this.store.lastOptions.add) == 'undefined' ||
14002 this.store.lastOptions.add != true
14005 this.select(0, true);
14008 if(this.autoFocus){
14011 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14012 this.taTask.delay(this.typeAheadDelay);
14016 this.onEmptyResults();
14022 onLoadException : function()
14024 this.hasQuery = false;
14026 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14027 this.loading.hide();
14030 if(this.tickable && this.editable){
14035 // only causes errors at present
14036 //Roo.log(this.store.reader.jsonData);
14037 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14039 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14045 onTypeAhead : function(){
14046 if(this.store.getCount() > 0){
14047 var r = this.store.getAt(0);
14048 var newValue = r.data[this.displayField];
14049 var len = newValue.length;
14050 var selStart = this.getRawValue().length;
14052 if(selStart != len){
14053 this.setRawValue(newValue);
14054 this.selectText(selStart, newValue.length);
14060 onSelect : function(record, index){
14062 if(this.fireEvent('beforeselect', this, record, index) !== false){
14064 this.setFromData(index > -1 ? record.data : false);
14067 this.fireEvent('select', this, record, index);
14072 * Returns the currently selected field value or empty string if no value is set.
14073 * @return {String} value The selected value
14075 getValue : function()
14077 if(Roo.isIOS && this.useNativeIOS){
14078 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14082 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14085 if(this.valueField){
14086 return typeof this.value != 'undefined' ? this.value : '';
14088 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14092 getRawValue : function()
14094 if(Roo.isIOS && this.useNativeIOS){
14095 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14098 var v = this.inputEl().getValue();
14104 * Clears any text/value currently set in the field
14106 clearValue : function(){
14108 if(this.hiddenField){
14109 this.hiddenField.dom.value = '';
14112 this.setRawValue('');
14113 this.lastSelectionText = '';
14114 this.lastData = false;
14116 var close = this.closeTriggerEl();
14127 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14128 * will be displayed in the field. If the value does not match the data value of an existing item,
14129 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14130 * Otherwise the field will be blank (although the value will still be set).
14131 * @param {String} value The value to match
14133 setValue : function(v)
14135 if(Roo.isIOS && this.useNativeIOS){
14136 this.setIOSValue(v);
14146 if(this.valueField){
14147 var r = this.findRecord(this.valueField, v);
14149 text = r.data[this.displayField];
14150 }else if(this.valueNotFoundText !== undefined){
14151 text = this.valueNotFoundText;
14154 this.lastSelectionText = text;
14155 if(this.hiddenField){
14156 this.hiddenField.dom.value = v;
14158 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14161 var close = this.closeTriggerEl();
14164 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14170 * @property {Object} the last set data for the element
14175 * Sets the value of the field based on a object which is related to the record format for the store.
14176 * @param {Object} value the value to set as. or false on reset?
14178 setFromData : function(o){
14185 var dv = ''; // display value
14186 var vv = ''; // value value..
14188 if (this.displayField) {
14189 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14191 // this is an error condition!!!
14192 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14195 if(this.valueField){
14196 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14199 var close = this.closeTriggerEl();
14202 if(dv.length || vv * 1 > 0){
14204 this.blockFocus=true;
14210 if(this.hiddenField){
14211 this.hiddenField.dom.value = vv;
14213 this.lastSelectionText = dv;
14214 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14218 // no hidden field.. - we store the value in 'value', but still display
14219 // display field!!!!
14220 this.lastSelectionText = dv;
14221 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14228 reset : function(){
14229 // overridden so that last data is reset..
14236 this.setValue(this.originalValue);
14237 //this.clearInvalid();
14238 this.lastData = false;
14240 this.view.clearSelections();
14246 findRecord : function(prop, value){
14248 if(this.store.getCount() > 0){
14249 this.store.each(function(r){
14250 if(r.data[prop] == value){
14260 getName: function()
14262 // returns hidden if it's set..
14263 if (!this.rendered) {return ''};
14264 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14268 onViewMove : function(e, t){
14269 this.inKeyMode = false;
14273 onViewOver : function(e, t){
14274 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14277 var item = this.view.findItemFromChild(t);
14280 var index = this.view.indexOf(item);
14281 this.select(index, false);
14286 onViewClick : function(view, doFocus, el, e)
14288 var index = this.view.getSelectedIndexes()[0];
14290 var r = this.store.getAt(index);
14294 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14301 Roo.each(this.tickItems, function(v,k){
14303 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14305 _this.tickItems.splice(k, 1);
14307 if(typeof(e) == 'undefined' && view == false){
14308 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14320 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14321 this.tickItems.push(r.data);
14324 if(typeof(e) == 'undefined' && view == false){
14325 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14332 this.onSelect(r, index);
14334 if(doFocus !== false && !this.blockFocus){
14335 this.inputEl().focus();
14340 restrictHeight : function(){
14341 //this.innerList.dom.style.height = '';
14342 //var inner = this.innerList.dom;
14343 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14344 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14345 //this.list.beginUpdate();
14346 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14347 this.list.alignTo(this.inputEl(), this.listAlign);
14348 this.list.alignTo(this.inputEl(), this.listAlign);
14349 //this.list.endUpdate();
14353 onEmptyResults : function(){
14355 if(this.tickable && this.editable){
14356 this.hasFocus = false;
14357 this.restrictHeight();
14365 * Returns true if the dropdown list is expanded, else false.
14367 isExpanded : function(){
14368 return this.list.isVisible();
14372 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14373 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14374 * @param {String} value The data value of the item to select
14375 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14376 * selected item if it is not currently in view (defaults to true)
14377 * @return {Boolean} True if the value matched an item in the list, else false
14379 selectByValue : function(v, scrollIntoView){
14380 if(v !== undefined && v !== null){
14381 var r = this.findRecord(this.valueField || this.displayField, v);
14383 this.select(this.store.indexOf(r), scrollIntoView);
14391 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14392 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14393 * @param {Number} index The zero-based index of the list item to select
14394 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14395 * selected item if it is not currently in view (defaults to true)
14397 select : function(index, scrollIntoView){
14398 this.selectedIndex = index;
14399 this.view.select(index);
14400 if(scrollIntoView !== false){
14401 var el = this.view.getNode(index);
14403 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14406 this.list.scrollChildIntoView(el, false);
14412 selectNext : function(){
14413 var ct = this.store.getCount();
14415 if(this.selectedIndex == -1){
14417 }else if(this.selectedIndex < ct-1){
14418 this.select(this.selectedIndex+1);
14424 selectPrev : function(){
14425 var ct = this.store.getCount();
14427 if(this.selectedIndex == -1){
14429 }else if(this.selectedIndex != 0){
14430 this.select(this.selectedIndex-1);
14436 onKeyUp : function(e){
14437 if(this.editable !== false && !e.isSpecialKey()){
14438 this.lastKey = e.getKey();
14439 this.dqTask.delay(this.queryDelay);
14444 validateBlur : function(){
14445 return !this.list || !this.list.isVisible();
14449 initQuery : function(){
14451 var v = this.getRawValue();
14453 if(this.tickable && this.editable){
14454 v = this.tickableInputEl().getValue();
14461 doForce : function(){
14462 if(this.inputEl().dom.value.length > 0){
14463 this.inputEl().dom.value =
14464 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14470 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14471 * query allowing the query action to be canceled if needed.
14472 * @param {String} query The SQL query to execute
14473 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14474 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14475 * saved in the current store (defaults to false)
14477 doQuery : function(q, forceAll){
14479 if(q === undefined || q === null){
14484 forceAll: forceAll,
14488 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14493 forceAll = qe.forceAll;
14494 if(forceAll === true || (q.length >= this.minChars)){
14496 this.hasQuery = true;
14498 if(this.lastQuery != q || this.alwaysQuery){
14499 this.lastQuery = q;
14500 if(this.mode == 'local'){
14501 this.selectedIndex = -1;
14503 this.store.clearFilter();
14506 if(this.specialFilter){
14507 this.fireEvent('specialfilter', this);
14512 this.store.filter(this.displayField, q);
14515 this.store.fireEvent("datachanged", this.store);
14522 this.store.baseParams[this.queryParam] = q;
14524 var options = {params : this.getParams(q)};
14527 options.add = true;
14528 options.params.start = this.page * this.pageSize;
14531 this.store.load(options);
14534 * this code will make the page width larger, at the beginning, the list not align correctly,
14535 * we should expand the list on onLoad
14536 * so command out it
14541 this.selectedIndex = -1;
14546 this.loadNext = false;
14550 getParams : function(q){
14552 //p[this.queryParam] = q;
14556 p.limit = this.pageSize;
14562 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14564 collapse : function(){
14565 if(!this.isExpanded()){
14571 this.hasFocus = false;
14575 this.cancelBtn.hide();
14576 this.trigger.show();
14579 this.tickableInputEl().dom.value = '';
14580 this.tickableInputEl().blur();
14585 Roo.get(document).un('mousedown', this.collapseIf, this);
14586 Roo.get(document).un('mousewheel', this.collapseIf, this);
14587 if (!this.editable) {
14588 Roo.get(document).un('keydown', this.listKeyPress, this);
14590 this.fireEvent('collapse', this);
14596 collapseIf : function(e){
14597 var in_combo = e.within(this.el);
14598 var in_list = e.within(this.list);
14599 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14601 if (in_combo || in_list || is_list) {
14602 //e.stopPropagation();
14607 this.onTickableFooterButtonClick(e, false, false);
14615 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14617 expand : function(){
14619 if(this.isExpanded() || !this.hasFocus){
14623 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14624 this.list.setWidth(lw);
14630 this.restrictHeight();
14634 this.tickItems = Roo.apply([], this.item);
14637 this.cancelBtn.show();
14638 this.trigger.hide();
14641 this.tickableInputEl().focus();
14646 Roo.get(document).on('mousedown', this.collapseIf, this);
14647 Roo.get(document).on('mousewheel', this.collapseIf, this);
14648 if (!this.editable) {
14649 Roo.get(document).on('keydown', this.listKeyPress, this);
14652 this.fireEvent('expand', this);
14656 // Implements the default empty TriggerField.onTriggerClick function
14657 onTriggerClick : function(e)
14659 Roo.log('trigger click');
14661 if(this.disabled || !this.triggerList){
14666 this.loadNext = false;
14668 if(this.isExpanded()){
14670 if (!this.blockFocus) {
14671 this.inputEl().focus();
14675 this.hasFocus = true;
14676 if(this.triggerAction == 'all') {
14677 this.doQuery(this.allQuery, true);
14679 this.doQuery(this.getRawValue());
14681 if (!this.blockFocus) {
14682 this.inputEl().focus();
14687 onTickableTriggerClick : function(e)
14694 this.loadNext = false;
14695 this.hasFocus = true;
14697 if(this.triggerAction == 'all') {
14698 this.doQuery(this.allQuery, true);
14700 this.doQuery(this.getRawValue());
14704 onSearchFieldClick : function(e)
14706 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14707 this.onTickableFooterButtonClick(e, false, false);
14711 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14716 this.loadNext = false;
14717 this.hasFocus = true;
14719 if(this.triggerAction == 'all') {
14720 this.doQuery(this.allQuery, true);
14722 this.doQuery(this.getRawValue());
14726 listKeyPress : function(e)
14728 //Roo.log('listkeypress');
14729 // scroll to first matching element based on key pres..
14730 if (e.isSpecialKey()) {
14733 var k = String.fromCharCode(e.getKey()).toUpperCase();
14736 var csel = this.view.getSelectedNodes();
14737 var cselitem = false;
14739 var ix = this.view.indexOf(csel[0]);
14740 cselitem = this.store.getAt(ix);
14741 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14747 this.store.each(function(v) {
14749 // start at existing selection.
14750 if (cselitem.id == v.id) {
14756 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14757 match = this.store.indexOf(v);
14763 if (match === false) {
14764 return true; // no more action?
14767 this.view.select(match);
14768 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14769 sn.scrollIntoView(sn.dom.parentNode, false);
14772 onViewScroll : function(e, t){
14774 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){
14778 this.hasQuery = true;
14780 this.loading = this.list.select('.loading', true).first();
14782 if(this.loading === null){
14783 this.list.createChild({
14785 cls: 'loading roo-select2-more-results roo-select2-active',
14786 html: 'Loading more results...'
14789 this.loading = this.list.select('.loading', true).first();
14791 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14793 this.loading.hide();
14796 this.loading.show();
14801 this.loadNext = true;
14803 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14808 addItem : function(o)
14810 var dv = ''; // display value
14812 if (this.displayField) {
14813 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14815 // this is an error condition!!!
14816 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14823 var choice = this.choices.createChild({
14825 cls: 'roo-select2-search-choice',
14834 cls: 'roo-select2-search-choice-close fa fa-times',
14839 }, this.searchField);
14841 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14843 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14851 this.inputEl().dom.value = '';
14856 onRemoveItem : function(e, _self, o)
14858 e.preventDefault();
14860 this.lastItem = Roo.apply([], this.item);
14862 var index = this.item.indexOf(o.data) * 1;
14865 Roo.log('not this item?!');
14869 this.item.splice(index, 1);
14874 this.fireEvent('remove', this, e);
14880 syncValue : function()
14882 if(!this.item.length){
14889 Roo.each(this.item, function(i){
14890 if(_this.valueField){
14891 value.push(i[_this.valueField]);
14898 this.value = value.join(',');
14900 if(this.hiddenField){
14901 this.hiddenField.dom.value = this.value;
14904 this.store.fireEvent("datachanged", this.store);
14909 clearItem : function()
14911 if(!this.multiple){
14917 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14925 if(this.tickable && !Roo.isTouch){
14926 this.view.refresh();
14930 inputEl: function ()
14932 if(Roo.isIOS && this.useNativeIOS){
14933 return this.el.select('select.roo-ios-select', true).first();
14936 if(Roo.isTouch && this.mobileTouchView){
14937 return this.el.select('input.form-control',true).first();
14941 return this.searchField;
14944 return this.el.select('input.form-control',true).first();
14947 onTickableFooterButtonClick : function(e, btn, el)
14949 e.preventDefault();
14951 this.lastItem = Roo.apply([], this.item);
14953 if(btn && btn.name == 'cancel'){
14954 this.tickItems = Roo.apply([], this.item);
14963 Roo.each(this.tickItems, function(o){
14971 validate : function()
14973 if(this.getVisibilityEl().hasClass('hidden')){
14977 var v = this.getRawValue();
14980 v = this.getValue();
14983 if(this.disabled || this.allowBlank || v.length){
14988 this.markInvalid();
14992 tickableInputEl : function()
14994 if(!this.tickable || !this.editable){
14995 return this.inputEl();
14998 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15002 getAutoCreateTouchView : function()
15007 cls: 'form-group' //input-group
15013 type : this.inputType,
15014 cls : 'form-control x-combo-noedit',
15015 autocomplete: 'new-password',
15016 placeholder : this.placeholder || '',
15021 input.name = this.name;
15025 input.cls += ' input-' + this.size;
15028 if (this.disabled) {
15029 input.disabled = true;
15040 inputblock.cls += ' input-group';
15042 inputblock.cn.unshift({
15044 cls : 'input-group-addon',
15049 if(this.removable && !this.multiple){
15050 inputblock.cls += ' roo-removable';
15052 inputblock.cn.push({
15055 cls : 'roo-combo-removable-btn close'
15059 if(this.hasFeedback && !this.allowBlank){
15061 inputblock.cls += ' has-feedback';
15063 inputblock.cn.push({
15065 cls: 'glyphicon form-control-feedback'
15072 inputblock.cls += (this.before) ? '' : ' input-group';
15074 inputblock.cn.push({
15076 cls : 'input-group-addon',
15087 cls: 'form-hidden-field'
15101 cls: 'form-hidden-field'
15105 cls: 'roo-select2-choices',
15109 cls: 'roo-select2-search-field',
15122 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15128 if(!this.multiple && this.showToggleBtn){
15135 if (this.caret != false) {
15138 cls: 'fa fa-' + this.caret
15145 cls : 'input-group-addon btn dropdown-toggle',
15150 cls: 'combobox-clear',
15164 combobox.cls += ' roo-select2-container-multi';
15167 var align = this.labelAlign || this.parentLabelAlign();
15169 if (align ==='left' && this.fieldLabel.length) {
15174 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15175 tooltip : 'This field is required'
15179 cls : 'control-label',
15180 html : this.fieldLabel
15191 var labelCfg = cfg.cn[1];
15192 var contentCfg = cfg.cn[2];
15195 if(this.indicatorpos == 'right'){
15200 cls : 'control-label',
15204 html : this.fieldLabel
15208 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15209 tooltip : 'This field is required'
15222 labelCfg = cfg.cn[0];
15223 contentCfg = cfg.cn[1];
15228 if(this.labelWidth > 12){
15229 labelCfg.style = "width: " + this.labelWidth + 'px';
15232 if(this.labelWidth < 13 && this.labelmd == 0){
15233 this.labelmd = this.labelWidth;
15236 if(this.labellg > 0){
15237 labelCfg.cls += ' col-lg-' + this.labellg;
15238 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15241 if(this.labelmd > 0){
15242 labelCfg.cls += ' col-md-' + this.labelmd;
15243 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15246 if(this.labelsm > 0){
15247 labelCfg.cls += ' col-sm-' + this.labelsm;
15248 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15251 if(this.labelxs > 0){
15252 labelCfg.cls += ' col-xs-' + this.labelxs;
15253 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15257 } else if ( this.fieldLabel.length) {
15261 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15262 tooltip : 'This field is required'
15266 cls : 'control-label',
15267 html : this.fieldLabel
15278 if(this.indicatorpos == 'right'){
15282 cls : 'control-label',
15283 html : this.fieldLabel,
15287 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15288 tooltip : 'This field is required'
15305 var settings = this;
15307 ['xs','sm','md','lg'].map(function(size){
15308 if (settings[size]) {
15309 cfg.cls += ' col-' + size + '-' + settings[size];
15316 initTouchView : function()
15318 this.renderTouchView();
15320 this.touchViewEl.on('scroll', function(){
15321 this.el.dom.scrollTop = 0;
15324 this.originalValue = this.getValue();
15326 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15328 this.inputEl().on("click", this.showTouchView, this);
15329 if (this.triggerEl) {
15330 this.triggerEl.on("click", this.showTouchView, this);
15334 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15335 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15337 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15339 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15340 this.store.on('load', this.onTouchViewLoad, this);
15341 this.store.on('loadexception', this.onTouchViewLoadException, this);
15343 if(this.hiddenName){
15345 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15347 this.hiddenField.dom.value =
15348 this.hiddenValue !== undefined ? this.hiddenValue :
15349 this.value !== undefined ? this.value : '';
15351 this.el.dom.removeAttribute('name');
15352 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15356 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15357 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15360 if(this.removable && !this.multiple){
15361 var close = this.closeTriggerEl();
15363 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15364 close.on('click', this.removeBtnClick, this, close);
15368 * fix the bug in Safari iOS8
15370 this.inputEl().on("focus", function(e){
15371 document.activeElement.blur();
15374 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15381 renderTouchView : function()
15383 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15384 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15386 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15387 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15389 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15390 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15391 this.touchViewBodyEl.setStyle('overflow', 'auto');
15393 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15394 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15396 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15397 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15401 showTouchView : function()
15407 this.touchViewHeaderEl.hide();
15409 if(this.modalTitle.length){
15410 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15411 this.touchViewHeaderEl.show();
15414 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15415 this.touchViewEl.show();
15417 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15419 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15420 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15422 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15424 if(this.modalTitle.length){
15425 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15428 this.touchViewBodyEl.setHeight(bodyHeight);
15432 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15434 this.touchViewEl.addClass('in');
15437 if(this._touchViewMask){
15438 Roo.get(document.body).addClass("x-body-masked");
15439 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15440 this._touchViewMask.setStyle('z-index', 10000);
15441 this._touchViewMask.addClass('show');
15444 this.doTouchViewQuery();
15448 hideTouchView : function()
15450 this.touchViewEl.removeClass('in');
15454 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15456 this.touchViewEl.setStyle('display', 'none');
15459 if(this._touchViewMask){
15460 this._touchViewMask.removeClass('show');
15461 Roo.get(document.body).removeClass("x-body-masked");
15465 setTouchViewValue : function()
15472 Roo.each(this.tickItems, function(o){
15477 this.hideTouchView();
15480 doTouchViewQuery : function()
15489 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15493 if(!this.alwaysQuery || this.mode == 'local'){
15494 this.onTouchViewLoad();
15501 onTouchViewBeforeLoad : function(combo,opts)
15507 onTouchViewLoad : function()
15509 if(this.store.getCount() < 1){
15510 this.onTouchViewEmptyResults();
15514 this.clearTouchView();
15516 var rawValue = this.getRawValue();
15518 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15520 this.tickItems = [];
15522 this.store.data.each(function(d, rowIndex){
15523 var row = this.touchViewListGroup.createChild(template);
15525 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15526 row.addClass(d.data.cls);
15529 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15532 html : d.data[this.displayField]
15535 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15536 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15539 row.removeClass('selected');
15540 if(!this.multiple && this.valueField &&
15541 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15544 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15545 row.addClass('selected');
15548 if(this.multiple && this.valueField &&
15549 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15553 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15554 this.tickItems.push(d.data);
15557 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15561 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15563 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15565 if(this.modalTitle.length){
15566 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15569 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15571 if(this.mobile_restrict_height && listHeight < bodyHeight){
15572 this.touchViewBodyEl.setHeight(listHeight);
15577 if(firstChecked && listHeight > bodyHeight){
15578 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15583 onTouchViewLoadException : function()
15585 this.hideTouchView();
15588 onTouchViewEmptyResults : function()
15590 this.clearTouchView();
15592 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15594 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15598 clearTouchView : function()
15600 this.touchViewListGroup.dom.innerHTML = '';
15603 onTouchViewClick : function(e, el, o)
15605 e.preventDefault();
15608 var rowIndex = o.rowIndex;
15610 var r = this.store.getAt(rowIndex);
15612 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15614 if(!this.multiple){
15615 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15616 c.dom.removeAttribute('checked');
15619 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15621 this.setFromData(r.data);
15623 var close = this.closeTriggerEl();
15629 this.hideTouchView();
15631 this.fireEvent('select', this, r, rowIndex);
15636 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15637 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15638 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15642 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15643 this.addItem(r.data);
15644 this.tickItems.push(r.data);
15648 getAutoCreateNativeIOS : function()
15651 cls: 'form-group' //input-group,
15656 cls : 'roo-ios-select'
15660 combobox.name = this.name;
15663 if (this.disabled) {
15664 combobox.disabled = true;
15667 var settings = this;
15669 ['xs','sm','md','lg'].map(function(size){
15670 if (settings[size]) {
15671 cfg.cls += ' col-' + size + '-' + settings[size];
15681 initIOSView : function()
15683 this.store.on('load', this.onIOSViewLoad, this);
15688 onIOSViewLoad : function()
15690 if(this.store.getCount() < 1){
15694 this.clearIOSView();
15696 if(this.allowBlank) {
15698 var default_text = '-- SELECT --';
15700 if(this.placeholder.length){
15701 default_text = this.placeholder;
15704 if(this.emptyTitle.length){
15705 default_text += ' - ' + this.emptyTitle + ' -';
15708 var opt = this.inputEl().createChild({
15711 html : default_text
15715 o[this.valueField] = 0;
15716 o[this.displayField] = default_text;
15718 this.ios_options.push({
15725 this.store.data.each(function(d, rowIndex){
15729 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15730 html = d.data[this.displayField];
15735 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15736 value = d.data[this.valueField];
15745 if(this.value == d.data[this.valueField]){
15746 option['selected'] = true;
15749 var opt = this.inputEl().createChild(option);
15751 this.ios_options.push({
15758 this.inputEl().on('change', function(){
15759 this.fireEvent('select', this);
15764 clearIOSView: function()
15766 this.inputEl().dom.innerHTML = '';
15768 this.ios_options = [];
15771 setIOSValue: function(v)
15775 if(!this.ios_options){
15779 Roo.each(this.ios_options, function(opts){
15781 opts.el.dom.removeAttribute('selected');
15783 if(opts.data[this.valueField] != v){
15787 opts.el.dom.setAttribute('selected', true);
15793 * @cfg {Boolean} grow
15797 * @cfg {Number} growMin
15801 * @cfg {Number} growMax
15810 Roo.apply(Roo.bootstrap.ComboBox, {
15814 cls: 'modal-header',
15836 cls: 'list-group-item',
15840 cls: 'roo-combobox-list-group-item-value'
15844 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15858 listItemCheckbox : {
15860 cls: 'list-group-item',
15864 cls: 'roo-combobox-list-group-item-value'
15868 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15884 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15889 cls: 'modal-footer',
15897 cls: 'col-xs-6 text-left',
15900 cls: 'btn btn-danger roo-touch-view-cancel',
15906 cls: 'col-xs-6 text-right',
15909 cls: 'btn btn-success roo-touch-view-ok',
15920 Roo.apply(Roo.bootstrap.ComboBox, {
15922 touchViewTemplate : {
15924 cls: 'modal fade roo-combobox-touch-view',
15928 cls: 'modal-dialog',
15929 style : 'position:fixed', // we have to fix position....
15933 cls: 'modal-content',
15935 Roo.bootstrap.ComboBox.header,
15936 Roo.bootstrap.ComboBox.body,
15937 Roo.bootstrap.ComboBox.footer
15946 * Ext JS Library 1.1.1
15947 * Copyright(c) 2006-2007, Ext JS, LLC.
15949 * Originally Released Under LGPL - original licence link has changed is not relivant.
15952 * <script type="text/javascript">
15957 * @extends Roo.util.Observable
15958 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15959 * This class also supports single and multi selection modes. <br>
15960 * Create a data model bound view:
15962 var store = new Roo.data.Store(...);
15964 var view = new Roo.View({
15966 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15968 singleSelect: true,
15969 selectedClass: "ydataview-selected",
15973 // listen for node click?
15974 view.on("click", function(vw, index, node, e){
15975 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15979 dataModel.load("foobar.xml");
15981 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15983 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15984 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15986 * Note: old style constructor is still suported (container, template, config)
15989 * Create a new View
15990 * @param {Object} config The config object
15993 Roo.View = function(config, depreciated_tpl, depreciated_config){
15995 this.parent = false;
15997 if (typeof(depreciated_tpl) == 'undefined') {
15998 // new way.. - universal constructor.
15999 Roo.apply(this, config);
16000 this.el = Roo.get(this.el);
16003 this.el = Roo.get(config);
16004 this.tpl = depreciated_tpl;
16005 Roo.apply(this, depreciated_config);
16007 this.wrapEl = this.el.wrap().wrap();
16008 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16011 if(typeof(this.tpl) == "string"){
16012 this.tpl = new Roo.Template(this.tpl);
16014 // support xtype ctors..
16015 this.tpl = new Roo.factory(this.tpl, Roo);
16019 this.tpl.compile();
16024 * @event beforeclick
16025 * Fires before a click is processed. Returns false to cancel the default action.
16026 * @param {Roo.View} this
16027 * @param {Number} index The index of the target node
16028 * @param {HTMLElement} node The target node
16029 * @param {Roo.EventObject} e The raw event object
16031 "beforeclick" : true,
16034 * Fires when a template node is clicked.
16035 * @param {Roo.View} this
16036 * @param {Number} index The index of the target node
16037 * @param {HTMLElement} node The target node
16038 * @param {Roo.EventObject} e The raw event object
16043 * Fires when a template node is double clicked.
16044 * @param {Roo.View} this
16045 * @param {Number} index The index of the target node
16046 * @param {HTMLElement} node The target node
16047 * @param {Roo.EventObject} e The raw event object
16051 * @event contextmenu
16052 * Fires when a template node is right clicked.
16053 * @param {Roo.View} this
16054 * @param {Number} index The index of the target node
16055 * @param {HTMLElement} node The target node
16056 * @param {Roo.EventObject} e The raw event object
16058 "contextmenu" : true,
16060 * @event selectionchange
16061 * Fires when the selected nodes change.
16062 * @param {Roo.View} this
16063 * @param {Array} selections Array of the selected nodes
16065 "selectionchange" : true,
16068 * @event beforeselect
16069 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16070 * @param {Roo.View} this
16071 * @param {HTMLElement} node The node to be selected
16072 * @param {Array} selections Array of currently selected nodes
16074 "beforeselect" : true,
16076 * @event preparedata
16077 * Fires on every row to render, to allow you to change the data.
16078 * @param {Roo.View} this
16079 * @param {Object} data to be rendered (change this)
16081 "preparedata" : true
16089 "click": this.onClick,
16090 "dblclick": this.onDblClick,
16091 "contextmenu": this.onContextMenu,
16095 this.selections = [];
16097 this.cmp = new Roo.CompositeElementLite([]);
16099 this.store = Roo.factory(this.store, Roo.data);
16100 this.setStore(this.store, true);
16103 if ( this.footer && this.footer.xtype) {
16105 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16107 this.footer.dataSource = this.store;
16108 this.footer.container = fctr;
16109 this.footer = Roo.factory(this.footer, Roo);
16110 fctr.insertFirst(this.el);
16112 // this is a bit insane - as the paging toolbar seems to detach the el..
16113 // dom.parentNode.parentNode.parentNode
16114 // they get detached?
16118 Roo.View.superclass.constructor.call(this);
16123 Roo.extend(Roo.View, Roo.util.Observable, {
16126 * @cfg {Roo.data.Store} store Data store to load data from.
16131 * @cfg {String|Roo.Element} el The container element.
16136 * @cfg {String|Roo.Template} tpl The template used by this View
16140 * @cfg {String} dataName the named area of the template to use as the data area
16141 * Works with domtemplates roo-name="name"
16145 * @cfg {String} selectedClass The css class to add to selected nodes
16147 selectedClass : "x-view-selected",
16149 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16154 * @cfg {String} text to display on mask (default Loading)
16158 * @cfg {Boolean} multiSelect Allow multiple selection
16160 multiSelect : false,
16162 * @cfg {Boolean} singleSelect Allow single selection
16164 singleSelect: false,
16167 * @cfg {Boolean} toggleSelect - selecting
16169 toggleSelect : false,
16172 * @cfg {Boolean} tickable - selecting
16177 * Returns the element this view is bound to.
16178 * @return {Roo.Element}
16180 getEl : function(){
16181 return this.wrapEl;
16187 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16189 refresh : function(){
16190 //Roo.log('refresh');
16193 // if we are using something like 'domtemplate', then
16194 // the what gets used is:
16195 // t.applySubtemplate(NAME, data, wrapping data..)
16196 // the outer template then get' applied with
16197 // the store 'extra data'
16198 // and the body get's added to the
16199 // roo-name="data" node?
16200 // <span class='roo-tpl-{name}'></span> ?????
16204 this.clearSelections();
16205 this.el.update("");
16207 var records = this.store.getRange();
16208 if(records.length < 1) {
16210 // is this valid?? = should it render a template??
16212 this.el.update(this.emptyText);
16216 if (this.dataName) {
16217 this.el.update(t.apply(this.store.meta)); //????
16218 el = this.el.child('.roo-tpl-' + this.dataName);
16221 for(var i = 0, len = records.length; i < len; i++){
16222 var data = this.prepareData(records[i].data, i, records[i]);
16223 this.fireEvent("preparedata", this, data, i, records[i]);
16225 var d = Roo.apply({}, data);
16228 Roo.apply(d, {'roo-id' : Roo.id()});
16232 Roo.each(this.parent.item, function(item){
16233 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16236 Roo.apply(d, {'roo-data-checked' : 'checked'});
16240 html[html.length] = Roo.util.Format.trim(
16242 t.applySubtemplate(this.dataName, d, this.store.meta) :
16249 el.update(html.join(""));
16250 this.nodes = el.dom.childNodes;
16251 this.updateIndexes(0);
16256 * Function to override to reformat the data that is sent to
16257 * the template for each node.
16258 * DEPRICATED - use the preparedata event handler.
16259 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16260 * a JSON object for an UpdateManager bound view).
16262 prepareData : function(data, index, record)
16264 this.fireEvent("preparedata", this, data, index, record);
16268 onUpdate : function(ds, record){
16269 // Roo.log('on update');
16270 this.clearSelections();
16271 var index = this.store.indexOf(record);
16272 var n = this.nodes[index];
16273 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16274 n.parentNode.removeChild(n);
16275 this.updateIndexes(index, index);
16281 onAdd : function(ds, records, index)
16283 //Roo.log(['on Add', ds, records, index] );
16284 this.clearSelections();
16285 if(this.nodes.length == 0){
16289 var n = this.nodes[index];
16290 for(var i = 0, len = records.length; i < len; i++){
16291 var d = this.prepareData(records[i].data, i, records[i]);
16293 this.tpl.insertBefore(n, d);
16296 this.tpl.append(this.el, d);
16299 this.updateIndexes(index);
16302 onRemove : function(ds, record, index){
16303 // Roo.log('onRemove');
16304 this.clearSelections();
16305 var el = this.dataName ?
16306 this.el.child('.roo-tpl-' + this.dataName) :
16309 el.dom.removeChild(this.nodes[index]);
16310 this.updateIndexes(index);
16314 * Refresh an individual node.
16315 * @param {Number} index
16317 refreshNode : function(index){
16318 this.onUpdate(this.store, this.store.getAt(index));
16321 updateIndexes : function(startIndex, endIndex){
16322 var ns = this.nodes;
16323 startIndex = startIndex || 0;
16324 endIndex = endIndex || ns.length - 1;
16325 for(var i = startIndex; i <= endIndex; i++){
16326 ns[i].nodeIndex = i;
16331 * Changes the data store this view uses and refresh the view.
16332 * @param {Store} store
16334 setStore : function(store, initial){
16335 if(!initial && this.store){
16336 this.store.un("datachanged", this.refresh);
16337 this.store.un("add", this.onAdd);
16338 this.store.un("remove", this.onRemove);
16339 this.store.un("update", this.onUpdate);
16340 this.store.un("clear", this.refresh);
16341 this.store.un("beforeload", this.onBeforeLoad);
16342 this.store.un("load", this.onLoad);
16343 this.store.un("loadexception", this.onLoad);
16347 store.on("datachanged", this.refresh, this);
16348 store.on("add", this.onAdd, this);
16349 store.on("remove", this.onRemove, this);
16350 store.on("update", this.onUpdate, this);
16351 store.on("clear", this.refresh, this);
16352 store.on("beforeload", this.onBeforeLoad, this);
16353 store.on("load", this.onLoad, this);
16354 store.on("loadexception", this.onLoad, this);
16362 * onbeforeLoad - masks the loading area.
16365 onBeforeLoad : function(store,opts)
16367 //Roo.log('onBeforeLoad');
16369 this.el.update("");
16371 this.el.mask(this.mask ? this.mask : "Loading" );
16373 onLoad : function ()
16380 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16381 * @param {HTMLElement} node
16382 * @return {HTMLElement} The template node
16384 findItemFromChild : function(node){
16385 var el = this.dataName ?
16386 this.el.child('.roo-tpl-' + this.dataName,true) :
16389 if(!node || node.parentNode == el){
16392 var p = node.parentNode;
16393 while(p && p != el){
16394 if(p.parentNode == el){
16403 onClick : function(e){
16404 var item = this.findItemFromChild(e.getTarget());
16406 var index = this.indexOf(item);
16407 if(this.onItemClick(item, index, e) !== false){
16408 this.fireEvent("click", this, index, item, e);
16411 this.clearSelections();
16416 onContextMenu : function(e){
16417 var item = this.findItemFromChild(e.getTarget());
16419 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16424 onDblClick : function(e){
16425 var item = this.findItemFromChild(e.getTarget());
16427 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16431 onItemClick : function(item, index, e)
16433 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16436 if (this.toggleSelect) {
16437 var m = this.isSelected(item) ? 'unselect' : 'select';
16440 _t[m](item, true, false);
16443 if(this.multiSelect || this.singleSelect){
16444 if(this.multiSelect && e.shiftKey && this.lastSelection){
16445 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16447 this.select(item, this.multiSelect && e.ctrlKey);
16448 this.lastSelection = item;
16451 if(!this.tickable){
16452 e.preventDefault();
16460 * Get the number of selected nodes.
16463 getSelectionCount : function(){
16464 return this.selections.length;
16468 * Get the currently selected nodes.
16469 * @return {Array} An array of HTMLElements
16471 getSelectedNodes : function(){
16472 return this.selections;
16476 * Get the indexes of the selected nodes.
16479 getSelectedIndexes : function(){
16480 var indexes = [], s = this.selections;
16481 for(var i = 0, len = s.length; i < len; i++){
16482 indexes.push(s[i].nodeIndex);
16488 * Clear all selections
16489 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16491 clearSelections : function(suppressEvent){
16492 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16493 this.cmp.elements = this.selections;
16494 this.cmp.removeClass(this.selectedClass);
16495 this.selections = [];
16496 if(!suppressEvent){
16497 this.fireEvent("selectionchange", this, this.selections);
16503 * Returns true if the passed node is selected
16504 * @param {HTMLElement/Number} node The node or node index
16505 * @return {Boolean}
16507 isSelected : function(node){
16508 var s = this.selections;
16512 node = this.getNode(node);
16513 return s.indexOf(node) !== -1;
16518 * @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
16519 * @param {Boolean} keepExisting (optional) true to keep existing selections
16520 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16522 select : function(nodeInfo, keepExisting, suppressEvent){
16523 if(nodeInfo instanceof Array){
16525 this.clearSelections(true);
16527 for(var i = 0, len = nodeInfo.length; i < len; i++){
16528 this.select(nodeInfo[i], true, true);
16532 var node = this.getNode(nodeInfo);
16533 if(!node || this.isSelected(node)){
16534 return; // already selected.
16537 this.clearSelections(true);
16540 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16541 Roo.fly(node).addClass(this.selectedClass);
16542 this.selections.push(node);
16543 if(!suppressEvent){
16544 this.fireEvent("selectionchange", this, this.selections);
16552 * @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
16553 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16554 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16556 unselect : function(nodeInfo, keepExisting, suppressEvent)
16558 if(nodeInfo instanceof Array){
16559 Roo.each(this.selections, function(s) {
16560 this.unselect(s, nodeInfo);
16564 var node = this.getNode(nodeInfo);
16565 if(!node || !this.isSelected(node)){
16566 //Roo.log("not selected");
16567 return; // not selected.
16571 Roo.each(this.selections, function(s) {
16573 Roo.fly(node).removeClass(this.selectedClass);
16580 this.selections= ns;
16581 this.fireEvent("selectionchange", this, this.selections);
16585 * Gets a template node.
16586 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16587 * @return {HTMLElement} The node or null if it wasn't found
16589 getNode : function(nodeInfo){
16590 if(typeof nodeInfo == "string"){
16591 return document.getElementById(nodeInfo);
16592 }else if(typeof nodeInfo == "number"){
16593 return this.nodes[nodeInfo];
16599 * Gets a range template nodes.
16600 * @param {Number} startIndex
16601 * @param {Number} endIndex
16602 * @return {Array} An array of nodes
16604 getNodes : function(start, end){
16605 var ns = this.nodes;
16606 start = start || 0;
16607 end = typeof end == "undefined" ? ns.length - 1 : end;
16610 for(var i = start; i <= end; i++){
16614 for(var i = start; i >= end; i--){
16622 * Finds the index of the passed node
16623 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16624 * @return {Number} The index of the node or -1
16626 indexOf : function(node){
16627 node = this.getNode(node);
16628 if(typeof node.nodeIndex == "number"){
16629 return node.nodeIndex;
16631 var ns = this.nodes;
16632 for(var i = 0, len = ns.length; i < len; i++){
16643 * based on jquery fullcalendar
16647 Roo.bootstrap = Roo.bootstrap || {};
16649 * @class Roo.bootstrap.Calendar
16650 * @extends Roo.bootstrap.Component
16651 * Bootstrap Calendar class
16652 * @cfg {Boolean} loadMask (true|false) default false
16653 * @cfg {Object} header generate the user specific header of the calendar, default false
16656 * Create a new Container
16657 * @param {Object} config The config object
16662 Roo.bootstrap.Calendar = function(config){
16663 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16667 * Fires when a date is selected
16668 * @param {DatePicker} this
16669 * @param {Date} date The selected date
16673 * @event monthchange
16674 * Fires when the displayed month changes
16675 * @param {DatePicker} this
16676 * @param {Date} date The selected month
16678 'monthchange': true,
16680 * @event evententer
16681 * Fires when mouse over an event
16682 * @param {Calendar} this
16683 * @param {event} Event
16685 'evententer': true,
16687 * @event eventleave
16688 * Fires when the mouse leaves an
16689 * @param {Calendar} this
16692 'eventleave': true,
16694 * @event eventclick
16695 * Fires when the mouse click an
16696 * @param {Calendar} this
16705 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16708 * @cfg {Number} startDay
16709 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16717 getAutoCreate : function(){
16720 var fc_button = function(name, corner, style, content ) {
16721 return Roo.apply({},{
16723 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16725 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16728 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16739 style : 'width:100%',
16746 cls : 'fc-header-left',
16748 fc_button('prev', 'left', 'arrow', '‹' ),
16749 fc_button('next', 'right', 'arrow', '›' ),
16750 { tag: 'span', cls: 'fc-header-space' },
16751 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16759 cls : 'fc-header-center',
16763 cls: 'fc-header-title',
16766 html : 'month / year'
16774 cls : 'fc-header-right',
16776 /* fc_button('month', 'left', '', 'month' ),
16777 fc_button('week', '', '', 'week' ),
16778 fc_button('day', 'right', '', 'day' )
16790 header = this.header;
16793 var cal_heads = function() {
16795 // fixme - handle this.
16797 for (var i =0; i < Date.dayNames.length; i++) {
16798 var d = Date.dayNames[i];
16801 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16802 html : d.substring(0,3)
16806 ret[0].cls += ' fc-first';
16807 ret[6].cls += ' fc-last';
16810 var cal_cell = function(n) {
16813 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16818 cls: 'fc-day-number',
16822 cls: 'fc-day-content',
16826 style: 'position: relative;' // height: 17px;
16838 var cal_rows = function() {
16841 for (var r = 0; r < 6; r++) {
16848 for (var i =0; i < Date.dayNames.length; i++) {
16849 var d = Date.dayNames[i];
16850 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16853 row.cn[0].cls+=' fc-first';
16854 row.cn[0].cn[0].style = 'min-height:90px';
16855 row.cn[6].cls+=' fc-last';
16859 ret[0].cls += ' fc-first';
16860 ret[4].cls += ' fc-prev-last';
16861 ret[5].cls += ' fc-last';
16868 cls: 'fc-border-separate',
16869 style : 'width:100%',
16877 cls : 'fc-first fc-last',
16895 cls : 'fc-content',
16896 style : "position: relative;",
16899 cls : 'fc-view fc-view-month fc-grid',
16900 style : 'position: relative',
16901 unselectable : 'on',
16904 cls : 'fc-event-container',
16905 style : 'position:absolute;z-index:8;top:0;left:0;'
16923 initEvents : function()
16926 throw "can not find store for calendar";
16932 style: "text-align:center",
16936 style: "background-color:white;width:50%;margin:250 auto",
16940 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16951 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16953 var size = this.el.select('.fc-content', true).first().getSize();
16954 this.maskEl.setSize(size.width, size.height);
16955 this.maskEl.enableDisplayMode("block");
16956 if(!this.loadMask){
16957 this.maskEl.hide();
16960 this.store = Roo.factory(this.store, Roo.data);
16961 this.store.on('load', this.onLoad, this);
16962 this.store.on('beforeload', this.onBeforeLoad, this);
16966 this.cells = this.el.select('.fc-day',true);
16967 //Roo.log(this.cells);
16968 this.textNodes = this.el.query('.fc-day-number');
16969 this.cells.addClassOnOver('fc-state-hover');
16971 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16972 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16973 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16974 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16976 this.on('monthchange', this.onMonthChange, this);
16978 this.update(new Date().clearTime());
16981 resize : function() {
16982 var sz = this.el.getSize();
16984 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16985 this.el.select('.fc-day-content div',true).setHeight(34);
16990 showPrevMonth : function(e){
16991 this.update(this.activeDate.add("mo", -1));
16993 showToday : function(e){
16994 this.update(new Date().clearTime());
16997 showNextMonth : function(e){
16998 this.update(this.activeDate.add("mo", 1));
17002 showPrevYear : function(){
17003 this.update(this.activeDate.add("y", -1));
17007 showNextYear : function(){
17008 this.update(this.activeDate.add("y", 1));
17013 update : function(date)
17015 var vd = this.activeDate;
17016 this.activeDate = date;
17017 // if(vd && this.el){
17018 // var t = date.getTime();
17019 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17020 // Roo.log('using add remove');
17022 // this.fireEvent('monthchange', this, date);
17024 // this.cells.removeClass("fc-state-highlight");
17025 // this.cells.each(function(c){
17026 // if(c.dateValue == t){
17027 // c.addClass("fc-state-highlight");
17028 // setTimeout(function(){
17029 // try{c.dom.firstChild.focus();}catch(e){}
17039 var days = date.getDaysInMonth();
17041 var firstOfMonth = date.getFirstDateOfMonth();
17042 var startingPos = firstOfMonth.getDay()-this.startDay;
17044 if(startingPos < this.startDay){
17048 var pm = date.add(Date.MONTH, -1);
17049 var prevStart = pm.getDaysInMonth()-startingPos;
17051 this.cells = this.el.select('.fc-day',true);
17052 this.textNodes = this.el.query('.fc-day-number');
17053 this.cells.addClassOnOver('fc-state-hover');
17055 var cells = this.cells.elements;
17056 var textEls = this.textNodes;
17058 Roo.each(cells, function(cell){
17059 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17062 days += startingPos;
17064 // convert everything to numbers so it's fast
17065 var day = 86400000;
17066 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17069 //Roo.log(prevStart);
17071 var today = new Date().clearTime().getTime();
17072 var sel = date.clearTime().getTime();
17073 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17074 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17075 var ddMatch = this.disabledDatesRE;
17076 var ddText = this.disabledDatesText;
17077 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17078 var ddaysText = this.disabledDaysText;
17079 var format = this.format;
17081 var setCellClass = function(cal, cell){
17085 //Roo.log('set Cell Class');
17087 var t = d.getTime();
17091 cell.dateValue = t;
17093 cell.className += " fc-today";
17094 cell.className += " fc-state-highlight";
17095 cell.title = cal.todayText;
17098 // disable highlight in other month..
17099 //cell.className += " fc-state-highlight";
17104 cell.className = " fc-state-disabled";
17105 cell.title = cal.minText;
17109 cell.className = " fc-state-disabled";
17110 cell.title = cal.maxText;
17114 if(ddays.indexOf(d.getDay()) != -1){
17115 cell.title = ddaysText;
17116 cell.className = " fc-state-disabled";
17119 if(ddMatch && format){
17120 var fvalue = d.dateFormat(format);
17121 if(ddMatch.test(fvalue)){
17122 cell.title = ddText.replace("%0", fvalue);
17123 cell.className = " fc-state-disabled";
17127 if (!cell.initialClassName) {
17128 cell.initialClassName = cell.dom.className;
17131 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17136 for(; i < startingPos; i++) {
17137 textEls[i].innerHTML = (++prevStart);
17138 d.setDate(d.getDate()+1);
17140 cells[i].className = "fc-past fc-other-month";
17141 setCellClass(this, cells[i]);
17146 for(; i < days; i++){
17147 intDay = i - startingPos + 1;
17148 textEls[i].innerHTML = (intDay);
17149 d.setDate(d.getDate()+1);
17151 cells[i].className = ''; // "x-date-active";
17152 setCellClass(this, cells[i]);
17156 for(; i < 42; i++) {
17157 textEls[i].innerHTML = (++extraDays);
17158 d.setDate(d.getDate()+1);
17160 cells[i].className = "fc-future fc-other-month";
17161 setCellClass(this, cells[i]);
17164 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17166 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17168 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17169 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17171 if(totalRows != 6){
17172 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17173 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17176 this.fireEvent('monthchange', this, date);
17180 if(!this.internalRender){
17181 var main = this.el.dom.firstChild;
17182 var w = main.offsetWidth;
17183 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17184 Roo.fly(main).setWidth(w);
17185 this.internalRender = true;
17186 // opera does not respect the auto grow header center column
17187 // then, after it gets a width opera refuses to recalculate
17188 // without a second pass
17189 if(Roo.isOpera && !this.secondPass){
17190 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17191 this.secondPass = true;
17192 this.update.defer(10, this, [date]);
17199 findCell : function(dt) {
17200 dt = dt.clearTime().getTime();
17202 this.cells.each(function(c){
17203 //Roo.log("check " +c.dateValue + '?=' + dt);
17204 if(c.dateValue == dt){
17214 findCells : function(ev) {
17215 var s = ev.start.clone().clearTime().getTime();
17217 var e= ev.end.clone().clearTime().getTime();
17220 this.cells.each(function(c){
17221 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17223 if(c.dateValue > e){
17226 if(c.dateValue < s){
17235 // findBestRow: function(cells)
17239 // for (var i =0 ; i < cells.length;i++) {
17240 // ret = Math.max(cells[i].rows || 0,ret);
17247 addItem : function(ev)
17249 // look for vertical location slot in
17250 var cells = this.findCells(ev);
17252 // ev.row = this.findBestRow(cells);
17254 // work out the location.
17258 for(var i =0; i < cells.length; i++) {
17260 cells[i].row = cells[0].row;
17263 cells[i].row = cells[i].row + 1;
17273 if (crow.start.getY() == cells[i].getY()) {
17275 crow.end = cells[i];
17292 cells[0].events.push(ev);
17294 this.calevents.push(ev);
17297 clearEvents: function() {
17299 if(!this.calevents){
17303 Roo.each(this.cells.elements, function(c){
17309 Roo.each(this.calevents, function(e) {
17310 Roo.each(e.els, function(el) {
17311 el.un('mouseenter' ,this.onEventEnter, this);
17312 el.un('mouseleave' ,this.onEventLeave, this);
17317 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17323 renderEvents: function()
17327 this.cells.each(function(c) {
17336 if(c.row != c.events.length){
17337 r = 4 - (4 - (c.row - c.events.length));
17340 c.events = ev.slice(0, r);
17341 c.more = ev.slice(r);
17343 if(c.more.length && c.more.length == 1){
17344 c.events.push(c.more.pop());
17347 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17351 this.cells.each(function(c) {
17353 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17356 for (var e = 0; e < c.events.length; e++){
17357 var ev = c.events[e];
17358 var rows = ev.rows;
17360 for(var i = 0; i < rows.length; i++) {
17362 // how many rows should it span..
17365 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17366 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17368 unselectable : "on",
17371 cls: 'fc-event-inner',
17375 // cls: 'fc-event-time',
17376 // html : cells.length > 1 ? '' : ev.time
17380 cls: 'fc-event-title',
17381 html : String.format('{0}', ev.title)
17388 cls: 'ui-resizable-handle ui-resizable-e',
17389 html : '  '
17396 cfg.cls += ' fc-event-start';
17398 if ((i+1) == rows.length) {
17399 cfg.cls += ' fc-event-end';
17402 var ctr = _this.el.select('.fc-event-container',true).first();
17403 var cg = ctr.createChild(cfg);
17405 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17406 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17408 var r = (c.more.length) ? 1 : 0;
17409 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17410 cg.setWidth(ebox.right - sbox.x -2);
17412 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17413 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17414 cg.on('click', _this.onEventClick, _this, ev);
17425 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17426 style : 'position: absolute',
17427 unselectable : "on",
17430 cls: 'fc-event-inner',
17434 cls: 'fc-event-title',
17442 cls: 'ui-resizable-handle ui-resizable-e',
17443 html : '  '
17449 var ctr = _this.el.select('.fc-event-container',true).first();
17450 var cg = ctr.createChild(cfg);
17452 var sbox = c.select('.fc-day-content',true).first().getBox();
17453 var ebox = c.select('.fc-day-content',true).first().getBox();
17455 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17456 cg.setWidth(ebox.right - sbox.x -2);
17458 cg.on('click', _this.onMoreEventClick, _this, c.more);
17468 onEventEnter: function (e, el,event,d) {
17469 this.fireEvent('evententer', this, el, event);
17472 onEventLeave: function (e, el,event,d) {
17473 this.fireEvent('eventleave', this, el, event);
17476 onEventClick: function (e, el,event,d) {
17477 this.fireEvent('eventclick', this, el, event);
17480 onMonthChange: function () {
17484 onMoreEventClick: function(e, el, more)
17488 this.calpopover.placement = 'right';
17489 this.calpopover.setTitle('More');
17491 this.calpopover.setContent('');
17493 var ctr = this.calpopover.el.select('.popover-content', true).first();
17495 Roo.each(more, function(m){
17497 cls : 'fc-event-hori fc-event-draggable',
17500 var cg = ctr.createChild(cfg);
17502 cg.on('click', _this.onEventClick, _this, m);
17505 this.calpopover.show(el);
17510 onLoad: function ()
17512 this.calevents = [];
17515 if(this.store.getCount() > 0){
17516 this.store.data.each(function(d){
17519 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17520 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17521 time : d.data.start_time,
17522 title : d.data.title,
17523 description : d.data.description,
17524 venue : d.data.venue
17529 this.renderEvents();
17531 if(this.calevents.length && this.loadMask){
17532 this.maskEl.hide();
17536 onBeforeLoad: function()
17538 this.clearEvents();
17540 this.maskEl.show();
17554 * @class Roo.bootstrap.Popover
17555 * @extends Roo.bootstrap.Component
17556 * Bootstrap Popover class
17557 * @cfg {String} html contents of the popover (or false to use children..)
17558 * @cfg {String} title of popover (or false to hide)
17559 * @cfg {String} placement how it is placed
17560 * @cfg {String} trigger click || hover (or false to trigger manually)
17561 * @cfg {String} over what (parent or false to trigger manually.)
17562 * @cfg {Number} delay - delay before showing
17565 * Create a new Popover
17566 * @param {Object} config The config object
17569 Roo.bootstrap.Popover = function(config){
17570 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17576 * After the popover show
17578 * @param {Roo.bootstrap.Popover} this
17583 * After the popover hide
17585 * @param {Roo.bootstrap.Popover} this
17591 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17593 title: 'Fill in a title',
17596 placement : 'right',
17597 trigger : 'hover', // hover
17603 can_build_overlaid : false,
17605 getChildContainer : function()
17607 return this.el.select('.popover-content',true).first();
17610 getAutoCreate : function(){
17613 cls : 'popover roo-dynamic',
17614 style: 'display:block',
17620 cls : 'popover-inner',
17624 cls: 'popover-title',
17628 cls : 'popover-content',
17639 setTitle: function(str)
17642 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17644 setContent: function(str)
17647 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17649 // as it get's added to the bottom of the page.
17650 onRender : function(ct, position)
17652 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17654 var cfg = Roo.apply({}, this.getAutoCreate());
17658 cfg.cls += ' ' + this.cls;
17661 cfg.style = this.style;
17663 //Roo.log("adding to ");
17664 this.el = Roo.get(document.body).createChild(cfg, position);
17665 // Roo.log(this.el);
17670 initEvents : function()
17672 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17673 this.el.enableDisplayMode('block');
17675 if (this.over === false) {
17678 if (this.triggers === false) {
17681 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17682 var triggers = this.trigger ? this.trigger.split(' ') : [];
17683 Roo.each(triggers, function(trigger) {
17685 if (trigger == 'click') {
17686 on_el.on('click', this.toggle, this);
17687 } else if (trigger != 'manual') {
17688 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17689 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17691 on_el.on(eventIn ,this.enter, this);
17692 on_el.on(eventOut, this.leave, this);
17703 toggle : function () {
17704 this.hoverState == 'in' ? this.leave() : this.enter();
17707 enter : function () {
17709 clearTimeout(this.timeout);
17711 this.hoverState = 'in';
17713 if (!this.delay || !this.delay.show) {
17718 this.timeout = setTimeout(function () {
17719 if (_t.hoverState == 'in') {
17722 }, this.delay.show)
17725 leave : function() {
17726 clearTimeout(this.timeout);
17728 this.hoverState = 'out';
17730 if (!this.delay || !this.delay.hide) {
17735 this.timeout = setTimeout(function () {
17736 if (_t.hoverState == 'out') {
17739 }, this.delay.hide)
17742 show : function (on_el)
17745 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17749 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17750 if (this.html !== false) {
17751 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17753 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17754 if (!this.title.length) {
17755 this.el.select('.popover-title',true).hide();
17758 var placement = typeof this.placement == 'function' ?
17759 this.placement.call(this, this.el, on_el) :
17762 var autoToken = /\s?auto?\s?/i;
17763 var autoPlace = autoToken.test(placement);
17765 placement = placement.replace(autoToken, '') || 'top';
17769 //this.el.setXY([0,0]);
17771 this.el.dom.style.display='block';
17772 this.el.addClass(placement);
17774 //this.el.appendTo(on_el);
17776 var p = this.getPosition();
17777 var box = this.el.getBox();
17782 var align = Roo.bootstrap.Popover.alignment[placement];
17785 this.el.alignTo(on_el, align[0],align[1]);
17786 //var arrow = this.el.select('.arrow',true).first();
17787 //arrow.set(align[2],
17789 this.el.addClass('in');
17792 if (this.el.hasClass('fade')) {
17796 this.hoverState = 'in';
17798 this.fireEvent('show', this);
17803 this.el.setXY([0,0]);
17804 this.el.removeClass('in');
17806 this.hoverState = null;
17808 this.fireEvent('hide', this);
17813 Roo.bootstrap.Popover.alignment = {
17814 'left' : ['r-l', [-10,0], 'right'],
17815 'right' : ['l-r', [10,0], 'left'],
17816 'bottom' : ['t-b', [0,10], 'top'],
17817 'top' : [ 'b-t', [0,-10], 'bottom']
17828 * @class Roo.bootstrap.Progress
17829 * @extends Roo.bootstrap.Component
17830 * Bootstrap Progress class
17831 * @cfg {Boolean} striped striped of the progress bar
17832 * @cfg {Boolean} active animated of the progress bar
17836 * Create a new Progress
17837 * @param {Object} config The config object
17840 Roo.bootstrap.Progress = function(config){
17841 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17844 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17849 getAutoCreate : function(){
17857 cfg.cls += ' progress-striped';
17861 cfg.cls += ' active';
17880 * @class Roo.bootstrap.ProgressBar
17881 * @extends Roo.bootstrap.Component
17882 * Bootstrap ProgressBar class
17883 * @cfg {Number} aria_valuenow aria-value now
17884 * @cfg {Number} aria_valuemin aria-value min
17885 * @cfg {Number} aria_valuemax aria-value max
17886 * @cfg {String} label label for the progress bar
17887 * @cfg {String} panel (success | info | warning | danger )
17888 * @cfg {String} role role of the progress bar
17889 * @cfg {String} sr_only text
17893 * Create a new ProgressBar
17894 * @param {Object} config The config object
17897 Roo.bootstrap.ProgressBar = function(config){
17898 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17901 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17905 aria_valuemax : 100,
17911 getAutoCreate : function()
17916 cls: 'progress-bar',
17917 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17929 cfg.role = this.role;
17932 if(this.aria_valuenow){
17933 cfg['aria-valuenow'] = this.aria_valuenow;
17936 if(this.aria_valuemin){
17937 cfg['aria-valuemin'] = this.aria_valuemin;
17940 if(this.aria_valuemax){
17941 cfg['aria-valuemax'] = this.aria_valuemax;
17944 if(this.label && !this.sr_only){
17945 cfg.html = this.label;
17949 cfg.cls += ' progress-bar-' + this.panel;
17955 update : function(aria_valuenow)
17957 this.aria_valuenow = aria_valuenow;
17959 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17974 * @class Roo.bootstrap.TabGroup
17975 * @extends Roo.bootstrap.Column
17976 * Bootstrap Column class
17977 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17978 * @cfg {Boolean} carousel true to make the group behave like a carousel
17979 * @cfg {Boolean} bullets show bullets for the panels
17980 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17981 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17982 * @cfg {Boolean} showarrow (true|false) show arrow default true
17985 * Create a new TabGroup
17986 * @param {Object} config The config object
17989 Roo.bootstrap.TabGroup = function(config){
17990 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17992 this.navId = Roo.id();
17995 Roo.bootstrap.TabGroup.register(this);
17999 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18002 transition : false,
18007 slideOnTouch : false,
18010 getAutoCreate : function()
18012 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18014 cfg.cls += ' tab-content';
18016 if (this.carousel) {
18017 cfg.cls += ' carousel slide';
18020 cls : 'carousel-inner',
18024 if(this.bullets && !Roo.isTouch){
18027 cls : 'carousel-bullets',
18031 if(this.bullets_cls){
18032 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18039 cfg.cn[0].cn.push(bullets);
18042 if(this.showarrow){
18043 cfg.cn[0].cn.push({
18045 class : 'carousel-arrow',
18049 class : 'carousel-prev',
18053 class : 'fa fa-chevron-left'
18059 class : 'carousel-next',
18063 class : 'fa fa-chevron-right'
18076 initEvents: function()
18078 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18079 // this.el.on("touchstart", this.onTouchStart, this);
18082 if(this.autoslide){
18085 this.slideFn = window.setInterval(function() {
18086 _this.showPanelNext();
18090 if(this.showarrow){
18091 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18092 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18098 // onTouchStart : function(e, el, o)
18100 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18104 // this.showPanelNext();
18108 getChildContainer : function()
18110 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18114 * register a Navigation item
18115 * @param {Roo.bootstrap.NavItem} the navitem to add
18117 register : function(item)
18119 this.tabs.push( item);
18120 item.navId = this.navId; // not really needed..
18125 getActivePanel : function()
18128 Roo.each(this.tabs, function(t) {
18138 getPanelByName : function(n)
18141 Roo.each(this.tabs, function(t) {
18142 if (t.tabId == n) {
18150 indexOfPanel : function(p)
18153 Roo.each(this.tabs, function(t,i) {
18154 if (t.tabId == p.tabId) {
18163 * show a specific panel
18164 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18165 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18167 showPanel : function (pan)
18169 if(this.transition || typeof(pan) == 'undefined'){
18170 Roo.log("waiting for the transitionend");
18174 if (typeof(pan) == 'number') {
18175 pan = this.tabs[pan];
18178 if (typeof(pan) == 'string') {
18179 pan = this.getPanelByName(pan);
18182 var cur = this.getActivePanel();
18185 Roo.log('pan or acitve pan is undefined');
18189 if (pan.tabId == this.getActivePanel().tabId) {
18193 if (false === cur.fireEvent('beforedeactivate')) {
18197 if(this.bullets > 0 && !Roo.isTouch){
18198 this.setActiveBullet(this.indexOfPanel(pan));
18201 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18203 this.transition = true;
18204 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18205 var lr = dir == 'next' ? 'left' : 'right';
18206 pan.el.addClass(dir); // or prev
18207 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18208 cur.el.addClass(lr); // or right
18209 pan.el.addClass(lr);
18212 cur.el.on('transitionend', function() {
18213 Roo.log("trans end?");
18215 pan.el.removeClass([lr,dir]);
18216 pan.setActive(true);
18218 cur.el.removeClass([lr]);
18219 cur.setActive(false);
18221 _this.transition = false;
18223 }, this, { single: true } );
18228 cur.setActive(false);
18229 pan.setActive(true);
18234 showPanelNext : function()
18236 var i = this.indexOfPanel(this.getActivePanel());
18238 if (i >= this.tabs.length - 1 && !this.autoslide) {
18242 if (i >= this.tabs.length - 1 && this.autoslide) {
18246 this.showPanel(this.tabs[i+1]);
18249 showPanelPrev : function()
18251 var i = this.indexOfPanel(this.getActivePanel());
18253 if (i < 1 && !this.autoslide) {
18257 if (i < 1 && this.autoslide) {
18258 i = this.tabs.length;
18261 this.showPanel(this.tabs[i-1]);
18265 addBullet: function()
18267 if(!this.bullets || Roo.isTouch){
18270 var ctr = this.el.select('.carousel-bullets',true).first();
18271 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18272 var bullet = ctr.createChild({
18273 cls : 'bullet bullet-' + i
18274 },ctr.dom.lastChild);
18279 bullet.on('click', (function(e, el, o, ii, t){
18281 e.preventDefault();
18283 this.showPanel(ii);
18285 if(this.autoslide && this.slideFn){
18286 clearInterval(this.slideFn);
18287 this.slideFn = window.setInterval(function() {
18288 _this.showPanelNext();
18292 }).createDelegate(this, [i, bullet], true));
18297 setActiveBullet : function(i)
18303 Roo.each(this.el.select('.bullet', true).elements, function(el){
18304 el.removeClass('selected');
18307 var bullet = this.el.select('.bullet-' + i, true).first();
18313 bullet.addClass('selected');
18324 Roo.apply(Roo.bootstrap.TabGroup, {
18328 * register a Navigation Group
18329 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18331 register : function(navgrp)
18333 this.groups[navgrp.navId] = navgrp;
18337 * fetch a Navigation Group based on the navigation ID
18338 * if one does not exist , it will get created.
18339 * @param {string} the navgroup to add
18340 * @returns {Roo.bootstrap.NavGroup} the navgroup
18342 get: function(navId) {
18343 if (typeof(this.groups[navId]) == 'undefined') {
18344 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18346 return this.groups[navId] ;
18361 * @class Roo.bootstrap.TabPanel
18362 * @extends Roo.bootstrap.Component
18363 * Bootstrap TabPanel class
18364 * @cfg {Boolean} active panel active
18365 * @cfg {String} html panel content
18366 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18367 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18368 * @cfg {String} href click to link..
18372 * Create a new TabPanel
18373 * @param {Object} config The config object
18376 Roo.bootstrap.TabPanel = function(config){
18377 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18381 * Fires when the active status changes
18382 * @param {Roo.bootstrap.TabPanel} this
18383 * @param {Boolean} state the new state
18388 * @event beforedeactivate
18389 * Fires before a tab is de-activated - can be used to do validation on a form.
18390 * @param {Roo.bootstrap.TabPanel} this
18391 * @return {Boolean} false if there is an error
18394 'beforedeactivate': true
18397 this.tabId = this.tabId || Roo.id();
18401 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18409 getAutoCreate : function(){
18412 // item is needed for carousel - not sure if it has any effect otherwise
18413 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18414 html: this.html || ''
18418 cfg.cls += ' active';
18422 cfg.tabId = this.tabId;
18429 initEvents: function()
18431 var p = this.parent();
18433 this.navId = this.navId || p.navId;
18435 if (typeof(this.navId) != 'undefined') {
18436 // not really needed.. but just in case.. parent should be a NavGroup.
18437 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18441 var i = tg.tabs.length - 1;
18443 if(this.active && tg.bullets > 0 && i < tg.bullets){
18444 tg.setActiveBullet(i);
18448 this.el.on('click', this.onClick, this);
18451 this.el.on("touchstart", this.onTouchStart, this);
18452 this.el.on("touchmove", this.onTouchMove, this);
18453 this.el.on("touchend", this.onTouchEnd, this);
18458 onRender : function(ct, position)
18460 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18463 setActive : function(state)
18465 Roo.log("panel - set active " + this.tabId + "=" + state);
18467 this.active = state;
18469 this.el.removeClass('active');
18471 } else if (!this.el.hasClass('active')) {
18472 this.el.addClass('active');
18475 this.fireEvent('changed', this, state);
18478 onClick : function(e)
18480 e.preventDefault();
18482 if(!this.href.length){
18486 window.location.href = this.href;
18495 onTouchStart : function(e)
18497 this.swiping = false;
18499 this.startX = e.browserEvent.touches[0].clientX;
18500 this.startY = e.browserEvent.touches[0].clientY;
18503 onTouchMove : function(e)
18505 this.swiping = true;
18507 this.endX = e.browserEvent.touches[0].clientX;
18508 this.endY = e.browserEvent.touches[0].clientY;
18511 onTouchEnd : function(e)
18518 var tabGroup = this.parent();
18520 if(this.endX > this.startX){ // swiping right
18521 tabGroup.showPanelPrev();
18525 if(this.startX > this.endX){ // swiping left
18526 tabGroup.showPanelNext();
18545 * @class Roo.bootstrap.DateField
18546 * @extends Roo.bootstrap.Input
18547 * Bootstrap DateField class
18548 * @cfg {Number} weekStart default 0
18549 * @cfg {String} viewMode default empty, (months|years)
18550 * @cfg {String} minViewMode default empty, (months|years)
18551 * @cfg {Number} startDate default -Infinity
18552 * @cfg {Number} endDate default Infinity
18553 * @cfg {Boolean} todayHighlight default false
18554 * @cfg {Boolean} todayBtn default false
18555 * @cfg {Boolean} calendarWeeks default false
18556 * @cfg {Object} daysOfWeekDisabled default empty
18557 * @cfg {Boolean} singleMode default false (true | false)
18559 * @cfg {Boolean} keyboardNavigation default true
18560 * @cfg {String} language default en
18563 * Create a new DateField
18564 * @param {Object} config The config object
18567 Roo.bootstrap.DateField = function(config){
18568 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18572 * Fires when this field show.
18573 * @param {Roo.bootstrap.DateField} this
18574 * @param {Mixed} date The date value
18579 * Fires when this field hide.
18580 * @param {Roo.bootstrap.DateField} this
18581 * @param {Mixed} date The date value
18586 * Fires when select a date.
18587 * @param {Roo.bootstrap.DateField} this
18588 * @param {Mixed} date The date value
18592 * @event beforeselect
18593 * Fires when before select a date.
18594 * @param {Roo.bootstrap.DateField} this
18595 * @param {Mixed} date The date value
18597 beforeselect : true
18601 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18604 * @cfg {String} format
18605 * The default date format string which can be overriden for localization support. The format must be
18606 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18610 * @cfg {String} altFormats
18611 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18612 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18614 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18622 todayHighlight : false,
18628 keyboardNavigation: true,
18630 calendarWeeks: false,
18632 startDate: -Infinity,
18636 daysOfWeekDisabled: [],
18640 singleMode : false,
18642 UTCDate: function()
18644 return new Date(Date.UTC.apply(Date, arguments));
18647 UTCToday: function()
18649 var today = new Date();
18650 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18653 getDate: function() {
18654 var d = this.getUTCDate();
18655 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18658 getUTCDate: function() {
18662 setDate: function(d) {
18663 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18666 setUTCDate: function(d) {
18668 this.setValue(this.formatDate(this.date));
18671 onRender: function(ct, position)
18674 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18676 this.language = this.language || 'en';
18677 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18678 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18680 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18681 this.format = this.format || 'm/d/y';
18682 this.isInline = false;
18683 this.isInput = true;
18684 this.component = this.el.select('.add-on', true).first() || false;
18685 this.component = (this.component && this.component.length === 0) ? false : this.component;
18686 this.hasInput = this.component && this.inputEl().length;
18688 if (typeof(this.minViewMode === 'string')) {
18689 switch (this.minViewMode) {
18691 this.minViewMode = 1;
18694 this.minViewMode = 2;
18697 this.minViewMode = 0;
18702 if (typeof(this.viewMode === 'string')) {
18703 switch (this.viewMode) {
18716 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18718 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18720 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18722 this.picker().on('mousedown', this.onMousedown, this);
18723 this.picker().on('click', this.onClick, this);
18725 this.picker().addClass('datepicker-dropdown');
18727 this.startViewMode = this.viewMode;
18729 if(this.singleMode){
18730 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18731 v.setVisibilityMode(Roo.Element.DISPLAY);
18735 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18736 v.setStyle('width', '189px');
18740 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18741 if(!this.calendarWeeks){
18746 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18747 v.attr('colspan', function(i, val){
18748 return parseInt(val) + 1;
18753 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18755 this.setStartDate(this.startDate);
18756 this.setEndDate(this.endDate);
18758 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18765 if(this.isInline) {
18770 picker : function()
18772 return this.pickerEl;
18773 // return this.el.select('.datepicker', true).first();
18776 fillDow: function()
18778 var dowCnt = this.weekStart;
18787 if(this.calendarWeeks){
18795 while (dowCnt < this.weekStart + 7) {
18799 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18803 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18806 fillMonths: function()
18809 var months = this.picker().select('>.datepicker-months td', true).first();
18811 months.dom.innerHTML = '';
18817 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18820 months.createChild(month);
18827 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;
18829 if (this.date < this.startDate) {
18830 this.viewDate = new Date(this.startDate);
18831 } else if (this.date > this.endDate) {
18832 this.viewDate = new Date(this.endDate);
18834 this.viewDate = new Date(this.date);
18842 var d = new Date(this.viewDate),
18843 year = d.getUTCFullYear(),
18844 month = d.getUTCMonth(),
18845 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18846 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18847 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18848 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18849 currentDate = this.date && this.date.valueOf(),
18850 today = this.UTCToday();
18852 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18854 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18856 // this.picker.select('>tfoot th.today').
18857 // .text(dates[this.language].today)
18858 // .toggle(this.todayBtn !== false);
18860 this.updateNavArrows();
18863 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18865 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18867 prevMonth.setUTCDate(day);
18869 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18871 var nextMonth = new Date(prevMonth);
18873 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18875 nextMonth = nextMonth.valueOf();
18877 var fillMonths = false;
18879 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18881 while(prevMonth.valueOf() <= nextMonth) {
18884 if (prevMonth.getUTCDay() === this.weekStart) {
18886 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18894 if(this.calendarWeeks){
18895 // ISO 8601: First week contains first thursday.
18896 // ISO also states week starts on Monday, but we can be more abstract here.
18898 // Start of current week: based on weekstart/current date
18899 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18900 // Thursday of this week
18901 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18902 // First Thursday of year, year from thursday
18903 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18904 // Calendar week: ms between thursdays, div ms per day, div 7 days
18905 calWeek = (th - yth) / 864e5 / 7 + 1;
18907 fillMonths.cn.push({
18915 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18917 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18920 if (this.todayHighlight &&
18921 prevMonth.getUTCFullYear() == today.getFullYear() &&
18922 prevMonth.getUTCMonth() == today.getMonth() &&
18923 prevMonth.getUTCDate() == today.getDate()) {
18924 clsName += ' today';
18927 if (currentDate && prevMonth.valueOf() === currentDate) {
18928 clsName += ' active';
18931 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18932 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18933 clsName += ' disabled';
18936 fillMonths.cn.push({
18938 cls: 'day ' + clsName,
18939 html: prevMonth.getDate()
18942 prevMonth.setDate(prevMonth.getDate()+1);
18945 var currentYear = this.date && this.date.getUTCFullYear();
18946 var currentMonth = this.date && this.date.getUTCMonth();
18948 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18950 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18951 v.removeClass('active');
18953 if(currentYear === year && k === currentMonth){
18954 v.addClass('active');
18957 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18958 v.addClass('disabled');
18964 year = parseInt(year/10, 10) * 10;
18966 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18968 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18971 for (var i = -1; i < 11; i++) {
18972 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18974 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18982 showMode: function(dir)
18985 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18988 Roo.each(this.picker().select('>div',true).elements, function(v){
18989 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18992 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18997 if(this.isInline) {
19001 this.picker().removeClass(['bottom', 'top']);
19003 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19005 * place to the top of element!
19009 this.picker().addClass('top');
19010 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19015 this.picker().addClass('bottom');
19017 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19020 parseDate : function(value)
19022 if(!value || value instanceof Date){
19025 var v = Date.parseDate(value, this.format);
19026 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19027 v = Date.parseDate(value, 'Y-m-d');
19029 if(!v && this.altFormats){
19030 if(!this.altFormatsArray){
19031 this.altFormatsArray = this.altFormats.split("|");
19033 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19034 v = Date.parseDate(value, this.altFormatsArray[i]);
19040 formatDate : function(date, fmt)
19042 return (!date || !(date instanceof Date)) ?
19043 date : date.dateFormat(fmt || this.format);
19046 onFocus : function()
19048 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19052 onBlur : function()
19054 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19056 var d = this.inputEl().getValue();
19063 showPopup : function()
19065 this.picker().show();
19069 this.fireEvent('showpopup', this, this.date);
19072 hidePopup : function()
19074 if(this.isInline) {
19077 this.picker().hide();
19078 this.viewMode = this.startViewMode;
19081 this.fireEvent('hidepopup', this, this.date);
19085 onMousedown: function(e)
19087 e.stopPropagation();
19088 e.preventDefault();
19093 Roo.bootstrap.DateField.superclass.keyup.call(this);
19097 setValue: function(v)
19099 if(this.fireEvent('beforeselect', this, v) !== false){
19100 var d = new Date(this.parseDate(v) ).clearTime();
19102 if(isNaN(d.getTime())){
19103 this.date = this.viewDate = '';
19104 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19108 v = this.formatDate(d);
19110 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19112 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19116 this.fireEvent('select', this, this.date);
19120 getValue: function()
19122 return this.formatDate(this.date);
19125 fireKey: function(e)
19127 if (!this.picker().isVisible()){
19128 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19134 var dateChanged = false,
19136 newDate, newViewDate;
19141 e.preventDefault();
19145 if (!this.keyboardNavigation) {
19148 dir = e.keyCode == 37 ? -1 : 1;
19151 newDate = this.moveYear(this.date, dir);
19152 newViewDate = this.moveYear(this.viewDate, dir);
19153 } else if (e.shiftKey){
19154 newDate = this.moveMonth(this.date, dir);
19155 newViewDate = this.moveMonth(this.viewDate, dir);
19157 newDate = new Date(this.date);
19158 newDate.setUTCDate(this.date.getUTCDate() + dir);
19159 newViewDate = new Date(this.viewDate);
19160 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19162 if (this.dateWithinRange(newDate)){
19163 this.date = newDate;
19164 this.viewDate = newViewDate;
19165 this.setValue(this.formatDate(this.date));
19167 e.preventDefault();
19168 dateChanged = true;
19173 if (!this.keyboardNavigation) {
19176 dir = e.keyCode == 38 ? -1 : 1;
19178 newDate = this.moveYear(this.date, dir);
19179 newViewDate = this.moveYear(this.viewDate, dir);
19180 } else if (e.shiftKey){
19181 newDate = this.moveMonth(this.date, dir);
19182 newViewDate = this.moveMonth(this.viewDate, dir);
19184 newDate = new Date(this.date);
19185 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19186 newViewDate = new Date(this.viewDate);
19187 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19189 if (this.dateWithinRange(newDate)){
19190 this.date = newDate;
19191 this.viewDate = newViewDate;
19192 this.setValue(this.formatDate(this.date));
19194 e.preventDefault();
19195 dateChanged = true;
19199 this.setValue(this.formatDate(this.date));
19201 e.preventDefault();
19204 this.setValue(this.formatDate(this.date));
19218 onClick: function(e)
19220 e.stopPropagation();
19221 e.preventDefault();
19223 var target = e.getTarget();
19225 if(target.nodeName.toLowerCase() === 'i'){
19226 target = Roo.get(target).dom.parentNode;
19229 var nodeName = target.nodeName;
19230 var className = target.className;
19231 var html = target.innerHTML;
19232 //Roo.log(nodeName);
19234 switch(nodeName.toLowerCase()) {
19236 switch(className) {
19242 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19243 switch(this.viewMode){
19245 this.viewDate = this.moveMonth(this.viewDate, dir);
19249 this.viewDate = this.moveYear(this.viewDate, dir);
19255 var date = new Date();
19256 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19258 this.setValue(this.formatDate(this.date));
19265 if (className.indexOf('disabled') < 0) {
19266 this.viewDate.setUTCDate(1);
19267 if (className.indexOf('month') > -1) {
19268 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19270 var year = parseInt(html, 10) || 0;
19271 this.viewDate.setUTCFullYear(year);
19275 if(this.singleMode){
19276 this.setValue(this.formatDate(this.viewDate));
19287 //Roo.log(className);
19288 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19289 var day = parseInt(html, 10) || 1;
19290 var year = this.viewDate.getUTCFullYear(),
19291 month = this.viewDate.getUTCMonth();
19293 if (className.indexOf('old') > -1) {
19300 } else if (className.indexOf('new') > -1) {
19308 //Roo.log([year,month,day]);
19309 this.date = this.UTCDate(year, month, day,0,0,0,0);
19310 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19312 //Roo.log(this.formatDate(this.date));
19313 this.setValue(this.formatDate(this.date));
19320 setStartDate: function(startDate)
19322 this.startDate = startDate || -Infinity;
19323 if (this.startDate !== -Infinity) {
19324 this.startDate = this.parseDate(this.startDate);
19327 this.updateNavArrows();
19330 setEndDate: function(endDate)
19332 this.endDate = endDate || Infinity;
19333 if (this.endDate !== Infinity) {
19334 this.endDate = this.parseDate(this.endDate);
19337 this.updateNavArrows();
19340 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19342 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19343 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19344 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19346 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19347 return parseInt(d, 10);
19350 this.updateNavArrows();
19353 updateNavArrows: function()
19355 if(this.singleMode){
19359 var d = new Date(this.viewDate),
19360 year = d.getUTCFullYear(),
19361 month = d.getUTCMonth();
19363 Roo.each(this.picker().select('.prev', true).elements, function(v){
19365 switch (this.viewMode) {
19368 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19374 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19381 Roo.each(this.picker().select('.next', true).elements, function(v){
19383 switch (this.viewMode) {
19386 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19392 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19400 moveMonth: function(date, dir)
19405 var new_date = new Date(date.valueOf()),
19406 day = new_date.getUTCDate(),
19407 month = new_date.getUTCMonth(),
19408 mag = Math.abs(dir),
19410 dir = dir > 0 ? 1 : -1;
19413 // If going back one month, make sure month is not current month
19414 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19416 return new_date.getUTCMonth() == month;
19418 // If going forward one month, make sure month is as expected
19419 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19421 return new_date.getUTCMonth() != new_month;
19423 new_month = month + dir;
19424 new_date.setUTCMonth(new_month);
19425 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19426 if (new_month < 0 || new_month > 11) {
19427 new_month = (new_month + 12) % 12;
19430 // For magnitudes >1, move one month at a time...
19431 for (var i=0; i<mag; i++) {
19432 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19433 new_date = this.moveMonth(new_date, dir);
19435 // ...then reset the day, keeping it in the new month
19436 new_month = new_date.getUTCMonth();
19437 new_date.setUTCDate(day);
19439 return new_month != new_date.getUTCMonth();
19442 // Common date-resetting loop -- if date is beyond end of month, make it
19445 new_date.setUTCDate(--day);
19446 new_date.setUTCMonth(new_month);
19451 moveYear: function(date, dir)
19453 return this.moveMonth(date, dir*12);
19456 dateWithinRange: function(date)
19458 return date >= this.startDate && date <= this.endDate;
19464 this.picker().remove();
19467 validateValue : function(value)
19469 if(this.getVisibilityEl().hasClass('hidden')){
19473 if(value.length < 1) {
19474 if(this.allowBlank){
19480 if(value.length < this.minLength){
19483 if(value.length > this.maxLength){
19487 var vt = Roo.form.VTypes;
19488 if(!vt[this.vtype](value, this)){
19492 if(typeof this.validator == "function"){
19493 var msg = this.validator(value);
19499 if(this.regex && !this.regex.test(value)){
19503 if(typeof(this.parseDate(value)) == 'undefined'){
19507 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19511 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19521 this.date = this.viewDate = '';
19523 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19528 Roo.apply(Roo.bootstrap.DateField, {
19539 html: '<i class="fa fa-arrow-left"/>'
19549 html: '<i class="fa fa-arrow-right"/>'
19591 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19592 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19593 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19594 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19595 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19608 navFnc: 'FullYear',
19613 navFnc: 'FullYear',
19618 Roo.apply(Roo.bootstrap.DateField, {
19622 cls: 'datepicker dropdown-menu roo-dynamic',
19626 cls: 'datepicker-days',
19630 cls: 'table-condensed',
19632 Roo.bootstrap.DateField.head,
19636 Roo.bootstrap.DateField.footer
19643 cls: 'datepicker-months',
19647 cls: 'table-condensed',
19649 Roo.bootstrap.DateField.head,
19650 Roo.bootstrap.DateField.content,
19651 Roo.bootstrap.DateField.footer
19658 cls: 'datepicker-years',
19662 cls: 'table-condensed',
19664 Roo.bootstrap.DateField.head,
19665 Roo.bootstrap.DateField.content,
19666 Roo.bootstrap.DateField.footer
19685 * @class Roo.bootstrap.TimeField
19686 * @extends Roo.bootstrap.Input
19687 * Bootstrap DateField class
19691 * Create a new TimeField
19692 * @param {Object} config The config object
19695 Roo.bootstrap.TimeField = function(config){
19696 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19700 * Fires when this field show.
19701 * @param {Roo.bootstrap.DateField} thisthis
19702 * @param {Mixed} date The date value
19707 * Fires when this field hide.
19708 * @param {Roo.bootstrap.DateField} this
19709 * @param {Mixed} date The date value
19714 * Fires when select a date.
19715 * @param {Roo.bootstrap.DateField} this
19716 * @param {Mixed} date The date value
19722 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19725 * @cfg {String} format
19726 * The default time format string which can be overriden for localization support. The format must be
19727 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19731 onRender: function(ct, position)
19734 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19736 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19738 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19740 this.pop = this.picker().select('>.datepicker-time',true).first();
19741 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19743 this.picker().on('mousedown', this.onMousedown, this);
19744 this.picker().on('click', this.onClick, this);
19746 this.picker().addClass('datepicker-dropdown');
19751 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19752 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19753 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19754 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19755 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19756 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19760 fireKey: function(e){
19761 if (!this.picker().isVisible()){
19762 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19768 e.preventDefault();
19776 this.onTogglePeriod();
19779 this.onIncrementMinutes();
19782 this.onDecrementMinutes();
19791 onClick: function(e) {
19792 e.stopPropagation();
19793 e.preventDefault();
19796 picker : function()
19798 return this.el.select('.datepicker', true).first();
19801 fillTime: function()
19803 var time = this.pop.select('tbody', true).first();
19805 time.dom.innerHTML = '';
19820 cls: 'hours-up glyphicon glyphicon-chevron-up'
19840 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19861 cls: 'timepicker-hour',
19876 cls: 'timepicker-minute',
19891 cls: 'btn btn-primary period',
19913 cls: 'hours-down glyphicon glyphicon-chevron-down'
19933 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19951 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19958 var hours = this.time.getHours();
19959 var minutes = this.time.getMinutes();
19972 hours = hours - 12;
19976 hours = '0' + hours;
19980 minutes = '0' + minutes;
19983 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19984 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19985 this.pop.select('button', true).first().dom.innerHTML = period;
19991 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19993 var cls = ['bottom'];
19995 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20002 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20007 this.picker().addClass(cls.join('-'));
20011 Roo.each(cls, function(c){
20013 _this.picker().setTop(_this.inputEl().getHeight());
20017 _this.picker().setTop(0 - _this.picker().getHeight());
20022 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20026 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20033 onFocus : function()
20035 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20039 onBlur : function()
20041 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20047 this.picker().show();
20052 this.fireEvent('show', this, this.date);
20057 this.picker().hide();
20060 this.fireEvent('hide', this, this.date);
20063 setTime : function()
20066 this.setValue(this.time.format(this.format));
20068 this.fireEvent('select', this, this.date);
20073 onMousedown: function(e){
20074 e.stopPropagation();
20075 e.preventDefault();
20078 onIncrementHours: function()
20080 Roo.log('onIncrementHours');
20081 this.time = this.time.add(Date.HOUR, 1);
20086 onDecrementHours: function()
20088 Roo.log('onDecrementHours');
20089 this.time = this.time.add(Date.HOUR, -1);
20093 onIncrementMinutes: function()
20095 Roo.log('onIncrementMinutes');
20096 this.time = this.time.add(Date.MINUTE, 1);
20100 onDecrementMinutes: function()
20102 Roo.log('onDecrementMinutes');
20103 this.time = this.time.add(Date.MINUTE, -1);
20107 onTogglePeriod: function()
20109 Roo.log('onTogglePeriod');
20110 this.time = this.time.add(Date.HOUR, 12);
20117 Roo.apply(Roo.bootstrap.TimeField, {
20147 cls: 'btn btn-info ok',
20159 Roo.apply(Roo.bootstrap.TimeField, {
20163 cls: 'datepicker dropdown-menu',
20167 cls: 'datepicker-time',
20171 cls: 'table-condensed',
20173 Roo.bootstrap.TimeField.content,
20174 Roo.bootstrap.TimeField.footer
20193 * @class Roo.bootstrap.MonthField
20194 * @extends Roo.bootstrap.Input
20195 * Bootstrap MonthField class
20197 * @cfg {String} language default en
20200 * Create a new MonthField
20201 * @param {Object} config The config object
20204 Roo.bootstrap.MonthField = function(config){
20205 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20210 * Fires when this field show.
20211 * @param {Roo.bootstrap.MonthField} this
20212 * @param {Mixed} date The date value
20217 * Fires when this field hide.
20218 * @param {Roo.bootstrap.MonthField} this
20219 * @param {Mixed} date The date value
20224 * Fires when select a date.
20225 * @param {Roo.bootstrap.MonthField} this
20226 * @param {String} oldvalue The old value
20227 * @param {String} newvalue The new value
20233 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20235 onRender: function(ct, position)
20238 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20240 this.language = this.language || 'en';
20241 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20242 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20244 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20245 this.isInline = false;
20246 this.isInput = true;
20247 this.component = this.el.select('.add-on', true).first() || false;
20248 this.component = (this.component && this.component.length === 0) ? false : this.component;
20249 this.hasInput = this.component && this.inputEL().length;
20251 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20253 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20255 this.picker().on('mousedown', this.onMousedown, this);
20256 this.picker().on('click', this.onClick, this);
20258 this.picker().addClass('datepicker-dropdown');
20260 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20261 v.setStyle('width', '189px');
20268 if(this.isInline) {
20274 setValue: function(v, suppressEvent)
20276 var o = this.getValue();
20278 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20282 if(suppressEvent !== true){
20283 this.fireEvent('select', this, o, v);
20288 getValue: function()
20293 onClick: function(e)
20295 e.stopPropagation();
20296 e.preventDefault();
20298 var target = e.getTarget();
20300 if(target.nodeName.toLowerCase() === 'i'){
20301 target = Roo.get(target).dom.parentNode;
20304 var nodeName = target.nodeName;
20305 var className = target.className;
20306 var html = target.innerHTML;
20308 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20312 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20314 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20320 picker : function()
20322 return this.pickerEl;
20325 fillMonths: function()
20328 var months = this.picker().select('>.datepicker-months td', true).first();
20330 months.dom.innerHTML = '';
20336 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20339 months.createChild(month);
20348 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20349 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20352 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20353 e.removeClass('active');
20355 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20356 e.addClass('active');
20363 if(this.isInline) {
20367 this.picker().removeClass(['bottom', 'top']);
20369 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20371 * place to the top of element!
20375 this.picker().addClass('top');
20376 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20381 this.picker().addClass('bottom');
20383 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20386 onFocus : function()
20388 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20392 onBlur : function()
20394 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20396 var d = this.inputEl().getValue();
20405 this.picker().show();
20406 this.picker().select('>.datepicker-months', true).first().show();
20410 this.fireEvent('show', this, this.date);
20415 if(this.isInline) {
20418 this.picker().hide();
20419 this.fireEvent('hide', this, this.date);
20423 onMousedown: function(e)
20425 e.stopPropagation();
20426 e.preventDefault();
20431 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20435 fireKey: function(e)
20437 if (!this.picker().isVisible()){
20438 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20449 e.preventDefault();
20453 dir = e.keyCode == 37 ? -1 : 1;
20455 this.vIndex = this.vIndex + dir;
20457 if(this.vIndex < 0){
20461 if(this.vIndex > 11){
20465 if(isNaN(this.vIndex)){
20469 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20475 dir = e.keyCode == 38 ? -1 : 1;
20477 this.vIndex = this.vIndex + dir * 4;
20479 if(this.vIndex < 0){
20483 if(this.vIndex > 11){
20487 if(isNaN(this.vIndex)){
20491 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20496 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20497 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20501 e.preventDefault();
20504 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20505 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20521 this.picker().remove();
20526 Roo.apply(Roo.bootstrap.MonthField, {
20545 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20546 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20551 Roo.apply(Roo.bootstrap.MonthField, {
20555 cls: 'datepicker dropdown-menu roo-dynamic',
20559 cls: 'datepicker-months',
20563 cls: 'table-condensed',
20565 Roo.bootstrap.DateField.content
20585 * @class Roo.bootstrap.CheckBox
20586 * @extends Roo.bootstrap.Input
20587 * Bootstrap CheckBox class
20589 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20590 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20591 * @cfg {String} boxLabel The text that appears beside the checkbox
20592 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20593 * @cfg {Boolean} checked initnal the element
20594 * @cfg {Boolean} inline inline the element (default false)
20595 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20596 * @cfg {String} tooltip label tooltip
20599 * Create a new CheckBox
20600 * @param {Object} config The config object
20603 Roo.bootstrap.CheckBox = function(config){
20604 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20609 * Fires when the element is checked or unchecked.
20610 * @param {Roo.bootstrap.CheckBox} this This input
20611 * @param {Boolean} checked The new checked value
20616 * Fires when the element is click.
20617 * @param {Roo.bootstrap.CheckBox} this This input
20624 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20626 inputType: 'checkbox',
20635 getAutoCreate : function()
20637 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20643 cfg.cls = 'form-group ' + this.inputType; //input-group
20646 cfg.cls += ' ' + this.inputType + '-inline';
20652 type : this.inputType,
20653 value : this.inputValue,
20654 cls : 'roo-' + this.inputType, //'form-box',
20655 placeholder : this.placeholder || ''
20659 if(this.inputType != 'radio'){
20663 cls : 'roo-hidden-value',
20664 value : this.checked ? this.inputValue : this.valueOff
20669 if (this.weight) { // Validity check?
20670 cfg.cls += " " + this.inputType + "-" + this.weight;
20673 if (this.disabled) {
20674 input.disabled=true;
20678 input.checked = this.checked;
20683 input.name = this.name;
20685 if(this.inputType != 'radio'){
20686 hidden.name = this.name;
20687 input.name = '_hidden_' + this.name;
20692 input.cls += ' input-' + this.size;
20697 ['xs','sm','md','lg'].map(function(size){
20698 if (settings[size]) {
20699 cfg.cls += ' col-' + size + '-' + settings[size];
20703 var inputblock = input;
20705 if (this.before || this.after) {
20708 cls : 'input-group',
20713 inputblock.cn.push({
20715 cls : 'input-group-addon',
20720 inputblock.cn.push(input);
20722 if(this.inputType != 'radio'){
20723 inputblock.cn.push(hidden);
20727 inputblock.cn.push({
20729 cls : 'input-group-addon',
20736 if (align ==='left' && this.fieldLabel.length) {
20737 // Roo.log("left and has label");
20742 cls : 'control-label',
20743 html : this.fieldLabel
20753 if(this.labelWidth > 12){
20754 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20757 if(this.labelWidth < 13 && this.labelmd == 0){
20758 this.labelmd = this.labelWidth;
20761 if(this.labellg > 0){
20762 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20763 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20766 if(this.labelmd > 0){
20767 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20768 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20771 if(this.labelsm > 0){
20772 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20773 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20776 if(this.labelxs > 0){
20777 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20778 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20781 } else if ( this.fieldLabel.length) {
20782 // Roo.log(" label");
20786 tag: this.boxLabel ? 'span' : 'label',
20788 cls: 'control-label box-input-label',
20789 //cls : 'input-group-addon',
20790 html : this.fieldLabel
20799 // Roo.log(" no label && no align");
20800 cfg.cn = [ inputblock ] ;
20806 var boxLabelCfg = {
20808 //'for': id, // box label is handled by onclick - so no for...
20810 html: this.boxLabel
20814 boxLabelCfg.tooltip = this.tooltip;
20817 cfg.cn.push(boxLabelCfg);
20820 if(this.inputType != 'radio'){
20821 cfg.cn.push(hidden);
20829 * return the real input element.
20831 inputEl: function ()
20833 return this.el.select('input.roo-' + this.inputType,true).first();
20835 hiddenEl: function ()
20837 return this.el.select('input.roo-hidden-value',true).first();
20840 labelEl: function()
20842 return this.el.select('label.control-label',true).first();
20844 /* depricated... */
20848 return this.labelEl();
20851 boxLabelEl: function()
20853 return this.el.select('label.box-label',true).first();
20856 initEvents : function()
20858 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20860 this.inputEl().on('click', this.onClick, this);
20862 if (this.boxLabel) {
20863 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20866 this.startValue = this.getValue();
20869 Roo.bootstrap.CheckBox.register(this);
20873 onClick : function(e)
20875 if(this.fireEvent('click', this, e) !== false){
20876 this.setChecked(!this.checked);
20881 setChecked : function(state,suppressEvent)
20883 this.startValue = this.getValue();
20885 if(this.inputType == 'radio'){
20887 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20888 e.dom.checked = false;
20891 this.inputEl().dom.checked = true;
20893 this.inputEl().dom.value = this.inputValue;
20895 if(suppressEvent !== true){
20896 this.fireEvent('check', this, true);
20904 this.checked = state;
20906 this.inputEl().dom.checked = state;
20909 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20911 if(suppressEvent !== true){
20912 this.fireEvent('check', this, state);
20918 getValue : function()
20920 if(this.inputType == 'radio'){
20921 return this.getGroupValue();
20924 return this.hiddenEl().dom.value;
20928 getGroupValue : function()
20930 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20934 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20937 setValue : function(v,suppressEvent)
20939 if(this.inputType == 'radio'){
20940 this.setGroupValue(v, suppressEvent);
20944 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20949 setGroupValue : function(v, suppressEvent)
20951 this.startValue = this.getValue();
20953 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20954 e.dom.checked = false;
20956 if(e.dom.value == v){
20957 e.dom.checked = true;
20961 if(suppressEvent !== true){
20962 this.fireEvent('check', this, true);
20970 validate : function()
20972 if(this.getVisibilityEl().hasClass('hidden')){
20978 (this.inputType == 'radio' && this.validateRadio()) ||
20979 (this.inputType == 'checkbox' && this.validateCheckbox())
20985 this.markInvalid();
20989 validateRadio : function()
20991 if(this.getVisibilityEl().hasClass('hidden')){
20995 if(this.allowBlank){
21001 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21002 if(!e.dom.checked){
21014 validateCheckbox : function()
21017 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21018 //return (this.getValue() == this.inputValue) ? true : false;
21021 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21029 for(var i in group){
21030 if(group[i].el.isVisible(true)){
21038 for(var i in group){
21043 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21050 * Mark this field as valid
21052 markValid : function()
21056 this.fireEvent('valid', this);
21058 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21061 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21068 if(this.inputType == 'radio'){
21069 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21070 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21071 e.findParent('.form-group', false, true).addClass(_this.validClass);
21078 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21079 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21083 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21089 for(var i in group){
21090 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21091 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21096 * Mark this field as invalid
21097 * @param {String} msg The validation message
21099 markInvalid : function(msg)
21101 if(this.allowBlank){
21107 this.fireEvent('invalid', this, msg);
21109 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21112 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21116 label.markInvalid();
21119 if(this.inputType == 'radio'){
21120 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21121 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21122 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21129 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21130 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21134 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21140 for(var i in group){
21141 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21142 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21147 clearInvalid : function()
21149 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21151 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21153 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21155 if (label && label.iconEl) {
21156 label.iconEl.removeClass(label.validClass);
21157 label.iconEl.removeClass(label.invalidClass);
21161 disable : function()
21163 if(this.inputType != 'radio'){
21164 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21171 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21172 _this.getActionEl().addClass(this.disabledClass);
21173 e.dom.disabled = true;
21177 this.disabled = true;
21178 this.fireEvent("disable", this);
21182 enable : function()
21184 if(this.inputType != 'radio'){
21185 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21192 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21193 _this.getActionEl().removeClass(this.disabledClass);
21194 e.dom.disabled = false;
21198 this.disabled = false;
21199 this.fireEvent("enable", this);
21203 setBoxLabel : function(v)
21208 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21214 Roo.apply(Roo.bootstrap.CheckBox, {
21219 * register a CheckBox Group
21220 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21222 register : function(checkbox)
21224 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21225 this.groups[checkbox.groupId] = {};
21228 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21232 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21236 * fetch a CheckBox Group based on the group ID
21237 * @param {string} the group ID
21238 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21240 get: function(groupId) {
21241 if (typeof(this.groups[groupId]) == 'undefined') {
21245 return this.groups[groupId] ;
21258 * @class Roo.bootstrap.Radio
21259 * @extends Roo.bootstrap.Component
21260 * Bootstrap Radio class
21261 * @cfg {String} boxLabel - the label associated
21262 * @cfg {String} value - the value of radio
21265 * Create a new Radio
21266 * @param {Object} config The config object
21268 Roo.bootstrap.Radio = function(config){
21269 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21273 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21279 getAutoCreate : function()
21283 cls : 'form-group radio',
21288 html : this.boxLabel
21296 initEvents : function()
21298 this.parent().register(this);
21300 this.el.on('click', this.onClick, this);
21304 onClick : function(e)
21306 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21307 this.setChecked(true);
21311 setChecked : function(state, suppressEvent)
21313 this.parent().setValue(this.value, suppressEvent);
21317 setBoxLabel : function(v)
21322 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21337 * @class Roo.bootstrap.SecurePass
21338 * @extends Roo.bootstrap.Input
21339 * Bootstrap SecurePass class
21343 * Create a new SecurePass
21344 * @param {Object} config The config object
21347 Roo.bootstrap.SecurePass = function (config) {
21348 // these go here, so the translation tool can replace them..
21350 PwdEmpty: "Please type a password, and then retype it to confirm.",
21351 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21352 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21353 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21354 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21355 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21356 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21357 TooWeak: "Your password is Too Weak."
21359 this.meterLabel = "Password strength:";
21360 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21361 this.meterClass = [
21362 "roo-password-meter-tooweak",
21363 "roo-password-meter-weak",
21364 "roo-password-meter-medium",
21365 "roo-password-meter-strong",
21366 "roo-password-meter-grey"
21371 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21374 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21376 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21378 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21379 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21380 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21381 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21382 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21383 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21384 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21394 * @cfg {String/Object} Label for the strength meter (defaults to
21395 * 'Password strength:')
21400 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21401 * ['Weak', 'Medium', 'Strong'])
21404 pwdStrengths: false,
21417 initEvents: function ()
21419 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21421 if (this.el.is('input[type=password]') && Roo.isSafari) {
21422 this.el.on('keydown', this.SafariOnKeyDown, this);
21425 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21428 onRender: function (ct, position)
21430 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21431 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21432 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21434 this.trigger.createChild({
21439 cls: 'roo-password-meter-grey col-xs-12',
21442 //width: this.meterWidth + 'px'
21446 cls: 'roo-password-meter-text'
21452 if (this.hideTrigger) {
21453 this.trigger.setDisplayed(false);
21455 this.setSize(this.width || '', this.height || '');
21458 onDestroy: function ()
21460 if (this.trigger) {
21461 this.trigger.removeAllListeners();
21462 this.trigger.remove();
21465 this.wrap.remove();
21467 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21470 checkStrength: function ()
21472 var pwd = this.inputEl().getValue();
21473 if (pwd == this._lastPwd) {
21478 if (this.ClientSideStrongPassword(pwd)) {
21480 } else if (this.ClientSideMediumPassword(pwd)) {
21482 } else if (this.ClientSideWeakPassword(pwd)) {
21488 Roo.log('strength1: ' + strength);
21490 //var pm = this.trigger.child('div/div/div').dom;
21491 var pm = this.trigger.child('div/div');
21492 pm.removeClass(this.meterClass);
21493 pm.addClass(this.meterClass[strength]);
21496 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21498 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21500 this._lastPwd = pwd;
21504 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21506 this._lastPwd = '';
21508 var pm = this.trigger.child('div/div');
21509 pm.removeClass(this.meterClass);
21510 pm.addClass('roo-password-meter-grey');
21513 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21516 this.inputEl().dom.type='password';
21519 validateValue: function (value)
21522 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21525 if (value.length == 0) {
21526 if (this.allowBlank) {
21527 this.clearInvalid();
21531 this.markInvalid(this.errors.PwdEmpty);
21532 this.errorMsg = this.errors.PwdEmpty;
21540 if ('[\x21-\x7e]*'.match(value)) {
21541 this.markInvalid(this.errors.PwdBadChar);
21542 this.errorMsg = this.errors.PwdBadChar;
21545 if (value.length < 6) {
21546 this.markInvalid(this.errors.PwdShort);
21547 this.errorMsg = this.errors.PwdShort;
21550 if (value.length > 16) {
21551 this.markInvalid(this.errors.PwdLong);
21552 this.errorMsg = this.errors.PwdLong;
21556 if (this.ClientSideStrongPassword(value)) {
21558 } else if (this.ClientSideMediumPassword(value)) {
21560 } else if (this.ClientSideWeakPassword(value)) {
21567 if (strength < 2) {
21568 //this.markInvalid(this.errors.TooWeak);
21569 this.errorMsg = this.errors.TooWeak;
21574 console.log('strength2: ' + strength);
21576 //var pm = this.trigger.child('div/div/div').dom;
21578 var pm = this.trigger.child('div/div');
21579 pm.removeClass(this.meterClass);
21580 pm.addClass(this.meterClass[strength]);
21582 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21584 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21586 this.errorMsg = '';
21590 CharacterSetChecks: function (type)
21593 this.fResult = false;
21596 isctype: function (character, type)
21599 case this.kCapitalLetter:
21600 if (character >= 'A' && character <= 'Z') {
21605 case this.kSmallLetter:
21606 if (character >= 'a' && character <= 'z') {
21612 if (character >= '0' && character <= '9') {
21617 case this.kPunctuation:
21618 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21629 IsLongEnough: function (pwd, size)
21631 return !(pwd == null || isNaN(size) || pwd.length < size);
21634 SpansEnoughCharacterSets: function (word, nb)
21636 if (!this.IsLongEnough(word, nb))
21641 var characterSetChecks = new Array(
21642 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21643 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21646 for (var index = 0; index < word.length; ++index) {
21647 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21648 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21649 characterSetChecks[nCharSet].fResult = true;
21656 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21657 if (characterSetChecks[nCharSet].fResult) {
21662 if (nCharSets < nb) {
21668 ClientSideStrongPassword: function (pwd)
21670 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21673 ClientSideMediumPassword: function (pwd)
21675 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21678 ClientSideWeakPassword: function (pwd)
21680 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21683 })//<script type="text/javascript">
21686 * Based Ext JS Library 1.1.1
21687 * Copyright(c) 2006-2007, Ext JS, LLC.
21693 * @class Roo.HtmlEditorCore
21694 * @extends Roo.Component
21695 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21697 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21700 Roo.HtmlEditorCore = function(config){
21703 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21708 * @event initialize
21709 * Fires when the editor is fully initialized (including the iframe)
21710 * @param {Roo.HtmlEditorCore} this
21715 * Fires when the editor is first receives the focus. Any insertion must wait
21716 * until after this event.
21717 * @param {Roo.HtmlEditorCore} this
21721 * @event beforesync
21722 * Fires before the textarea is updated with content from the editor iframe. Return false
21723 * to cancel the sync.
21724 * @param {Roo.HtmlEditorCore} this
21725 * @param {String} html
21729 * @event beforepush
21730 * Fires before the iframe editor is updated with content from the textarea. Return false
21731 * to cancel the push.
21732 * @param {Roo.HtmlEditorCore} this
21733 * @param {String} html
21738 * Fires when the textarea is updated with content from the editor iframe.
21739 * @param {Roo.HtmlEditorCore} this
21740 * @param {String} html
21745 * Fires when the iframe editor is updated with content from the textarea.
21746 * @param {Roo.HtmlEditorCore} this
21747 * @param {String} html
21752 * @event editorevent
21753 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21754 * @param {Roo.HtmlEditorCore} this
21760 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21762 // defaults : white / black...
21763 this.applyBlacklists();
21770 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21774 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21780 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21785 * @cfg {Number} height (in pixels)
21789 * @cfg {Number} width (in pixels)
21794 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21797 stylesheets: false,
21802 // private properties
21803 validationEvent : false,
21805 initialized : false,
21807 sourceEditMode : false,
21808 onFocus : Roo.emptyFn,
21810 hideMode:'offsets',
21814 // blacklist + whitelisted elements..
21821 * Protected method that will not generally be called directly. It
21822 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21823 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21825 getDocMarkup : function(){
21829 // inherit styels from page...??
21830 if (this.stylesheets === false) {
21832 Roo.get(document.head).select('style').each(function(node) {
21833 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21836 Roo.get(document.head).select('link').each(function(node) {
21837 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21840 } else if (!this.stylesheets.length) {
21842 st = '<style type="text/css">' +
21843 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21846 st = '<style type="text/css">' +
21851 st += '<style type="text/css">' +
21852 'IMG { cursor: pointer } ' +
21855 var cls = 'roo-htmleditor-body';
21857 if(this.bodyCls.length){
21858 cls += ' ' + this.bodyCls;
21861 return '<html><head>' + st +
21862 //<style type="text/css">' +
21863 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21865 ' </head><body class="' + cls + '"></body></html>';
21869 onRender : function(ct, position)
21872 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21873 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21876 this.el.dom.style.border = '0 none';
21877 this.el.dom.setAttribute('tabIndex', -1);
21878 this.el.addClass('x-hidden hide');
21882 if(Roo.isIE){ // fix IE 1px bogus margin
21883 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21887 this.frameId = Roo.id();
21891 var iframe = this.owner.wrap.createChild({
21893 cls: 'form-control', // bootstrap..
21895 name: this.frameId,
21896 frameBorder : 'no',
21897 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21902 this.iframe = iframe.dom;
21904 this.assignDocWin();
21906 this.doc.designMode = 'on';
21909 this.doc.write(this.getDocMarkup());
21913 var task = { // must defer to wait for browser to be ready
21915 //console.log("run task?" + this.doc.readyState);
21916 this.assignDocWin();
21917 if(this.doc.body || this.doc.readyState == 'complete'){
21919 this.doc.designMode="on";
21923 Roo.TaskMgr.stop(task);
21924 this.initEditor.defer(10, this);
21931 Roo.TaskMgr.start(task);
21936 onResize : function(w, h)
21938 Roo.log('resize: ' +w + ',' + h );
21939 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21943 if(typeof w == 'number'){
21945 this.iframe.style.width = w + 'px';
21947 if(typeof h == 'number'){
21949 this.iframe.style.height = h + 'px';
21951 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21958 * Toggles the editor between standard and source edit mode.
21959 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21961 toggleSourceEdit : function(sourceEditMode){
21963 this.sourceEditMode = sourceEditMode === true;
21965 if(this.sourceEditMode){
21967 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21970 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21971 //this.iframe.className = '';
21974 //this.setSize(this.owner.wrap.getSize());
21975 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21982 * Protected method that will not generally be called directly. If you need/want
21983 * custom HTML cleanup, this is the method you should override.
21984 * @param {String} html The HTML to be cleaned
21985 * return {String} The cleaned HTML
21987 cleanHtml : function(html){
21988 html = String(html);
21989 if(html.length > 5){
21990 if(Roo.isSafari){ // strip safari nonsense
21991 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21994 if(html == ' '){
22001 * HTML Editor -> Textarea
22002 * Protected method that will not generally be called directly. Syncs the contents
22003 * of the editor iframe with the textarea.
22005 syncValue : function(){
22006 if(this.initialized){
22007 var bd = (this.doc.body || this.doc.documentElement);
22008 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22009 var html = bd.innerHTML;
22011 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22012 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22014 html = '<div style="'+m[0]+'">' + html + '</div>';
22017 html = this.cleanHtml(html);
22018 // fix up the special chars.. normaly like back quotes in word...
22019 // however we do not want to do this with chinese..
22020 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22021 var cc = b.charCodeAt();
22023 (cc >= 0x4E00 && cc < 0xA000 ) ||
22024 (cc >= 0x3400 && cc < 0x4E00 ) ||
22025 (cc >= 0xf900 && cc < 0xfb00 )
22031 if(this.owner.fireEvent('beforesync', this, html) !== false){
22032 this.el.dom.value = html;
22033 this.owner.fireEvent('sync', this, html);
22039 * Protected method that will not generally be called directly. Pushes the value of the textarea
22040 * into the iframe editor.
22042 pushValue : function(){
22043 if(this.initialized){
22044 var v = this.el.dom.value.trim();
22046 // if(v.length < 1){
22050 if(this.owner.fireEvent('beforepush', this, v) !== false){
22051 var d = (this.doc.body || this.doc.documentElement);
22053 this.cleanUpPaste();
22054 this.el.dom.value = d.innerHTML;
22055 this.owner.fireEvent('push', this, v);
22061 deferFocus : function(){
22062 this.focus.defer(10, this);
22066 focus : function(){
22067 if(this.win && !this.sourceEditMode){
22074 assignDocWin: function()
22076 var iframe = this.iframe;
22079 this.doc = iframe.contentWindow.document;
22080 this.win = iframe.contentWindow;
22082 // if (!Roo.get(this.frameId)) {
22085 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22086 // this.win = Roo.get(this.frameId).dom.contentWindow;
22088 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22092 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22093 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22098 initEditor : function(){
22099 //console.log("INIT EDITOR");
22100 this.assignDocWin();
22104 this.doc.designMode="on";
22106 this.doc.write(this.getDocMarkup());
22109 var dbody = (this.doc.body || this.doc.documentElement);
22110 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22111 // this copies styles from the containing element into thsi one..
22112 // not sure why we need all of this..
22113 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22115 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22116 //ss['background-attachment'] = 'fixed'; // w3c
22117 dbody.bgProperties = 'fixed'; // ie
22118 //Roo.DomHelper.applyStyles(dbody, ss);
22119 Roo.EventManager.on(this.doc, {
22120 //'mousedown': this.onEditorEvent,
22121 'mouseup': this.onEditorEvent,
22122 'dblclick': this.onEditorEvent,
22123 'click': this.onEditorEvent,
22124 'keyup': this.onEditorEvent,
22129 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22131 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22132 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22134 this.initialized = true;
22136 this.owner.fireEvent('initialize', this);
22141 onDestroy : function(){
22147 //for (var i =0; i < this.toolbars.length;i++) {
22148 // // fixme - ask toolbars for heights?
22149 // this.toolbars[i].onDestroy();
22152 //this.wrap.dom.innerHTML = '';
22153 //this.wrap.remove();
22158 onFirstFocus : function(){
22160 this.assignDocWin();
22163 this.activated = true;
22166 if(Roo.isGecko){ // prevent silly gecko errors
22168 var s = this.win.getSelection();
22169 if(!s.focusNode || s.focusNode.nodeType != 3){
22170 var r = s.getRangeAt(0);
22171 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22176 this.execCmd('useCSS', true);
22177 this.execCmd('styleWithCSS', false);
22180 this.owner.fireEvent('activate', this);
22184 adjustFont: function(btn){
22185 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22186 //if(Roo.isSafari){ // safari
22189 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22190 if(Roo.isSafari){ // safari
22191 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22192 v = (v < 10) ? 10 : v;
22193 v = (v > 48) ? 48 : v;
22194 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22199 v = Math.max(1, v+adjust);
22201 this.execCmd('FontSize', v );
22204 onEditorEvent : function(e)
22206 this.owner.fireEvent('editorevent', this, e);
22207 // this.updateToolbar();
22208 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22211 insertTag : function(tg)
22213 // could be a bit smarter... -> wrap the current selected tRoo..
22214 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22216 range = this.createRange(this.getSelection());
22217 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22218 wrappingNode.appendChild(range.extractContents());
22219 range.insertNode(wrappingNode);
22226 this.execCmd("formatblock", tg);
22230 insertText : function(txt)
22234 var range = this.createRange();
22235 range.deleteContents();
22236 //alert(Sender.getAttribute('label'));
22238 range.insertNode(this.doc.createTextNode(txt));
22244 * Executes a Midas editor command on the editor document and performs necessary focus and
22245 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22246 * @param {String} cmd The Midas command
22247 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22249 relayCmd : function(cmd, value){
22251 this.execCmd(cmd, value);
22252 this.owner.fireEvent('editorevent', this);
22253 //this.updateToolbar();
22254 this.owner.deferFocus();
22258 * Executes a Midas editor command directly on the editor document.
22259 * For visual commands, you should use {@link #relayCmd} instead.
22260 * <b>This should only be called after the editor is initialized.</b>
22261 * @param {String} cmd The Midas command
22262 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22264 execCmd : function(cmd, value){
22265 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22272 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22274 * @param {String} text | dom node..
22276 insertAtCursor : function(text)
22279 if(!this.activated){
22285 var r = this.doc.selection.createRange();
22296 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22300 // from jquery ui (MIT licenced)
22302 var win = this.win;
22304 if (win.getSelection && win.getSelection().getRangeAt) {
22305 range = win.getSelection().getRangeAt(0);
22306 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22307 range.insertNode(node);
22308 } else if (win.document.selection && win.document.selection.createRange) {
22309 // no firefox support
22310 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22311 win.document.selection.createRange().pasteHTML(txt);
22313 // no firefox support
22314 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22315 this.execCmd('InsertHTML', txt);
22324 mozKeyPress : function(e){
22326 var c = e.getCharCode(), cmd;
22329 c = String.fromCharCode(c).toLowerCase();
22343 this.cleanUpPaste.defer(100, this);
22351 e.preventDefault();
22359 fixKeys : function(){ // load time branching for fastest keydown performance
22361 return function(e){
22362 var k = e.getKey(), r;
22365 r = this.doc.selection.createRange();
22368 r.pasteHTML('    ');
22375 r = this.doc.selection.createRange();
22377 var target = r.parentElement();
22378 if(!target || target.tagName.toLowerCase() != 'li'){
22380 r.pasteHTML('<br />');
22386 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22387 this.cleanUpPaste.defer(100, this);
22393 }else if(Roo.isOpera){
22394 return function(e){
22395 var k = e.getKey();
22399 this.execCmd('InsertHTML','    ');
22402 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22403 this.cleanUpPaste.defer(100, this);
22408 }else if(Roo.isSafari){
22409 return function(e){
22410 var k = e.getKey();
22414 this.execCmd('InsertText','\t');
22418 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22419 this.cleanUpPaste.defer(100, this);
22427 getAllAncestors: function()
22429 var p = this.getSelectedNode();
22432 a.push(p); // push blank onto stack..
22433 p = this.getParentElement();
22437 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22441 a.push(this.doc.body);
22445 lastSelNode : false,
22448 getSelection : function()
22450 this.assignDocWin();
22451 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22454 getSelectedNode: function()
22456 // this may only work on Gecko!!!
22458 // should we cache this!!!!
22463 var range = this.createRange(this.getSelection()).cloneRange();
22466 var parent = range.parentElement();
22468 var testRange = range.duplicate();
22469 testRange.moveToElementText(parent);
22470 if (testRange.inRange(range)) {
22473 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22476 parent = parent.parentElement;
22481 // is ancestor a text element.
22482 var ac = range.commonAncestorContainer;
22483 if (ac.nodeType == 3) {
22484 ac = ac.parentNode;
22487 var ar = ac.childNodes;
22490 var other_nodes = [];
22491 var has_other_nodes = false;
22492 for (var i=0;i<ar.length;i++) {
22493 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22496 // fullly contained node.
22498 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22503 // probably selected..
22504 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22505 other_nodes.push(ar[i]);
22509 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22514 has_other_nodes = true;
22516 if (!nodes.length && other_nodes.length) {
22517 nodes= other_nodes;
22519 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22525 createRange: function(sel)
22527 // this has strange effects when using with
22528 // top toolbar - not sure if it's a great idea.
22529 //this.editor.contentWindow.focus();
22530 if (typeof sel != "undefined") {
22532 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22534 return this.doc.createRange();
22537 return this.doc.createRange();
22540 getParentElement: function()
22543 this.assignDocWin();
22544 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22546 var range = this.createRange(sel);
22549 var p = range.commonAncestorContainer;
22550 while (p.nodeType == 3) { // text node
22561 * Range intersection.. the hard stuff...
22565 * [ -- selected range --- ]
22569 * if end is before start or hits it. fail.
22570 * if start is after end or hits it fail.
22572 * if either hits (but other is outside. - then it's not
22578 // @see http://www.thismuchiknow.co.uk/?p=64.
22579 rangeIntersectsNode : function(range, node)
22581 var nodeRange = node.ownerDocument.createRange();
22583 nodeRange.selectNode(node);
22585 nodeRange.selectNodeContents(node);
22588 var rangeStartRange = range.cloneRange();
22589 rangeStartRange.collapse(true);
22591 var rangeEndRange = range.cloneRange();
22592 rangeEndRange.collapse(false);
22594 var nodeStartRange = nodeRange.cloneRange();
22595 nodeStartRange.collapse(true);
22597 var nodeEndRange = nodeRange.cloneRange();
22598 nodeEndRange.collapse(false);
22600 return rangeStartRange.compareBoundaryPoints(
22601 Range.START_TO_START, nodeEndRange) == -1 &&
22602 rangeEndRange.compareBoundaryPoints(
22603 Range.START_TO_START, nodeStartRange) == 1;
22607 rangeCompareNode : function(range, node)
22609 var nodeRange = node.ownerDocument.createRange();
22611 nodeRange.selectNode(node);
22613 nodeRange.selectNodeContents(node);
22617 range.collapse(true);
22619 nodeRange.collapse(true);
22621 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22622 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22624 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22626 var nodeIsBefore = ss == 1;
22627 var nodeIsAfter = ee == -1;
22629 if (nodeIsBefore && nodeIsAfter) {
22632 if (!nodeIsBefore && nodeIsAfter) {
22633 return 1; //right trailed.
22636 if (nodeIsBefore && !nodeIsAfter) {
22637 return 2; // left trailed.
22643 // private? - in a new class?
22644 cleanUpPaste : function()
22646 // cleans up the whole document..
22647 Roo.log('cleanuppaste');
22649 this.cleanUpChildren(this.doc.body);
22650 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22651 if (clean != this.doc.body.innerHTML) {
22652 this.doc.body.innerHTML = clean;
22657 cleanWordChars : function(input) {// change the chars to hex code
22658 var he = Roo.HtmlEditorCore;
22660 var output = input;
22661 Roo.each(he.swapCodes, function(sw) {
22662 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22664 output = output.replace(swapper, sw[1]);
22671 cleanUpChildren : function (n)
22673 if (!n.childNodes.length) {
22676 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22677 this.cleanUpChild(n.childNodes[i]);
22684 cleanUpChild : function (node)
22687 //console.log(node);
22688 if (node.nodeName == "#text") {
22689 // clean up silly Windows -- stuff?
22692 if (node.nodeName == "#comment") {
22693 node.parentNode.removeChild(node);
22694 // clean up silly Windows -- stuff?
22697 var lcname = node.tagName.toLowerCase();
22698 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22699 // whitelist of tags..
22701 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22703 node.parentNode.removeChild(node);
22708 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22710 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22711 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22713 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22714 // remove_keep_children = true;
22717 if (remove_keep_children) {
22718 this.cleanUpChildren(node);
22719 // inserts everything just before this node...
22720 while (node.childNodes.length) {
22721 var cn = node.childNodes[0];
22722 node.removeChild(cn);
22723 node.parentNode.insertBefore(cn, node);
22725 node.parentNode.removeChild(node);
22729 if (!node.attributes || !node.attributes.length) {
22730 this.cleanUpChildren(node);
22734 function cleanAttr(n,v)
22737 if (v.match(/^\./) || v.match(/^\//)) {
22740 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22743 if (v.match(/^#/)) {
22746 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22747 node.removeAttribute(n);
22751 var cwhite = this.cwhite;
22752 var cblack = this.cblack;
22754 function cleanStyle(n,v)
22756 if (v.match(/expression/)) { //XSS?? should we even bother..
22757 node.removeAttribute(n);
22761 var parts = v.split(/;/);
22764 Roo.each(parts, function(p) {
22765 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22769 var l = p.split(':').shift().replace(/\s+/g,'');
22770 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22772 if ( cwhite.length && cblack.indexOf(l) > -1) {
22773 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22774 //node.removeAttribute(n);
22778 // only allow 'c whitelisted system attributes'
22779 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22780 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22781 //node.removeAttribute(n);
22791 if (clean.length) {
22792 node.setAttribute(n, clean.join(';'));
22794 node.removeAttribute(n);
22800 for (var i = node.attributes.length-1; i > -1 ; i--) {
22801 var a = node.attributes[i];
22804 if (a.name.toLowerCase().substr(0,2)=='on') {
22805 node.removeAttribute(a.name);
22808 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22809 node.removeAttribute(a.name);
22812 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22813 cleanAttr(a.name,a.value); // fixme..
22816 if (a.name == 'style') {
22817 cleanStyle(a.name,a.value);
22820 /// clean up MS crap..
22821 // tecnically this should be a list of valid class'es..
22824 if (a.name == 'class') {
22825 if (a.value.match(/^Mso/)) {
22826 node.className = '';
22829 if (a.value.match(/^body$/)) {
22830 node.className = '';
22841 this.cleanUpChildren(node);
22847 * Clean up MS wordisms...
22849 cleanWord : function(node)
22854 this.cleanWord(this.doc.body);
22857 if (node.nodeName == "#text") {
22858 // clean up silly Windows -- stuff?
22861 if (node.nodeName == "#comment") {
22862 node.parentNode.removeChild(node);
22863 // clean up silly Windows -- stuff?
22867 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22868 node.parentNode.removeChild(node);
22872 // remove - but keep children..
22873 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22874 while (node.childNodes.length) {
22875 var cn = node.childNodes[0];
22876 node.removeChild(cn);
22877 node.parentNode.insertBefore(cn, node);
22879 node.parentNode.removeChild(node);
22880 this.iterateChildren(node, this.cleanWord);
22884 if (node.className.length) {
22886 var cn = node.className.split(/\W+/);
22888 Roo.each(cn, function(cls) {
22889 if (cls.match(/Mso[a-zA-Z]+/)) {
22894 node.className = cna.length ? cna.join(' ') : '';
22896 node.removeAttribute("class");
22900 if (node.hasAttribute("lang")) {
22901 node.removeAttribute("lang");
22904 if (node.hasAttribute("style")) {
22906 var styles = node.getAttribute("style").split(";");
22908 Roo.each(styles, function(s) {
22909 if (!s.match(/:/)) {
22912 var kv = s.split(":");
22913 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22916 // what ever is left... we allow.
22919 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22920 if (!nstyle.length) {
22921 node.removeAttribute('style');
22924 this.iterateChildren(node, this.cleanWord);
22930 * iterateChildren of a Node, calling fn each time, using this as the scole..
22931 * @param {DomNode} node node to iterate children of.
22932 * @param {Function} fn method of this class to call on each item.
22934 iterateChildren : function(node, fn)
22936 if (!node.childNodes.length) {
22939 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22940 fn.call(this, node.childNodes[i])
22946 * cleanTableWidths.
22948 * Quite often pasting from word etc.. results in tables with column and widths.
22949 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22952 cleanTableWidths : function(node)
22957 this.cleanTableWidths(this.doc.body);
22962 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22965 Roo.log(node.tagName);
22966 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22967 this.iterateChildren(node, this.cleanTableWidths);
22970 if (node.hasAttribute('width')) {
22971 node.removeAttribute('width');
22975 if (node.hasAttribute("style")) {
22978 var styles = node.getAttribute("style").split(";");
22980 Roo.each(styles, function(s) {
22981 if (!s.match(/:/)) {
22984 var kv = s.split(":");
22985 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22988 // what ever is left... we allow.
22991 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22992 if (!nstyle.length) {
22993 node.removeAttribute('style');
22997 this.iterateChildren(node, this.cleanTableWidths);
23005 domToHTML : function(currentElement, depth, nopadtext) {
23007 depth = depth || 0;
23008 nopadtext = nopadtext || false;
23010 if (!currentElement) {
23011 return this.domToHTML(this.doc.body);
23014 //Roo.log(currentElement);
23016 var allText = false;
23017 var nodeName = currentElement.nodeName;
23018 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23020 if (nodeName == '#text') {
23022 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23027 if (nodeName != 'BODY') {
23030 // Prints the node tagName, such as <A>, <IMG>, etc
23033 for(i = 0; i < currentElement.attributes.length;i++) {
23035 var aname = currentElement.attributes.item(i).name;
23036 if (!currentElement.attributes.item(i).value.length) {
23039 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23042 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23051 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23054 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23059 // Traverse the tree
23061 var currentElementChild = currentElement.childNodes.item(i);
23062 var allText = true;
23063 var innerHTML = '';
23065 while (currentElementChild) {
23066 // Formatting code (indent the tree so it looks nice on the screen)
23067 var nopad = nopadtext;
23068 if (lastnode == 'SPAN') {
23072 if (currentElementChild.nodeName == '#text') {
23073 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23074 toadd = nopadtext ? toadd : toadd.trim();
23075 if (!nopad && toadd.length > 80) {
23076 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23078 innerHTML += toadd;
23081 currentElementChild = currentElement.childNodes.item(i);
23087 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23089 // Recursively traverse the tree structure of the child node
23090 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23091 lastnode = currentElementChild.nodeName;
23093 currentElementChild=currentElement.childNodes.item(i);
23099 // The remaining code is mostly for formatting the tree
23100 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23105 ret+= "</"+tagName+">";
23111 applyBlacklists : function()
23113 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23114 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23118 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23119 if (b.indexOf(tag) > -1) {
23122 this.white.push(tag);
23126 Roo.each(w, function(tag) {
23127 if (b.indexOf(tag) > -1) {
23130 if (this.white.indexOf(tag) > -1) {
23133 this.white.push(tag);
23138 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23139 if (w.indexOf(tag) > -1) {
23142 this.black.push(tag);
23146 Roo.each(b, function(tag) {
23147 if (w.indexOf(tag) > -1) {
23150 if (this.black.indexOf(tag) > -1) {
23153 this.black.push(tag);
23158 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23159 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23163 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23164 if (b.indexOf(tag) > -1) {
23167 this.cwhite.push(tag);
23171 Roo.each(w, function(tag) {
23172 if (b.indexOf(tag) > -1) {
23175 if (this.cwhite.indexOf(tag) > -1) {
23178 this.cwhite.push(tag);
23183 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23184 if (w.indexOf(tag) > -1) {
23187 this.cblack.push(tag);
23191 Roo.each(b, function(tag) {
23192 if (w.indexOf(tag) > -1) {
23195 if (this.cblack.indexOf(tag) > -1) {
23198 this.cblack.push(tag);
23203 setStylesheets : function(stylesheets)
23205 if(typeof(stylesheets) == 'string'){
23206 Roo.get(this.iframe.contentDocument.head).createChild({
23208 rel : 'stylesheet',
23217 Roo.each(stylesheets, function(s) {
23222 Roo.get(_this.iframe.contentDocument.head).createChild({
23224 rel : 'stylesheet',
23233 removeStylesheets : function()
23237 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23242 setStyle : function(style)
23244 Roo.get(this.iframe.contentDocument.head).createChild({
23253 // hide stuff that is not compatible
23267 * @event specialkey
23271 * @cfg {String} fieldClass @hide
23274 * @cfg {String} focusClass @hide
23277 * @cfg {String} autoCreate @hide
23280 * @cfg {String} inputType @hide
23283 * @cfg {String} invalidClass @hide
23286 * @cfg {String} invalidText @hide
23289 * @cfg {String} msgFx @hide
23292 * @cfg {String} validateOnBlur @hide
23296 Roo.HtmlEditorCore.white = [
23297 'area', 'br', 'img', 'input', 'hr', 'wbr',
23299 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23300 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23301 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23302 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23303 'table', 'ul', 'xmp',
23305 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23308 'dir', 'menu', 'ol', 'ul', 'dl',
23314 Roo.HtmlEditorCore.black = [
23315 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23317 'base', 'basefont', 'bgsound', 'blink', 'body',
23318 'frame', 'frameset', 'head', 'html', 'ilayer',
23319 'iframe', 'layer', 'link', 'meta', 'object',
23320 'script', 'style' ,'title', 'xml' // clean later..
23322 Roo.HtmlEditorCore.clean = [
23323 'script', 'style', 'title', 'xml'
23325 Roo.HtmlEditorCore.remove = [
23330 Roo.HtmlEditorCore.ablack = [
23334 Roo.HtmlEditorCore.aclean = [
23335 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23339 Roo.HtmlEditorCore.pwhite= [
23340 'http', 'https', 'mailto'
23343 // white listed style attributes.
23344 Roo.HtmlEditorCore.cwhite= [
23345 // 'text-align', /// default is to allow most things..
23351 // black listed style attributes.
23352 Roo.HtmlEditorCore.cblack= [
23353 // 'font-size' -- this can be set by the project
23357 Roo.HtmlEditorCore.swapCodes =[
23376 * @class Roo.bootstrap.HtmlEditor
23377 * @extends Roo.bootstrap.TextArea
23378 * Bootstrap HtmlEditor class
23381 * Create a new HtmlEditor
23382 * @param {Object} config The config object
23385 Roo.bootstrap.HtmlEditor = function(config){
23386 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23387 if (!this.toolbars) {
23388 this.toolbars = [];
23391 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23394 * @event initialize
23395 * Fires when the editor is fully initialized (including the iframe)
23396 * @param {HtmlEditor} this
23401 * Fires when the editor is first receives the focus. Any insertion must wait
23402 * until after this event.
23403 * @param {HtmlEditor} this
23407 * @event beforesync
23408 * Fires before the textarea is updated with content from the editor iframe. Return false
23409 * to cancel the sync.
23410 * @param {HtmlEditor} this
23411 * @param {String} html
23415 * @event beforepush
23416 * Fires before the iframe editor is updated with content from the textarea. Return false
23417 * to cancel the push.
23418 * @param {HtmlEditor} this
23419 * @param {String} html
23424 * Fires when the textarea is updated with content from the editor iframe.
23425 * @param {HtmlEditor} this
23426 * @param {String} html
23431 * Fires when the iframe editor is updated with content from the textarea.
23432 * @param {HtmlEditor} this
23433 * @param {String} html
23437 * @event editmodechange
23438 * Fires when the editor switches edit modes
23439 * @param {HtmlEditor} this
23440 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23442 editmodechange: true,
23444 * @event editorevent
23445 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23446 * @param {HtmlEditor} this
23450 * @event firstfocus
23451 * Fires when on first focus - needed by toolbars..
23452 * @param {HtmlEditor} this
23457 * Auto save the htmlEditor value as a file into Events
23458 * @param {HtmlEditor} this
23462 * @event savedpreview
23463 * preview the saved version of htmlEditor
23464 * @param {HtmlEditor} this
23471 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23475 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23480 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23485 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23490 * @cfg {Number} height (in pixels)
23494 * @cfg {Number} width (in pixels)
23499 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23502 stylesheets: false,
23507 // private properties
23508 validationEvent : false,
23510 initialized : false,
23513 onFocus : Roo.emptyFn,
23515 hideMode:'offsets',
23517 tbContainer : false,
23521 toolbarContainer :function() {
23522 return this.wrap.select('.x-html-editor-tb',true).first();
23526 * Protected method that will not generally be called directly. It
23527 * is called when the editor creates its toolbar. Override this method if you need to
23528 * add custom toolbar buttons.
23529 * @param {HtmlEditor} editor
23531 createToolbar : function(){
23532 Roo.log('renewing');
23533 Roo.log("create toolbars");
23535 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23536 this.toolbars[0].render(this.toolbarContainer());
23540 // if (!editor.toolbars || !editor.toolbars.length) {
23541 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23544 // for (var i =0 ; i < editor.toolbars.length;i++) {
23545 // editor.toolbars[i] = Roo.factory(
23546 // typeof(editor.toolbars[i]) == 'string' ?
23547 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23548 // Roo.bootstrap.HtmlEditor);
23549 // editor.toolbars[i].init(editor);
23555 onRender : function(ct, position)
23557 // Roo.log("Call onRender: " + this.xtype);
23559 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23561 this.wrap = this.inputEl().wrap({
23562 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23565 this.editorcore.onRender(ct, position);
23567 if (this.resizable) {
23568 this.resizeEl = new Roo.Resizable(this.wrap, {
23572 minHeight : this.height,
23573 height: this.height,
23574 handles : this.resizable,
23577 resize : function(r, w, h) {
23578 _t.onResize(w,h); // -something
23584 this.createToolbar(this);
23587 if(!this.width && this.resizable){
23588 this.setSize(this.wrap.getSize());
23590 if (this.resizeEl) {
23591 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23592 // should trigger onReize..
23598 onResize : function(w, h)
23600 Roo.log('resize: ' +w + ',' + h );
23601 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23605 if(this.inputEl() ){
23606 if(typeof w == 'number'){
23607 var aw = w - this.wrap.getFrameWidth('lr');
23608 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23611 if(typeof h == 'number'){
23612 var tbh = -11; // fixme it needs to tool bar size!
23613 for (var i =0; i < this.toolbars.length;i++) {
23614 // fixme - ask toolbars for heights?
23615 tbh += this.toolbars[i].el.getHeight();
23616 //if (this.toolbars[i].footer) {
23617 // tbh += this.toolbars[i].footer.el.getHeight();
23625 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23626 ah -= 5; // knock a few pixes off for look..
23627 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23631 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23632 this.editorcore.onResize(ew,eh);
23637 * Toggles the editor between standard and source edit mode.
23638 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23640 toggleSourceEdit : function(sourceEditMode)
23642 this.editorcore.toggleSourceEdit(sourceEditMode);
23644 if(this.editorcore.sourceEditMode){
23645 Roo.log('editor - showing textarea');
23648 // Roo.log(this.syncValue());
23650 this.inputEl().removeClass(['hide', 'x-hidden']);
23651 this.inputEl().dom.removeAttribute('tabIndex');
23652 this.inputEl().focus();
23654 Roo.log('editor - hiding textarea');
23656 // Roo.log(this.pushValue());
23659 this.inputEl().addClass(['hide', 'x-hidden']);
23660 this.inputEl().dom.setAttribute('tabIndex', -1);
23661 //this.deferFocus();
23664 if(this.resizable){
23665 this.setSize(this.wrap.getSize());
23668 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23671 // private (for BoxComponent)
23672 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23674 // private (for BoxComponent)
23675 getResizeEl : function(){
23679 // private (for BoxComponent)
23680 getPositionEl : function(){
23685 initEvents : function(){
23686 this.originalValue = this.getValue();
23690 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23693 // markInvalid : Roo.emptyFn,
23695 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23698 // clearInvalid : Roo.emptyFn,
23700 setValue : function(v){
23701 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23702 this.editorcore.pushValue();
23707 deferFocus : function(){
23708 this.focus.defer(10, this);
23712 focus : function(){
23713 this.editorcore.focus();
23719 onDestroy : function(){
23725 for (var i =0; i < this.toolbars.length;i++) {
23726 // fixme - ask toolbars for heights?
23727 this.toolbars[i].onDestroy();
23730 this.wrap.dom.innerHTML = '';
23731 this.wrap.remove();
23736 onFirstFocus : function(){
23737 //Roo.log("onFirstFocus");
23738 this.editorcore.onFirstFocus();
23739 for (var i =0; i < this.toolbars.length;i++) {
23740 this.toolbars[i].onFirstFocus();
23746 syncValue : function()
23748 this.editorcore.syncValue();
23751 pushValue : function()
23753 this.editorcore.pushValue();
23757 // hide stuff that is not compatible
23771 * @event specialkey
23775 * @cfg {String} fieldClass @hide
23778 * @cfg {String} focusClass @hide
23781 * @cfg {String} autoCreate @hide
23784 * @cfg {String} inputType @hide
23787 * @cfg {String} invalidClass @hide
23790 * @cfg {String} invalidText @hide
23793 * @cfg {String} msgFx @hide
23796 * @cfg {String} validateOnBlur @hide
23805 Roo.namespace('Roo.bootstrap.htmleditor');
23807 * @class Roo.bootstrap.HtmlEditorToolbar1
23812 new Roo.bootstrap.HtmlEditor({
23815 new Roo.bootstrap.HtmlEditorToolbar1({
23816 disable : { fonts: 1 , format: 1, ..., ... , ...],
23822 * @cfg {Object} disable List of elements to disable..
23823 * @cfg {Array} btns List of additional buttons.
23827 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23830 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23833 Roo.apply(this, config);
23835 // default disabled, based on 'good practice'..
23836 this.disable = this.disable || {};
23837 Roo.applyIf(this.disable, {
23840 specialElements : true
23842 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23844 this.editor = config.editor;
23845 this.editorcore = config.editor.editorcore;
23847 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23849 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23850 // dont call parent... till later.
23852 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23857 editorcore : false,
23862 "h1","h2","h3","h4","h5","h6",
23864 "abbr", "acronym", "address", "cite", "samp", "var",
23868 onRender : function(ct, position)
23870 // Roo.log("Call onRender: " + this.xtype);
23872 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23874 this.el.dom.style.marginBottom = '0';
23876 var editorcore = this.editorcore;
23877 var editor= this.editor;
23880 var btn = function(id,cmd , toggle, handler, html){
23882 var event = toggle ? 'toggle' : 'click';
23887 xns: Roo.bootstrap,
23890 enableToggle:toggle !== false,
23892 pressed : toggle ? false : null,
23895 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23896 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23902 // var cb_box = function...
23907 xns: Roo.bootstrap,
23908 glyphicon : 'font',
23912 xns: Roo.bootstrap,
23916 Roo.each(this.formats, function(f) {
23917 style.menu.items.push({
23919 xns: Roo.bootstrap,
23920 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23925 editorcore.insertTag(this.tagname);
23932 children.push(style);
23934 btn('bold',false,true);
23935 btn('italic',false,true);
23936 btn('align-left', 'justifyleft',true);
23937 btn('align-center', 'justifycenter',true);
23938 btn('align-right' , 'justifyright',true);
23939 btn('link', false, false, function(btn) {
23940 //Roo.log("create link?");
23941 var url = prompt(this.createLinkText, this.defaultLinkValue);
23942 if(url && url != 'http:/'+'/'){
23943 this.editorcore.relayCmd('createlink', url);
23946 btn('list','insertunorderedlist',true);
23947 btn('pencil', false,true, function(btn){
23949 this.toggleSourceEdit(btn.pressed);
23952 if (this.editor.btns.length > 0) {
23953 for (var i = 0; i<this.editor.btns.length; i++) {
23954 children.push(this.editor.btns[i]);
23962 xns: Roo.bootstrap,
23967 xns: Roo.bootstrap,
23972 cog.menu.items.push({
23974 xns: Roo.bootstrap,
23975 html : Clean styles,
23980 editorcore.insertTag(this.tagname);
23989 this.xtype = 'NavSimplebar';
23991 for(var i=0;i< children.length;i++) {
23993 this.buttons.add(this.addxtypeChild(children[i]));
23997 editor.on('editorevent', this.updateToolbar, this);
23999 onBtnClick : function(id)
24001 this.editorcore.relayCmd(id);
24002 this.editorcore.focus();
24006 * Protected method that will not generally be called directly. It triggers
24007 * a toolbar update by reading the markup state of the current selection in the editor.
24009 updateToolbar: function(){
24011 if(!this.editorcore.activated){
24012 this.editor.onFirstFocus(); // is this neeed?
24016 var btns = this.buttons;
24017 var doc = this.editorcore.doc;
24018 btns.get('bold').setActive(doc.queryCommandState('bold'));
24019 btns.get('italic').setActive(doc.queryCommandState('italic'));
24020 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24022 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24023 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24024 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24026 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24027 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24030 var ans = this.editorcore.getAllAncestors();
24031 if (this.formatCombo) {
24034 var store = this.formatCombo.store;
24035 this.formatCombo.setValue("");
24036 for (var i =0; i < ans.length;i++) {
24037 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24039 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24047 // hides menus... - so this cant be on a menu...
24048 Roo.bootstrap.MenuMgr.hideAll();
24050 Roo.bootstrap.MenuMgr.hideAll();
24051 //this.editorsyncValue();
24053 onFirstFocus: function() {
24054 this.buttons.each(function(item){
24058 toggleSourceEdit : function(sourceEditMode){
24061 if(sourceEditMode){
24062 Roo.log("disabling buttons");
24063 this.buttons.each( function(item){
24064 if(item.cmd != 'pencil'){
24070 Roo.log("enabling buttons");
24071 if(this.editorcore.initialized){
24072 this.buttons.each( function(item){
24078 Roo.log("calling toggole on editor");
24079 // tell the editor that it's been pressed..
24080 this.editor.toggleSourceEdit(sourceEditMode);
24090 * @class Roo.bootstrap.Table.AbstractSelectionModel
24091 * @extends Roo.util.Observable
24092 * Abstract base class for grid SelectionModels. It provides the interface that should be
24093 * implemented by descendant classes. This class should not be directly instantiated.
24096 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24097 this.locked = false;
24098 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24102 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24103 /** @ignore Called by the grid automatically. Do not call directly. */
24104 init : function(grid){
24110 * Locks the selections.
24113 this.locked = true;
24117 * Unlocks the selections.
24119 unlock : function(){
24120 this.locked = false;
24124 * Returns true if the selections are locked.
24125 * @return {Boolean}
24127 isLocked : function(){
24128 return this.locked;
24132 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24133 * @class Roo.bootstrap.Table.RowSelectionModel
24134 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24135 * It supports multiple selections and keyboard selection/navigation.
24137 * @param {Object} config
24140 Roo.bootstrap.Table.RowSelectionModel = function(config){
24141 Roo.apply(this, config);
24142 this.selections = new Roo.util.MixedCollection(false, function(o){
24147 this.lastActive = false;
24151 * @event selectionchange
24152 * Fires when the selection changes
24153 * @param {SelectionModel} this
24155 "selectionchange" : true,
24157 * @event afterselectionchange
24158 * Fires after the selection changes (eg. by key press or clicking)
24159 * @param {SelectionModel} this
24161 "afterselectionchange" : true,
24163 * @event beforerowselect
24164 * Fires when a row is selected being selected, return false to cancel.
24165 * @param {SelectionModel} this
24166 * @param {Number} rowIndex The selected index
24167 * @param {Boolean} keepExisting False if other selections will be cleared
24169 "beforerowselect" : true,
24172 * Fires when a row is selected.
24173 * @param {SelectionModel} this
24174 * @param {Number} rowIndex The selected index
24175 * @param {Roo.data.Record} r The record
24177 "rowselect" : true,
24179 * @event rowdeselect
24180 * Fires when a row is deselected.
24181 * @param {SelectionModel} this
24182 * @param {Number} rowIndex The selected index
24184 "rowdeselect" : true
24186 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24187 this.locked = false;
24190 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24192 * @cfg {Boolean} singleSelect
24193 * True to allow selection of only one row at a time (defaults to false)
24195 singleSelect : false,
24198 initEvents : function()
24201 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24202 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24203 //}else{ // allow click to work like normal
24204 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24206 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24207 this.grid.on("rowclick", this.handleMouseDown, this);
24209 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24210 "up" : function(e){
24212 this.selectPrevious(e.shiftKey);
24213 }else if(this.last !== false && this.lastActive !== false){
24214 var last = this.last;
24215 this.selectRange(this.last, this.lastActive-1);
24216 this.grid.getView().focusRow(this.lastActive);
24217 if(last !== false){
24221 this.selectFirstRow();
24223 this.fireEvent("afterselectionchange", this);
24225 "down" : function(e){
24227 this.selectNext(e.shiftKey);
24228 }else if(this.last !== false && this.lastActive !== false){
24229 var last = this.last;
24230 this.selectRange(this.last, this.lastActive+1);
24231 this.grid.getView().focusRow(this.lastActive);
24232 if(last !== false){
24236 this.selectFirstRow();
24238 this.fireEvent("afterselectionchange", this);
24242 this.grid.store.on('load', function(){
24243 this.selections.clear();
24246 var view = this.grid.view;
24247 view.on("refresh", this.onRefresh, this);
24248 view.on("rowupdated", this.onRowUpdated, this);
24249 view.on("rowremoved", this.onRemove, this);
24254 onRefresh : function()
24256 var ds = this.grid.store, i, v = this.grid.view;
24257 var s = this.selections;
24258 s.each(function(r){
24259 if((i = ds.indexOfId(r.id)) != -1){
24268 onRemove : function(v, index, r){
24269 this.selections.remove(r);
24273 onRowUpdated : function(v, index, r){
24274 if(this.isSelected(r)){
24275 v.onRowSelect(index);
24281 * @param {Array} records The records to select
24282 * @param {Boolean} keepExisting (optional) True to keep existing selections
24284 selectRecords : function(records, keepExisting)
24287 this.clearSelections();
24289 var ds = this.grid.store;
24290 for(var i = 0, len = records.length; i < len; i++){
24291 this.selectRow(ds.indexOf(records[i]), true);
24296 * Gets the number of selected rows.
24299 getCount : function(){
24300 return this.selections.length;
24304 * Selects the first row in the grid.
24306 selectFirstRow : function(){
24311 * Select the last row.
24312 * @param {Boolean} keepExisting (optional) True to keep existing selections
24314 selectLastRow : function(keepExisting){
24315 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24316 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24320 * Selects the row immediately following the last selected row.
24321 * @param {Boolean} keepExisting (optional) True to keep existing selections
24323 selectNext : function(keepExisting)
24325 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24326 this.selectRow(this.last+1, keepExisting);
24327 this.grid.getView().focusRow(this.last);
24332 * Selects the row that precedes the last selected row.
24333 * @param {Boolean} keepExisting (optional) True to keep existing selections
24335 selectPrevious : function(keepExisting){
24337 this.selectRow(this.last-1, keepExisting);
24338 this.grid.getView().focusRow(this.last);
24343 * Returns the selected records
24344 * @return {Array} Array of selected records
24346 getSelections : function(){
24347 return [].concat(this.selections.items);
24351 * Returns the first selected record.
24354 getSelected : function(){
24355 return this.selections.itemAt(0);
24360 * Clears all selections.
24362 clearSelections : function(fast)
24368 var ds = this.grid.store;
24369 var s = this.selections;
24370 s.each(function(r){
24371 this.deselectRow(ds.indexOfId(r.id));
24375 this.selections.clear();
24382 * Selects all rows.
24384 selectAll : function(){
24388 this.selections.clear();
24389 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24390 this.selectRow(i, true);
24395 * Returns True if there is a selection.
24396 * @return {Boolean}
24398 hasSelection : function(){
24399 return this.selections.length > 0;
24403 * Returns True if the specified row is selected.
24404 * @param {Number/Record} record The record or index of the record to check
24405 * @return {Boolean}
24407 isSelected : function(index){
24408 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24409 return (r && this.selections.key(r.id) ? true : false);
24413 * Returns True if the specified record id is selected.
24414 * @param {String} id The id of record to check
24415 * @return {Boolean}
24417 isIdSelected : function(id){
24418 return (this.selections.key(id) ? true : false);
24423 handleMouseDBClick : function(e, t){
24427 handleMouseDown : function(e, t)
24429 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24430 if(this.isLocked() || rowIndex < 0 ){
24433 if(e.shiftKey && this.last !== false){
24434 var last = this.last;
24435 this.selectRange(last, rowIndex, e.ctrlKey);
24436 this.last = last; // reset the last
24440 var isSelected = this.isSelected(rowIndex);
24441 //Roo.log("select row:" + rowIndex);
24443 this.deselectRow(rowIndex);
24445 this.selectRow(rowIndex, true);
24449 if(e.button !== 0 && isSelected){
24450 alert('rowIndex 2: ' + rowIndex);
24451 view.focusRow(rowIndex);
24452 }else if(e.ctrlKey && isSelected){
24453 this.deselectRow(rowIndex);
24454 }else if(!isSelected){
24455 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24456 view.focusRow(rowIndex);
24460 this.fireEvent("afterselectionchange", this);
24463 handleDragableRowClick : function(grid, rowIndex, e)
24465 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24466 this.selectRow(rowIndex, false);
24467 grid.view.focusRow(rowIndex);
24468 this.fireEvent("afterselectionchange", this);
24473 * Selects multiple rows.
24474 * @param {Array} rows Array of the indexes of the row to select
24475 * @param {Boolean} keepExisting (optional) True to keep existing selections
24477 selectRows : function(rows, keepExisting){
24479 this.clearSelections();
24481 for(var i = 0, len = rows.length; i < len; i++){
24482 this.selectRow(rows[i], true);
24487 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24488 * @param {Number} startRow The index of the first row in the range
24489 * @param {Number} endRow The index of the last row in the range
24490 * @param {Boolean} keepExisting (optional) True to retain existing selections
24492 selectRange : function(startRow, endRow, keepExisting){
24497 this.clearSelections();
24499 if(startRow <= endRow){
24500 for(var i = startRow; i <= endRow; i++){
24501 this.selectRow(i, true);
24504 for(var i = startRow; i >= endRow; i--){
24505 this.selectRow(i, true);
24511 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24512 * @param {Number} startRow The index of the first row in the range
24513 * @param {Number} endRow The index of the last row in the range
24515 deselectRange : function(startRow, endRow, preventViewNotify){
24519 for(var i = startRow; i <= endRow; i++){
24520 this.deselectRow(i, preventViewNotify);
24526 * @param {Number} row The index of the row to select
24527 * @param {Boolean} keepExisting (optional) True to keep existing selections
24529 selectRow : function(index, keepExisting, preventViewNotify)
24531 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24534 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24535 if(!keepExisting || this.singleSelect){
24536 this.clearSelections();
24539 var r = this.grid.store.getAt(index);
24540 //console.log('selectRow - record id :' + r.id);
24542 this.selections.add(r);
24543 this.last = this.lastActive = index;
24544 if(!preventViewNotify){
24545 var proxy = new Roo.Element(
24546 this.grid.getRowDom(index)
24548 proxy.addClass('bg-info info');
24550 this.fireEvent("rowselect", this, index, r);
24551 this.fireEvent("selectionchange", this);
24557 * @param {Number} row The index of the row to deselect
24559 deselectRow : function(index, preventViewNotify)
24564 if(this.last == index){
24567 if(this.lastActive == index){
24568 this.lastActive = false;
24571 var r = this.grid.store.getAt(index);
24576 this.selections.remove(r);
24577 //.console.log('deselectRow - record id :' + r.id);
24578 if(!preventViewNotify){
24580 var proxy = new Roo.Element(
24581 this.grid.getRowDom(index)
24583 proxy.removeClass('bg-info info');
24585 this.fireEvent("rowdeselect", this, index);
24586 this.fireEvent("selectionchange", this);
24590 restoreLast : function(){
24592 this.last = this._last;
24597 acceptsNav : function(row, col, cm){
24598 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24602 onEditorKey : function(field, e){
24603 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24608 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24610 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24612 }else if(k == e.ENTER && !e.ctrlKey){
24616 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24618 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24620 }else if(k == e.ESC){
24624 g.startEditing(newCell[0], newCell[1]);
24630 * Ext JS Library 1.1.1
24631 * Copyright(c) 2006-2007, Ext JS, LLC.
24633 * Originally Released Under LGPL - original licence link has changed is not relivant.
24636 * <script type="text/javascript">
24640 * @class Roo.bootstrap.PagingToolbar
24641 * @extends Roo.bootstrap.NavSimplebar
24642 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24644 * Create a new PagingToolbar
24645 * @param {Object} config The config object
24646 * @param {Roo.data.Store} store
24648 Roo.bootstrap.PagingToolbar = function(config)
24650 // old args format still supported... - xtype is prefered..
24651 // created from xtype...
24653 this.ds = config.dataSource;
24655 if (config.store && !this.ds) {
24656 this.store= Roo.factory(config.store, Roo.data);
24657 this.ds = this.store;
24658 this.ds.xmodule = this.xmodule || false;
24661 this.toolbarItems = [];
24662 if (config.items) {
24663 this.toolbarItems = config.items;
24666 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24671 this.bind(this.ds);
24674 if (Roo.bootstrap.version == 4) {
24675 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24677 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24682 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24684 * @cfg {Roo.data.Store} dataSource
24685 * The underlying data store providing the paged data
24688 * @cfg {String/HTMLElement/Element} container
24689 * container The id or element that will contain the toolbar
24692 * @cfg {Boolean} displayInfo
24693 * True to display the displayMsg (defaults to false)
24696 * @cfg {Number} pageSize
24697 * The number of records to display per page (defaults to 20)
24701 * @cfg {String} displayMsg
24702 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24704 displayMsg : 'Displaying {0} - {1} of {2}',
24706 * @cfg {String} emptyMsg
24707 * The message to display when no records are found (defaults to "No data to display")
24709 emptyMsg : 'No data to display',
24711 * Customizable piece of the default paging text (defaults to "Page")
24714 beforePageText : "Page",
24716 * Customizable piece of the default paging text (defaults to "of %0")
24719 afterPageText : "of {0}",
24721 * Customizable piece of the default paging text (defaults to "First Page")
24724 firstText : "First Page",
24726 * Customizable piece of the default paging text (defaults to "Previous Page")
24729 prevText : "Previous Page",
24731 * Customizable piece of the default paging text (defaults to "Next Page")
24734 nextText : "Next Page",
24736 * Customizable piece of the default paging text (defaults to "Last Page")
24739 lastText : "Last Page",
24741 * Customizable piece of the default paging text (defaults to "Refresh")
24744 refreshText : "Refresh",
24748 onRender : function(ct, position)
24750 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24751 this.navgroup.parentId = this.id;
24752 this.navgroup.onRender(this.el, null);
24753 // add the buttons to the navgroup
24755 if(this.displayInfo){
24756 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24757 this.displayEl = this.el.select('.x-paging-info', true).first();
24758 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24759 // this.displayEl = navel.el.select('span',true).first();
24765 Roo.each(_this.buttons, function(e){ // this might need to use render????
24766 Roo.factory(e).render(_this.el);
24770 Roo.each(_this.toolbarItems, function(e) {
24771 _this.navgroup.addItem(e);
24775 this.first = this.navgroup.addItem({
24776 tooltip: this.firstText,
24777 cls: "prev btn-outline-secondary",
24778 html : ' <i class="fa fa-step-backward"></i>',
24780 preventDefault: true,
24781 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24784 this.prev = this.navgroup.addItem({
24785 tooltip: this.prevText,
24786 cls: "prev btn-outline-secondary",
24787 html : ' <i class="fa fa-backward"></i>',
24789 preventDefault: true,
24790 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24792 //this.addSeparator();
24795 var field = this.navgroup.addItem( {
24797 cls : 'x-paging-position btn-outline-secondary',
24799 html : this.beforePageText +
24800 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24801 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24804 this.field = field.el.select('input', true).first();
24805 this.field.on("keydown", this.onPagingKeydown, this);
24806 this.field.on("focus", function(){this.dom.select();});
24809 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24810 //this.field.setHeight(18);
24811 //this.addSeparator();
24812 this.next = this.navgroup.addItem({
24813 tooltip: this.nextText,
24814 cls: "next btn-outline-secondary",
24815 html : ' <i class="fa fa-forward"></i>',
24817 preventDefault: true,
24818 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24820 this.last = this.navgroup.addItem({
24821 tooltip: this.lastText,
24822 html : ' <i class="fa fa-step-forward"></i>',
24823 cls: "next btn-outline-secondary",
24825 preventDefault: true,
24826 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24828 //this.addSeparator();
24829 this.loading = this.navgroup.addItem({
24830 tooltip: this.refreshText,
24831 cls: "btn-outline-secondary",
24832 html : ' <i class="fa fa-refresh"></i>',
24833 preventDefault: true,
24834 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24840 updateInfo : function(){
24841 if(this.displayEl){
24842 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24843 var msg = count == 0 ?
24847 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24849 this.displayEl.update(msg);
24854 onLoad : function(ds, r, o)
24856 this.cursor = o.params.start ? o.params.start : 0;
24858 var d = this.getPageData(),
24863 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24864 this.field.dom.value = ap;
24865 this.first.setDisabled(ap == 1);
24866 this.prev.setDisabled(ap == 1);
24867 this.next.setDisabled(ap == ps);
24868 this.last.setDisabled(ap == ps);
24869 this.loading.enable();
24874 getPageData : function(){
24875 var total = this.ds.getTotalCount();
24878 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24879 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24884 onLoadError : function(){
24885 this.loading.enable();
24889 onPagingKeydown : function(e){
24890 var k = e.getKey();
24891 var d = this.getPageData();
24893 var v = this.field.dom.value, pageNum;
24894 if(!v || isNaN(pageNum = parseInt(v, 10))){
24895 this.field.dom.value = d.activePage;
24898 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24899 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24902 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))
24904 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24905 this.field.dom.value = pageNum;
24906 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24909 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24911 var v = this.field.dom.value, pageNum;
24912 var increment = (e.shiftKey) ? 10 : 1;
24913 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24916 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24917 this.field.dom.value = d.activePage;
24920 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24922 this.field.dom.value = parseInt(v, 10) + increment;
24923 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24924 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24931 beforeLoad : function(){
24933 this.loading.disable();
24938 onClick : function(which){
24947 ds.load({params:{start: 0, limit: this.pageSize}});
24950 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24953 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24956 var total = ds.getTotalCount();
24957 var extra = total % this.pageSize;
24958 var lastStart = extra ? (total - extra) : total-this.pageSize;
24959 ds.load({params:{start: lastStart, limit: this.pageSize}});
24962 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24968 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24969 * @param {Roo.data.Store} store The data store to unbind
24971 unbind : function(ds){
24972 ds.un("beforeload", this.beforeLoad, this);
24973 ds.un("load", this.onLoad, this);
24974 ds.un("loadexception", this.onLoadError, this);
24975 ds.un("remove", this.updateInfo, this);
24976 ds.un("add", this.updateInfo, this);
24977 this.ds = undefined;
24981 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24982 * @param {Roo.data.Store} store The data store to bind
24984 bind : function(ds){
24985 ds.on("beforeload", this.beforeLoad, this);
24986 ds.on("load", this.onLoad, this);
24987 ds.on("loadexception", this.onLoadError, this);
24988 ds.on("remove", this.updateInfo, this);
24989 ds.on("add", this.updateInfo, this);
25000 * @class Roo.bootstrap.MessageBar
25001 * @extends Roo.bootstrap.Component
25002 * Bootstrap MessageBar class
25003 * @cfg {String} html contents of the MessageBar
25004 * @cfg {String} weight (info | success | warning | danger) default info
25005 * @cfg {String} beforeClass insert the bar before the given class
25006 * @cfg {Boolean} closable (true | false) default false
25007 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25010 * Create a new Element
25011 * @param {Object} config The config object
25014 Roo.bootstrap.MessageBar = function(config){
25015 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25018 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25024 beforeClass: 'bootstrap-sticky-wrap',
25026 getAutoCreate : function(){
25030 cls: 'alert alert-dismissable alert-' + this.weight,
25035 html: this.html || ''
25041 cfg.cls += ' alert-messages-fixed';
25055 onRender : function(ct, position)
25057 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25060 var cfg = Roo.apply({}, this.getAutoCreate());
25064 cfg.cls += ' ' + this.cls;
25067 cfg.style = this.style;
25069 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25071 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25074 this.el.select('>button.close').on('click', this.hide, this);
25080 if (!this.rendered) {
25086 this.fireEvent('show', this);
25092 if (!this.rendered) {
25098 this.fireEvent('hide', this);
25101 update : function()
25103 // var e = this.el.dom.firstChild;
25105 // if(this.closable){
25106 // e = e.nextSibling;
25109 // e.data = this.html || '';
25111 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25127 * @class Roo.bootstrap.Graph
25128 * @extends Roo.bootstrap.Component
25129 * Bootstrap Graph class
25133 @cfg {String} graphtype bar | vbar | pie
25134 @cfg {number} g_x coodinator | centre x (pie)
25135 @cfg {number} g_y coodinator | centre y (pie)
25136 @cfg {number} g_r radius (pie)
25137 @cfg {number} g_height height of the chart (respected by all elements in the set)
25138 @cfg {number} g_width width of the chart (respected by all elements in the set)
25139 @cfg {Object} title The title of the chart
25142 -opts (object) options for the chart
25144 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25145 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25147 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.
25148 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25150 o stretch (boolean)
25152 -opts (object) options for the pie
25155 o startAngle (number)
25156 o endAngle (number)
25160 * Create a new Input
25161 * @param {Object} config The config object
25164 Roo.bootstrap.Graph = function(config){
25165 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25171 * The img click event for the img.
25172 * @param {Roo.EventObject} e
25178 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25189 //g_colors: this.colors,
25196 getAutoCreate : function(){
25207 onRender : function(ct,position){
25210 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25212 if (typeof(Raphael) == 'undefined') {
25213 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25217 this.raphael = Raphael(this.el.dom);
25219 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25220 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25221 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25222 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25224 r.text(160, 10, "Single Series Chart").attr(txtattr);
25225 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25226 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25227 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25229 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25230 r.barchart(330, 10, 300, 220, data1);
25231 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25232 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25235 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25236 // r.barchart(30, 30, 560, 250, xdata, {
25237 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25238 // axis : "0 0 1 1",
25239 // axisxlabels : xdata
25240 // //yvalues : cols,
25243 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25245 // this.load(null,xdata,{
25246 // axis : "0 0 1 1",
25247 // axisxlabels : xdata
25252 load : function(graphtype,xdata,opts)
25254 this.raphael.clear();
25256 graphtype = this.graphtype;
25261 var r = this.raphael,
25262 fin = function () {
25263 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25265 fout = function () {
25266 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25268 pfin = function() {
25269 this.sector.stop();
25270 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25273 this.label[0].stop();
25274 this.label[0].attr({ r: 7.5 });
25275 this.label[1].attr({ "font-weight": 800 });
25278 pfout = function() {
25279 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25282 this.label[0].animate({ r: 5 }, 500, "bounce");
25283 this.label[1].attr({ "font-weight": 400 });
25289 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25292 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25295 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25296 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25298 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25305 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25310 setTitle: function(o)
25315 initEvents: function() {
25318 this.el.on('click', this.onClick, this);
25322 onClick : function(e)
25324 Roo.log('img onclick');
25325 this.fireEvent('click', this, e);
25337 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25340 * @class Roo.bootstrap.dash.NumberBox
25341 * @extends Roo.bootstrap.Component
25342 * Bootstrap NumberBox class
25343 * @cfg {String} headline Box headline
25344 * @cfg {String} content Box content
25345 * @cfg {String} icon Box icon
25346 * @cfg {String} footer Footer text
25347 * @cfg {String} fhref Footer href
25350 * Create a new NumberBox
25351 * @param {Object} config The config object
25355 Roo.bootstrap.dash.NumberBox = function(config){
25356 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25360 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25369 getAutoCreate : function(){
25373 cls : 'small-box ',
25381 cls : 'roo-headline',
25382 html : this.headline
25386 cls : 'roo-content',
25387 html : this.content
25401 cls : 'ion ' + this.icon
25410 cls : 'small-box-footer',
25411 href : this.fhref || '#',
25415 cfg.cn.push(footer);
25422 onRender : function(ct,position){
25423 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25430 setHeadline: function (value)
25432 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25435 setFooter: function (value, href)
25437 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25440 this.el.select('a.small-box-footer',true).first().attr('href', href);
25445 setContent: function (value)
25447 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25450 initEvents: function()
25464 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25467 * @class Roo.bootstrap.dash.TabBox
25468 * @extends Roo.bootstrap.Component
25469 * Bootstrap TabBox class
25470 * @cfg {String} title Title of the TabBox
25471 * @cfg {String} icon Icon of the TabBox
25472 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25473 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25476 * Create a new TabBox
25477 * @param {Object} config The config object
25481 Roo.bootstrap.dash.TabBox = function(config){
25482 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25487 * When a pane is added
25488 * @param {Roo.bootstrap.dash.TabPane} pane
25492 * @event activatepane
25493 * When a pane is activated
25494 * @param {Roo.bootstrap.dash.TabPane} pane
25496 "activatepane" : true
25504 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25509 tabScrollable : false,
25511 getChildContainer : function()
25513 return this.el.select('.tab-content', true).first();
25516 getAutoCreate : function(){
25520 cls: 'pull-left header',
25528 cls: 'fa ' + this.icon
25534 cls: 'nav nav-tabs pull-right',
25540 if(this.tabScrollable){
25547 cls: 'nav nav-tabs pull-right',
25558 cls: 'nav-tabs-custom',
25563 cls: 'tab-content no-padding',
25571 initEvents : function()
25573 //Roo.log('add add pane handler');
25574 this.on('addpane', this.onAddPane, this);
25577 * Updates the box title
25578 * @param {String} html to set the title to.
25580 setTitle : function(value)
25582 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25584 onAddPane : function(pane)
25586 this.panes.push(pane);
25587 //Roo.log('addpane');
25589 // tabs are rendere left to right..
25590 if(!this.showtabs){
25594 var ctr = this.el.select('.nav-tabs', true).first();
25597 var existing = ctr.select('.nav-tab',true);
25598 var qty = existing.getCount();;
25601 var tab = ctr.createChild({
25603 cls : 'nav-tab' + (qty ? '' : ' active'),
25611 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25614 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25616 pane.el.addClass('active');
25621 onTabClick : function(ev,un,ob,pane)
25623 //Roo.log('tab - prev default');
25624 ev.preventDefault();
25627 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25628 pane.tab.addClass('active');
25629 //Roo.log(pane.title);
25630 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25631 // technically we should have a deactivate event.. but maybe add later.
25632 // and it should not de-activate the selected tab...
25633 this.fireEvent('activatepane', pane);
25634 pane.el.addClass('active');
25635 pane.fireEvent('activate');
25640 getActivePane : function()
25643 Roo.each(this.panes, function(p) {
25644 if(p.el.hasClass('active')){
25665 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25667 * @class Roo.bootstrap.TabPane
25668 * @extends Roo.bootstrap.Component
25669 * Bootstrap TabPane class
25670 * @cfg {Boolean} active (false | true) Default false
25671 * @cfg {String} title title of panel
25675 * Create a new TabPane
25676 * @param {Object} config The config object
25679 Roo.bootstrap.dash.TabPane = function(config){
25680 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25686 * When a pane is activated
25687 * @param {Roo.bootstrap.dash.TabPane} pane
25694 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25699 // the tabBox that this is attached to.
25702 getAutoCreate : function()
25710 cfg.cls += ' active';
25715 initEvents : function()
25717 //Roo.log('trigger add pane handler');
25718 this.parent().fireEvent('addpane', this)
25722 * Updates the tab title
25723 * @param {String} html to set the title to.
25725 setTitle: function(str)
25731 this.tab.select('a', true).first().dom.innerHTML = str;
25748 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25751 * @class Roo.bootstrap.menu.Menu
25752 * @extends Roo.bootstrap.Component
25753 * Bootstrap Menu class - container for Menu
25754 * @cfg {String} html Text of the menu
25755 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25756 * @cfg {String} icon Font awesome icon
25757 * @cfg {String} pos Menu align to (top | bottom) default bottom
25761 * Create a new Menu
25762 * @param {Object} config The config object
25766 Roo.bootstrap.menu.Menu = function(config){
25767 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25771 * @event beforeshow
25772 * Fires before this menu is displayed
25773 * @param {Roo.bootstrap.menu.Menu} this
25777 * @event beforehide
25778 * Fires before this menu is hidden
25779 * @param {Roo.bootstrap.menu.Menu} this
25784 * Fires after this menu is displayed
25785 * @param {Roo.bootstrap.menu.Menu} this
25790 * Fires after this menu is hidden
25791 * @param {Roo.bootstrap.menu.Menu} this
25796 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25797 * @param {Roo.bootstrap.menu.Menu} this
25798 * @param {Roo.EventObject} e
25805 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25809 weight : 'default',
25814 getChildContainer : function() {
25815 if(this.isSubMenu){
25819 return this.el.select('ul.dropdown-menu', true).first();
25822 getAutoCreate : function()
25827 cls : 'roo-menu-text',
25835 cls : 'fa ' + this.icon
25846 cls : 'dropdown-button btn btn-' + this.weight,
25851 cls : 'dropdown-toggle btn btn-' + this.weight,
25861 cls : 'dropdown-menu'
25867 if(this.pos == 'top'){
25868 cfg.cls += ' dropup';
25871 if(this.isSubMenu){
25874 cls : 'dropdown-menu'
25881 onRender : function(ct, position)
25883 this.isSubMenu = ct.hasClass('dropdown-submenu');
25885 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25888 initEvents : function()
25890 if(this.isSubMenu){
25894 this.hidden = true;
25896 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25897 this.triggerEl.on('click', this.onTriggerPress, this);
25899 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25900 this.buttonEl.on('click', this.onClick, this);
25906 if(this.isSubMenu){
25910 return this.el.select('ul.dropdown-menu', true).first();
25913 onClick : function(e)
25915 this.fireEvent("click", this, e);
25918 onTriggerPress : function(e)
25920 if (this.isVisible()) {
25927 isVisible : function(){
25928 return !this.hidden;
25933 this.fireEvent("beforeshow", this);
25935 this.hidden = false;
25936 this.el.addClass('open');
25938 Roo.get(document).on("mouseup", this.onMouseUp, this);
25940 this.fireEvent("show", this);
25947 this.fireEvent("beforehide", this);
25949 this.hidden = true;
25950 this.el.removeClass('open');
25952 Roo.get(document).un("mouseup", this.onMouseUp);
25954 this.fireEvent("hide", this);
25957 onMouseUp : function()
25971 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25974 * @class Roo.bootstrap.menu.Item
25975 * @extends Roo.bootstrap.Component
25976 * Bootstrap MenuItem class
25977 * @cfg {Boolean} submenu (true | false) default false
25978 * @cfg {String} html text of the item
25979 * @cfg {String} href the link
25980 * @cfg {Boolean} disable (true | false) default false
25981 * @cfg {Boolean} preventDefault (true | false) default true
25982 * @cfg {String} icon Font awesome icon
25983 * @cfg {String} pos Submenu align to (left | right) default right
25987 * Create a new Item
25988 * @param {Object} config The config object
25992 Roo.bootstrap.menu.Item = function(config){
25993 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25997 * Fires when the mouse is hovering over this menu
25998 * @param {Roo.bootstrap.menu.Item} this
25999 * @param {Roo.EventObject} e
26004 * Fires when the mouse exits this menu
26005 * @param {Roo.bootstrap.menu.Item} this
26006 * @param {Roo.EventObject} e
26012 * The raw click event for the entire grid.
26013 * @param {Roo.EventObject} e
26019 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26024 preventDefault: true,
26029 getAutoCreate : function()
26034 cls : 'roo-menu-item-text',
26042 cls : 'fa ' + this.icon
26051 href : this.href || '#',
26058 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26062 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26064 if(this.pos == 'left'){
26065 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26072 initEvents : function()
26074 this.el.on('mouseover', this.onMouseOver, this);
26075 this.el.on('mouseout', this.onMouseOut, this);
26077 this.el.select('a', true).first().on('click', this.onClick, this);
26081 onClick : function(e)
26083 if(this.preventDefault){
26084 e.preventDefault();
26087 this.fireEvent("click", this, e);
26090 onMouseOver : function(e)
26092 if(this.submenu && this.pos == 'left'){
26093 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26096 this.fireEvent("mouseover", this, e);
26099 onMouseOut : function(e)
26101 this.fireEvent("mouseout", this, e);
26113 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26116 * @class Roo.bootstrap.menu.Separator
26117 * @extends Roo.bootstrap.Component
26118 * Bootstrap Separator class
26121 * Create a new Separator
26122 * @param {Object} config The config object
26126 Roo.bootstrap.menu.Separator = function(config){
26127 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26130 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26132 getAutoCreate : function(){
26153 * @class Roo.bootstrap.Tooltip
26154 * Bootstrap Tooltip class
26155 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26156 * to determine which dom element triggers the tooltip.
26158 * It needs to add support for additional attributes like tooltip-position
26161 * Create a new Toolti
26162 * @param {Object} config The config object
26165 Roo.bootstrap.Tooltip = function(config){
26166 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26168 this.alignment = Roo.bootstrap.Tooltip.alignment;
26170 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26171 this.alignment = config.alignment;
26176 Roo.apply(Roo.bootstrap.Tooltip, {
26178 * @function init initialize tooltip monitoring.
26182 currentTip : false,
26183 currentRegion : false,
26189 Roo.get(document).on('mouseover', this.enter ,this);
26190 Roo.get(document).on('mouseout', this.leave, this);
26193 this.currentTip = new Roo.bootstrap.Tooltip();
26196 enter : function(ev)
26198 var dom = ev.getTarget();
26200 //Roo.log(['enter',dom]);
26201 var el = Roo.fly(dom);
26202 if (this.currentEl) {
26204 //Roo.log(this.currentEl);
26205 //Roo.log(this.currentEl.contains(dom));
26206 if (this.currentEl == el) {
26209 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26215 if (this.currentTip.el) {
26216 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26220 if(!el || el.dom == document){
26226 // you can not look for children, as if el is the body.. then everythign is the child..
26227 if (!el.attr('tooltip')) { //
26228 if (!el.select("[tooltip]").elements.length) {
26231 // is the mouse over this child...?
26232 bindEl = el.select("[tooltip]").first();
26233 var xy = ev.getXY();
26234 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26235 //Roo.log("not in region.");
26238 //Roo.log("child element over..");
26241 this.currentEl = bindEl;
26242 this.currentTip.bind(bindEl);
26243 this.currentRegion = Roo.lib.Region.getRegion(dom);
26244 this.currentTip.enter();
26247 leave : function(ev)
26249 var dom = ev.getTarget();
26250 //Roo.log(['leave',dom]);
26251 if (!this.currentEl) {
26256 if (dom != this.currentEl.dom) {
26259 var xy = ev.getXY();
26260 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26263 // only activate leave if mouse cursor is outside... bounding box..
26268 if (this.currentTip) {
26269 this.currentTip.leave();
26271 //Roo.log('clear currentEl');
26272 this.currentEl = false;
26277 'left' : ['r-l', [-2,0], 'right'],
26278 'right' : ['l-r', [2,0], 'left'],
26279 'bottom' : ['t-b', [0,2], 'top'],
26280 'top' : [ 'b-t', [0,-2], 'bottom']
26286 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26291 delay : null, // can be { show : 300 , hide: 500}
26295 hoverState : null, //???
26297 placement : 'bottom',
26301 getAutoCreate : function(){
26308 cls : 'tooltip-arrow'
26311 cls : 'tooltip-inner'
26318 bind : function(el)
26324 enter : function () {
26326 if (this.timeout != null) {
26327 clearTimeout(this.timeout);
26330 this.hoverState = 'in';
26331 //Roo.log("enter - show");
26332 if (!this.delay || !this.delay.show) {
26337 this.timeout = setTimeout(function () {
26338 if (_t.hoverState == 'in') {
26341 }, this.delay.show);
26345 clearTimeout(this.timeout);
26347 this.hoverState = 'out';
26348 if (!this.delay || !this.delay.hide) {
26354 this.timeout = setTimeout(function () {
26355 //Roo.log("leave - timeout");
26357 if (_t.hoverState == 'out') {
26359 Roo.bootstrap.Tooltip.currentEl = false;
26364 show : function (msg)
26367 this.render(document.body);
26370 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26372 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26374 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26376 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26378 var placement = typeof this.placement == 'function' ?
26379 this.placement.call(this, this.el, on_el) :
26382 var autoToken = /\s?auto?\s?/i;
26383 var autoPlace = autoToken.test(placement);
26385 placement = placement.replace(autoToken, '') || 'top';
26389 //this.el.setXY([0,0]);
26391 //this.el.dom.style.display='block';
26393 //this.el.appendTo(on_el);
26395 var p = this.getPosition();
26396 var box = this.el.getBox();
26402 var align = this.alignment[placement];
26404 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26406 if(placement == 'top' || placement == 'bottom'){
26408 placement = 'right';
26411 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26412 placement = 'left';
26415 var scroll = Roo.select('body', true).first().getScroll();
26417 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26421 align = this.alignment[placement];
26424 this.el.alignTo(this.bindEl, align[0],align[1]);
26425 //var arrow = this.el.select('.arrow',true).first();
26426 //arrow.set(align[2],
26428 this.el.addClass(placement);
26430 this.el.addClass('in fade');
26432 this.hoverState = null;
26434 if (this.el.hasClass('fade')) {
26445 //this.el.setXY([0,0]);
26446 this.el.removeClass('in');
26462 * @class Roo.bootstrap.LocationPicker
26463 * @extends Roo.bootstrap.Component
26464 * Bootstrap LocationPicker class
26465 * @cfg {Number} latitude Position when init default 0
26466 * @cfg {Number} longitude Position when init default 0
26467 * @cfg {Number} zoom default 15
26468 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26469 * @cfg {Boolean} mapTypeControl default false
26470 * @cfg {Boolean} disableDoubleClickZoom default false
26471 * @cfg {Boolean} scrollwheel default true
26472 * @cfg {Boolean} streetViewControl default false
26473 * @cfg {Number} radius default 0
26474 * @cfg {String} locationName
26475 * @cfg {Boolean} draggable default true
26476 * @cfg {Boolean} enableAutocomplete default false
26477 * @cfg {Boolean} enableReverseGeocode default true
26478 * @cfg {String} markerTitle
26481 * Create a new LocationPicker
26482 * @param {Object} config The config object
26486 Roo.bootstrap.LocationPicker = function(config){
26488 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26493 * Fires when the picker initialized.
26494 * @param {Roo.bootstrap.LocationPicker} this
26495 * @param {Google Location} location
26499 * @event positionchanged
26500 * Fires when the picker position changed.
26501 * @param {Roo.bootstrap.LocationPicker} this
26502 * @param {Google Location} location
26504 positionchanged : true,
26507 * Fires when the map resize.
26508 * @param {Roo.bootstrap.LocationPicker} this
26513 * Fires when the map show.
26514 * @param {Roo.bootstrap.LocationPicker} this
26519 * Fires when the map hide.
26520 * @param {Roo.bootstrap.LocationPicker} this
26525 * Fires when click the map.
26526 * @param {Roo.bootstrap.LocationPicker} this
26527 * @param {Map event} e
26531 * @event mapRightClick
26532 * Fires when right click the map.
26533 * @param {Roo.bootstrap.LocationPicker} this
26534 * @param {Map event} e
26536 mapRightClick : true,
26538 * @event markerClick
26539 * Fires when click the marker.
26540 * @param {Roo.bootstrap.LocationPicker} this
26541 * @param {Map event} e
26543 markerClick : true,
26545 * @event markerRightClick
26546 * Fires when right click the marker.
26547 * @param {Roo.bootstrap.LocationPicker} this
26548 * @param {Map event} e
26550 markerRightClick : true,
26552 * @event OverlayViewDraw
26553 * Fires when OverlayView Draw
26554 * @param {Roo.bootstrap.LocationPicker} this
26556 OverlayViewDraw : true,
26558 * @event OverlayViewOnAdd
26559 * Fires when OverlayView Draw
26560 * @param {Roo.bootstrap.LocationPicker} this
26562 OverlayViewOnAdd : true,
26564 * @event OverlayViewOnRemove
26565 * Fires when OverlayView Draw
26566 * @param {Roo.bootstrap.LocationPicker} this
26568 OverlayViewOnRemove : true,
26570 * @event OverlayViewShow
26571 * Fires when OverlayView Draw
26572 * @param {Roo.bootstrap.LocationPicker} this
26573 * @param {Pixel} cpx
26575 OverlayViewShow : true,
26577 * @event OverlayViewHide
26578 * Fires when OverlayView Draw
26579 * @param {Roo.bootstrap.LocationPicker} this
26581 OverlayViewHide : true,
26583 * @event loadexception
26584 * Fires when load google lib failed.
26585 * @param {Roo.bootstrap.LocationPicker} this
26587 loadexception : true
26592 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26594 gMapContext: false,
26600 mapTypeControl: false,
26601 disableDoubleClickZoom: false,
26603 streetViewControl: false,
26607 enableAutocomplete: false,
26608 enableReverseGeocode: true,
26611 getAutoCreate: function()
26616 cls: 'roo-location-picker'
26622 initEvents: function(ct, position)
26624 if(!this.el.getWidth() || this.isApplied()){
26628 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26633 initial: function()
26635 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26636 this.fireEvent('loadexception', this);
26640 if(!this.mapTypeId){
26641 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26644 this.gMapContext = this.GMapContext();
26646 this.initOverlayView();
26648 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26652 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26653 _this.setPosition(_this.gMapContext.marker.position);
26656 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26657 _this.fireEvent('mapClick', this, event);
26661 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26662 _this.fireEvent('mapRightClick', this, event);
26666 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26667 _this.fireEvent('markerClick', this, event);
26671 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26672 _this.fireEvent('markerRightClick', this, event);
26676 this.setPosition(this.gMapContext.location);
26678 this.fireEvent('initial', this, this.gMapContext.location);
26681 initOverlayView: function()
26685 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26689 _this.fireEvent('OverlayViewDraw', _this);
26694 _this.fireEvent('OverlayViewOnAdd', _this);
26697 onRemove: function()
26699 _this.fireEvent('OverlayViewOnRemove', _this);
26702 show: function(cpx)
26704 _this.fireEvent('OverlayViewShow', _this, cpx);
26709 _this.fireEvent('OverlayViewHide', _this);
26715 fromLatLngToContainerPixel: function(event)
26717 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26720 isApplied: function()
26722 return this.getGmapContext() == false ? false : true;
26725 getGmapContext: function()
26727 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26730 GMapContext: function()
26732 var position = new google.maps.LatLng(this.latitude, this.longitude);
26734 var _map = new google.maps.Map(this.el.dom, {
26737 mapTypeId: this.mapTypeId,
26738 mapTypeControl: this.mapTypeControl,
26739 disableDoubleClickZoom: this.disableDoubleClickZoom,
26740 scrollwheel: this.scrollwheel,
26741 streetViewControl: this.streetViewControl,
26742 locationName: this.locationName,
26743 draggable: this.draggable,
26744 enableAutocomplete: this.enableAutocomplete,
26745 enableReverseGeocode: this.enableReverseGeocode
26748 var _marker = new google.maps.Marker({
26749 position: position,
26751 title: this.markerTitle,
26752 draggable: this.draggable
26759 location: position,
26760 radius: this.radius,
26761 locationName: this.locationName,
26762 addressComponents: {
26763 formatted_address: null,
26764 addressLine1: null,
26765 addressLine2: null,
26767 streetNumber: null,
26771 stateOrProvince: null
26774 domContainer: this.el.dom,
26775 geodecoder: new google.maps.Geocoder()
26779 drawCircle: function(center, radius, options)
26781 if (this.gMapContext.circle != null) {
26782 this.gMapContext.circle.setMap(null);
26786 options = Roo.apply({}, options, {
26787 strokeColor: "#0000FF",
26788 strokeOpacity: .35,
26790 fillColor: "#0000FF",
26794 options.map = this.gMapContext.map;
26795 options.radius = radius;
26796 options.center = center;
26797 this.gMapContext.circle = new google.maps.Circle(options);
26798 return this.gMapContext.circle;
26804 setPosition: function(location)
26806 this.gMapContext.location = location;
26807 this.gMapContext.marker.setPosition(location);
26808 this.gMapContext.map.panTo(location);
26809 this.drawCircle(location, this.gMapContext.radius, {});
26813 if (this.gMapContext.settings.enableReverseGeocode) {
26814 this.gMapContext.geodecoder.geocode({
26815 latLng: this.gMapContext.location
26816 }, function(results, status) {
26818 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26819 _this.gMapContext.locationName = results[0].formatted_address;
26820 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26822 _this.fireEvent('positionchanged', this, location);
26829 this.fireEvent('positionchanged', this, location);
26834 google.maps.event.trigger(this.gMapContext.map, "resize");
26836 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26838 this.fireEvent('resize', this);
26841 setPositionByLatLng: function(latitude, longitude)
26843 this.setPosition(new google.maps.LatLng(latitude, longitude));
26846 getCurrentPosition: function()
26849 latitude: this.gMapContext.location.lat(),
26850 longitude: this.gMapContext.location.lng()
26854 getAddressName: function()
26856 return this.gMapContext.locationName;
26859 getAddressComponents: function()
26861 return this.gMapContext.addressComponents;
26864 address_component_from_google_geocode: function(address_components)
26868 for (var i = 0; i < address_components.length; i++) {
26869 var component = address_components[i];
26870 if (component.types.indexOf("postal_code") >= 0) {
26871 result.postalCode = component.short_name;
26872 } else if (component.types.indexOf("street_number") >= 0) {
26873 result.streetNumber = component.short_name;
26874 } else if (component.types.indexOf("route") >= 0) {
26875 result.streetName = component.short_name;
26876 } else if (component.types.indexOf("neighborhood") >= 0) {
26877 result.city = component.short_name;
26878 } else if (component.types.indexOf("locality") >= 0) {
26879 result.city = component.short_name;
26880 } else if (component.types.indexOf("sublocality") >= 0) {
26881 result.district = component.short_name;
26882 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26883 result.stateOrProvince = component.short_name;
26884 } else if (component.types.indexOf("country") >= 0) {
26885 result.country = component.short_name;
26889 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26890 result.addressLine2 = "";
26894 setZoomLevel: function(zoom)
26896 this.gMapContext.map.setZoom(zoom);
26909 this.fireEvent('show', this);
26920 this.fireEvent('hide', this);
26925 Roo.apply(Roo.bootstrap.LocationPicker, {
26927 OverlayView : function(map, options)
26929 options = options || {};
26943 * @class Roo.bootstrap.Alert
26944 * @extends Roo.bootstrap.Component
26945 * Bootstrap Alert class
26946 * @cfg {String} title The title of alert
26947 * @cfg {String} html The content of alert
26948 * @cfg {String} weight ( success | info | warning | danger )
26949 * @cfg {String} faicon font-awesomeicon
26952 * Create a new alert
26953 * @param {Object} config The config object
26957 Roo.bootstrap.Alert = function(config){
26958 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26962 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26969 getAutoCreate : function()
26978 cls : 'roo-alert-icon'
26983 cls : 'roo-alert-title',
26988 cls : 'roo-alert-text',
26995 cfg.cn[0].cls += ' fa ' + this.faicon;
26999 cfg.cls += ' alert-' + this.weight;
27005 initEvents: function()
27007 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27010 setTitle : function(str)
27012 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27015 setText : function(str)
27017 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27020 setWeight : function(weight)
27023 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27026 this.weight = weight;
27028 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27031 setIcon : function(icon)
27034 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27037 this.faicon = icon;
27039 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27060 * @class Roo.bootstrap.UploadCropbox
27061 * @extends Roo.bootstrap.Component
27062 * Bootstrap UploadCropbox class
27063 * @cfg {String} emptyText show when image has been loaded
27064 * @cfg {String} rotateNotify show when image too small to rotate
27065 * @cfg {Number} errorTimeout default 3000
27066 * @cfg {Number} minWidth default 300
27067 * @cfg {Number} minHeight default 300
27068 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27069 * @cfg {Boolean} isDocument (true|false) default false
27070 * @cfg {String} url action url
27071 * @cfg {String} paramName default 'imageUpload'
27072 * @cfg {String} method default POST
27073 * @cfg {Boolean} loadMask (true|false) default true
27074 * @cfg {Boolean} loadingText default 'Loading...'
27077 * Create a new UploadCropbox
27078 * @param {Object} config The config object
27081 Roo.bootstrap.UploadCropbox = function(config){
27082 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27086 * @event beforeselectfile
27087 * Fire before select file
27088 * @param {Roo.bootstrap.UploadCropbox} this
27090 "beforeselectfile" : true,
27093 * Fire after initEvent
27094 * @param {Roo.bootstrap.UploadCropbox} this
27099 * Fire after initEvent
27100 * @param {Roo.bootstrap.UploadCropbox} this
27101 * @param {String} data
27106 * Fire when preparing the file data
27107 * @param {Roo.bootstrap.UploadCropbox} this
27108 * @param {Object} file
27113 * Fire when get exception
27114 * @param {Roo.bootstrap.UploadCropbox} this
27115 * @param {XMLHttpRequest} xhr
27117 "exception" : true,
27119 * @event beforeloadcanvas
27120 * Fire before load the canvas
27121 * @param {Roo.bootstrap.UploadCropbox} this
27122 * @param {String} src
27124 "beforeloadcanvas" : true,
27127 * Fire when trash image
27128 * @param {Roo.bootstrap.UploadCropbox} this
27133 * Fire when download the image
27134 * @param {Roo.bootstrap.UploadCropbox} this
27138 * @event footerbuttonclick
27139 * Fire when footerbuttonclick
27140 * @param {Roo.bootstrap.UploadCropbox} this
27141 * @param {String} type
27143 "footerbuttonclick" : true,
27147 * @param {Roo.bootstrap.UploadCropbox} this
27152 * Fire when rotate the image
27153 * @param {Roo.bootstrap.UploadCropbox} this
27154 * @param {String} pos
27159 * Fire when inspect the file
27160 * @param {Roo.bootstrap.UploadCropbox} this
27161 * @param {Object} file
27166 * Fire when xhr upload the file
27167 * @param {Roo.bootstrap.UploadCropbox} this
27168 * @param {Object} data
27173 * Fire when arrange the file data
27174 * @param {Roo.bootstrap.UploadCropbox} this
27175 * @param {Object} formData
27180 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27183 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27185 emptyText : 'Click to upload image',
27186 rotateNotify : 'Image is too small to rotate',
27187 errorTimeout : 3000,
27201 cropType : 'image/jpeg',
27203 canvasLoaded : false,
27204 isDocument : false,
27206 paramName : 'imageUpload',
27208 loadingText : 'Loading...',
27211 getAutoCreate : function()
27215 cls : 'roo-upload-cropbox',
27219 cls : 'roo-upload-cropbox-selector',
27224 cls : 'roo-upload-cropbox-body',
27225 style : 'cursor:pointer',
27229 cls : 'roo-upload-cropbox-preview'
27233 cls : 'roo-upload-cropbox-thumb'
27237 cls : 'roo-upload-cropbox-empty-notify',
27238 html : this.emptyText
27242 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27243 html : this.rotateNotify
27249 cls : 'roo-upload-cropbox-footer',
27252 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27262 onRender : function(ct, position)
27264 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27266 if (this.buttons.length) {
27268 Roo.each(this.buttons, function(bb) {
27270 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27272 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27278 this.maskEl = this.el;
27282 initEvents : function()
27284 this.urlAPI = (window.createObjectURL && window) ||
27285 (window.URL && URL.revokeObjectURL && URL) ||
27286 (window.webkitURL && webkitURL);
27288 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27289 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27291 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27292 this.selectorEl.hide();
27294 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27295 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27297 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27298 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27299 this.thumbEl.hide();
27301 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27302 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27304 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27305 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27306 this.errorEl.hide();
27308 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27309 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27310 this.footerEl.hide();
27312 this.setThumbBoxSize();
27318 this.fireEvent('initial', this);
27325 window.addEventListener("resize", function() { _this.resize(); } );
27327 this.bodyEl.on('click', this.beforeSelectFile, this);
27330 this.bodyEl.on('touchstart', this.onTouchStart, this);
27331 this.bodyEl.on('touchmove', this.onTouchMove, this);
27332 this.bodyEl.on('touchend', this.onTouchEnd, this);
27336 this.bodyEl.on('mousedown', this.onMouseDown, this);
27337 this.bodyEl.on('mousemove', this.onMouseMove, this);
27338 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27339 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27340 Roo.get(document).on('mouseup', this.onMouseUp, this);
27343 this.selectorEl.on('change', this.onFileSelected, this);
27349 this.baseScale = 1;
27351 this.baseRotate = 1;
27352 this.dragable = false;
27353 this.pinching = false;
27356 this.cropData = false;
27357 this.notifyEl.dom.innerHTML = this.emptyText;
27359 this.selectorEl.dom.value = '';
27363 resize : function()
27365 if(this.fireEvent('resize', this) != false){
27366 this.setThumbBoxPosition();
27367 this.setCanvasPosition();
27371 onFooterButtonClick : function(e, el, o, type)
27374 case 'rotate-left' :
27375 this.onRotateLeft(e);
27377 case 'rotate-right' :
27378 this.onRotateRight(e);
27381 this.beforeSelectFile(e);
27396 this.fireEvent('footerbuttonclick', this, type);
27399 beforeSelectFile : function(e)
27401 e.preventDefault();
27403 if(this.fireEvent('beforeselectfile', this) != false){
27404 this.selectorEl.dom.click();
27408 onFileSelected : function(e)
27410 e.preventDefault();
27412 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27416 var file = this.selectorEl.dom.files[0];
27418 if(this.fireEvent('inspect', this, file) != false){
27419 this.prepare(file);
27424 trash : function(e)
27426 this.fireEvent('trash', this);
27429 download : function(e)
27431 this.fireEvent('download', this);
27434 loadCanvas : function(src)
27436 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27440 this.imageEl = document.createElement('img');
27444 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27446 this.imageEl.src = src;
27450 onLoadCanvas : function()
27452 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27453 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27455 this.bodyEl.un('click', this.beforeSelectFile, this);
27457 this.notifyEl.hide();
27458 this.thumbEl.show();
27459 this.footerEl.show();
27461 this.baseRotateLevel();
27463 if(this.isDocument){
27464 this.setThumbBoxSize();
27467 this.setThumbBoxPosition();
27469 this.baseScaleLevel();
27475 this.canvasLoaded = true;
27478 this.maskEl.unmask();
27483 setCanvasPosition : function()
27485 if(!this.canvasEl){
27489 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27490 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27492 this.previewEl.setLeft(pw);
27493 this.previewEl.setTop(ph);
27497 onMouseDown : function(e)
27501 this.dragable = true;
27502 this.pinching = false;
27504 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27505 this.dragable = false;
27509 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27510 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27514 onMouseMove : function(e)
27518 if(!this.canvasLoaded){
27522 if (!this.dragable){
27526 var minX = Math.ceil(this.thumbEl.getLeft(true));
27527 var minY = Math.ceil(this.thumbEl.getTop(true));
27529 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27530 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27532 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27533 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27535 x = x - this.mouseX;
27536 y = y - this.mouseY;
27538 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27539 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27541 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27542 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27544 this.previewEl.setLeft(bgX);
27545 this.previewEl.setTop(bgY);
27547 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27548 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27551 onMouseUp : function(e)
27555 this.dragable = false;
27558 onMouseWheel : function(e)
27562 this.startScale = this.scale;
27564 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27566 if(!this.zoomable()){
27567 this.scale = this.startScale;
27576 zoomable : function()
27578 var minScale = this.thumbEl.getWidth() / this.minWidth;
27580 if(this.minWidth < this.minHeight){
27581 minScale = this.thumbEl.getHeight() / this.minHeight;
27584 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27585 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27589 (this.rotate == 0 || this.rotate == 180) &&
27591 width > this.imageEl.OriginWidth ||
27592 height > this.imageEl.OriginHeight ||
27593 (width < this.minWidth && height < this.minHeight)
27601 (this.rotate == 90 || this.rotate == 270) &&
27603 width > this.imageEl.OriginWidth ||
27604 height > this.imageEl.OriginHeight ||
27605 (width < this.minHeight && height < this.minWidth)
27612 !this.isDocument &&
27613 (this.rotate == 0 || this.rotate == 180) &&
27615 width < this.minWidth ||
27616 width > this.imageEl.OriginWidth ||
27617 height < this.minHeight ||
27618 height > this.imageEl.OriginHeight
27625 !this.isDocument &&
27626 (this.rotate == 90 || this.rotate == 270) &&
27628 width < this.minHeight ||
27629 width > this.imageEl.OriginWidth ||
27630 height < this.minWidth ||
27631 height > this.imageEl.OriginHeight
27641 onRotateLeft : function(e)
27643 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27645 var minScale = this.thumbEl.getWidth() / this.minWidth;
27647 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27648 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27650 this.startScale = this.scale;
27652 while (this.getScaleLevel() < minScale){
27654 this.scale = this.scale + 1;
27656 if(!this.zoomable()){
27661 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27662 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27667 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27674 this.scale = this.startScale;
27676 this.onRotateFail();
27681 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27683 if(this.isDocument){
27684 this.setThumbBoxSize();
27685 this.setThumbBoxPosition();
27686 this.setCanvasPosition();
27691 this.fireEvent('rotate', this, 'left');
27695 onRotateRight : function(e)
27697 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27699 var minScale = this.thumbEl.getWidth() / this.minWidth;
27701 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27702 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27704 this.startScale = this.scale;
27706 while (this.getScaleLevel() < minScale){
27708 this.scale = this.scale + 1;
27710 if(!this.zoomable()){
27715 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27716 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27721 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27728 this.scale = this.startScale;
27730 this.onRotateFail();
27735 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27737 if(this.isDocument){
27738 this.setThumbBoxSize();
27739 this.setThumbBoxPosition();
27740 this.setCanvasPosition();
27745 this.fireEvent('rotate', this, 'right');
27748 onRotateFail : function()
27750 this.errorEl.show(true);
27754 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27759 this.previewEl.dom.innerHTML = '';
27761 var canvasEl = document.createElement("canvas");
27763 var contextEl = canvasEl.getContext("2d");
27765 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27766 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27767 var center = this.imageEl.OriginWidth / 2;
27769 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27770 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27771 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27772 center = this.imageEl.OriginHeight / 2;
27775 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27777 contextEl.translate(center, center);
27778 contextEl.rotate(this.rotate * Math.PI / 180);
27780 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27782 this.canvasEl = document.createElement("canvas");
27784 this.contextEl = this.canvasEl.getContext("2d");
27786 switch (this.rotate) {
27789 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27790 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27792 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27797 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27798 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27800 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27801 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);
27805 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27810 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27811 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27813 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27814 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);
27818 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);
27823 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27824 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27826 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27827 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27831 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);
27838 this.previewEl.appendChild(this.canvasEl);
27840 this.setCanvasPosition();
27845 if(!this.canvasLoaded){
27849 var imageCanvas = document.createElement("canvas");
27851 var imageContext = imageCanvas.getContext("2d");
27853 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27854 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27856 var center = imageCanvas.width / 2;
27858 imageContext.translate(center, center);
27860 imageContext.rotate(this.rotate * Math.PI / 180);
27862 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27864 var canvas = document.createElement("canvas");
27866 var context = canvas.getContext("2d");
27868 canvas.width = this.minWidth;
27869 canvas.height = this.minHeight;
27871 switch (this.rotate) {
27874 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27875 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27877 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27878 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27880 var targetWidth = this.minWidth - 2 * x;
27881 var targetHeight = this.minHeight - 2 * y;
27885 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27886 scale = targetWidth / width;
27889 if(x > 0 && y == 0){
27890 scale = targetHeight / height;
27893 if(x > 0 && y > 0){
27894 scale = targetWidth / width;
27896 if(width < height){
27897 scale = targetHeight / height;
27901 context.scale(scale, scale);
27903 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27904 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27906 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27907 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27909 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27914 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27915 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27917 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27918 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27920 var targetWidth = this.minWidth - 2 * x;
27921 var targetHeight = this.minHeight - 2 * y;
27925 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27926 scale = targetWidth / width;
27929 if(x > 0 && y == 0){
27930 scale = targetHeight / height;
27933 if(x > 0 && y > 0){
27934 scale = targetWidth / width;
27936 if(width < height){
27937 scale = targetHeight / height;
27941 context.scale(scale, scale);
27943 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27944 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27946 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27947 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27949 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27951 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27956 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27957 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27959 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27960 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27962 var targetWidth = this.minWidth - 2 * x;
27963 var targetHeight = this.minHeight - 2 * y;
27967 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27968 scale = targetWidth / width;
27971 if(x > 0 && y == 0){
27972 scale = targetHeight / height;
27975 if(x > 0 && y > 0){
27976 scale = targetWidth / width;
27978 if(width < height){
27979 scale = targetHeight / height;
27983 context.scale(scale, scale);
27985 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27986 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27988 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27989 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27991 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27992 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27994 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27999 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28000 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28002 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28003 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28005 var targetWidth = this.minWidth - 2 * x;
28006 var targetHeight = this.minHeight - 2 * y;
28010 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28011 scale = targetWidth / width;
28014 if(x > 0 && y == 0){
28015 scale = targetHeight / height;
28018 if(x > 0 && y > 0){
28019 scale = targetWidth / width;
28021 if(width < height){
28022 scale = targetHeight / height;
28026 context.scale(scale, scale);
28028 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28029 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28031 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28032 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28034 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28036 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28043 this.cropData = canvas.toDataURL(this.cropType);
28045 if(this.fireEvent('crop', this, this.cropData) !== false){
28046 this.process(this.file, this.cropData);
28053 setThumbBoxSize : function()
28057 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28058 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28059 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28061 this.minWidth = width;
28062 this.minHeight = height;
28064 if(this.rotate == 90 || this.rotate == 270){
28065 this.minWidth = height;
28066 this.minHeight = width;
28071 width = Math.ceil(this.minWidth * height / this.minHeight);
28073 if(this.minWidth > this.minHeight){
28075 height = Math.ceil(this.minHeight * width / this.minWidth);
28078 this.thumbEl.setStyle({
28079 width : width + 'px',
28080 height : height + 'px'
28087 setThumbBoxPosition : function()
28089 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28090 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28092 this.thumbEl.setLeft(x);
28093 this.thumbEl.setTop(y);
28097 baseRotateLevel : function()
28099 this.baseRotate = 1;
28102 typeof(this.exif) != 'undefined' &&
28103 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28104 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28106 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28109 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28113 baseScaleLevel : function()
28117 if(this.isDocument){
28119 if(this.baseRotate == 6 || this.baseRotate == 8){
28121 height = this.thumbEl.getHeight();
28122 this.baseScale = height / this.imageEl.OriginWidth;
28124 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28125 width = this.thumbEl.getWidth();
28126 this.baseScale = width / this.imageEl.OriginHeight;
28132 height = this.thumbEl.getHeight();
28133 this.baseScale = height / this.imageEl.OriginHeight;
28135 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28136 width = this.thumbEl.getWidth();
28137 this.baseScale = width / this.imageEl.OriginWidth;
28143 if(this.baseRotate == 6 || this.baseRotate == 8){
28145 width = this.thumbEl.getHeight();
28146 this.baseScale = width / this.imageEl.OriginHeight;
28148 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28149 height = this.thumbEl.getWidth();
28150 this.baseScale = height / this.imageEl.OriginHeight;
28153 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28154 height = this.thumbEl.getWidth();
28155 this.baseScale = height / this.imageEl.OriginHeight;
28157 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28158 width = this.thumbEl.getHeight();
28159 this.baseScale = width / this.imageEl.OriginWidth;
28166 width = this.thumbEl.getWidth();
28167 this.baseScale = width / this.imageEl.OriginWidth;
28169 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28170 height = this.thumbEl.getHeight();
28171 this.baseScale = height / this.imageEl.OriginHeight;
28174 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28176 height = this.thumbEl.getHeight();
28177 this.baseScale = height / this.imageEl.OriginHeight;
28179 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28180 width = this.thumbEl.getWidth();
28181 this.baseScale = width / this.imageEl.OriginWidth;
28189 getScaleLevel : function()
28191 return this.baseScale * Math.pow(1.1, this.scale);
28194 onTouchStart : function(e)
28196 if(!this.canvasLoaded){
28197 this.beforeSelectFile(e);
28201 var touches = e.browserEvent.touches;
28207 if(touches.length == 1){
28208 this.onMouseDown(e);
28212 if(touches.length != 2){
28218 for(var i = 0, finger; finger = touches[i]; i++){
28219 coords.push(finger.pageX, finger.pageY);
28222 var x = Math.pow(coords[0] - coords[2], 2);
28223 var y = Math.pow(coords[1] - coords[3], 2);
28225 this.startDistance = Math.sqrt(x + y);
28227 this.startScale = this.scale;
28229 this.pinching = true;
28230 this.dragable = false;
28234 onTouchMove : function(e)
28236 if(!this.pinching && !this.dragable){
28240 var touches = e.browserEvent.touches;
28247 this.onMouseMove(e);
28253 for(var i = 0, finger; finger = touches[i]; i++){
28254 coords.push(finger.pageX, finger.pageY);
28257 var x = Math.pow(coords[0] - coords[2], 2);
28258 var y = Math.pow(coords[1] - coords[3], 2);
28260 this.endDistance = Math.sqrt(x + y);
28262 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28264 if(!this.zoomable()){
28265 this.scale = this.startScale;
28273 onTouchEnd : function(e)
28275 this.pinching = false;
28276 this.dragable = false;
28280 process : function(file, crop)
28283 this.maskEl.mask(this.loadingText);
28286 this.xhr = new XMLHttpRequest();
28288 file.xhr = this.xhr;
28290 this.xhr.open(this.method, this.url, true);
28293 "Accept": "application/json",
28294 "Cache-Control": "no-cache",
28295 "X-Requested-With": "XMLHttpRequest"
28298 for (var headerName in headers) {
28299 var headerValue = headers[headerName];
28301 this.xhr.setRequestHeader(headerName, headerValue);
28307 this.xhr.onload = function()
28309 _this.xhrOnLoad(_this.xhr);
28312 this.xhr.onerror = function()
28314 _this.xhrOnError(_this.xhr);
28317 var formData = new FormData();
28319 formData.append('returnHTML', 'NO');
28322 formData.append('crop', crop);
28325 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28326 formData.append(this.paramName, file, file.name);
28329 if(typeof(file.filename) != 'undefined'){
28330 formData.append('filename', file.filename);
28333 if(typeof(file.mimetype) != 'undefined'){
28334 formData.append('mimetype', file.mimetype);
28337 if(this.fireEvent('arrange', this, formData) != false){
28338 this.xhr.send(formData);
28342 xhrOnLoad : function(xhr)
28345 this.maskEl.unmask();
28348 if (xhr.readyState !== 4) {
28349 this.fireEvent('exception', this, xhr);
28353 var response = Roo.decode(xhr.responseText);
28355 if(!response.success){
28356 this.fireEvent('exception', this, xhr);
28360 var response = Roo.decode(xhr.responseText);
28362 this.fireEvent('upload', this, response);
28366 xhrOnError : function()
28369 this.maskEl.unmask();
28372 Roo.log('xhr on error');
28374 var response = Roo.decode(xhr.responseText);
28380 prepare : function(file)
28383 this.maskEl.mask(this.loadingText);
28389 if(typeof(file) === 'string'){
28390 this.loadCanvas(file);
28394 if(!file || !this.urlAPI){
28399 this.cropType = file.type;
28403 if(this.fireEvent('prepare', this, this.file) != false){
28405 var reader = new FileReader();
28407 reader.onload = function (e) {
28408 if (e.target.error) {
28409 Roo.log(e.target.error);
28413 var buffer = e.target.result,
28414 dataView = new DataView(buffer),
28416 maxOffset = dataView.byteLength - 4,
28420 if (dataView.getUint16(0) === 0xffd8) {
28421 while (offset < maxOffset) {
28422 markerBytes = dataView.getUint16(offset);
28424 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28425 markerLength = dataView.getUint16(offset + 2) + 2;
28426 if (offset + markerLength > dataView.byteLength) {
28427 Roo.log('Invalid meta data: Invalid segment size.');
28431 if(markerBytes == 0xffe1){
28432 _this.parseExifData(
28439 offset += markerLength;
28449 var url = _this.urlAPI.createObjectURL(_this.file);
28451 _this.loadCanvas(url);
28456 reader.readAsArrayBuffer(this.file);
28462 parseExifData : function(dataView, offset, length)
28464 var tiffOffset = offset + 10,
28468 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28469 // No Exif data, might be XMP data instead
28473 // Check for the ASCII code for "Exif" (0x45786966):
28474 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28475 // No Exif data, might be XMP data instead
28478 if (tiffOffset + 8 > dataView.byteLength) {
28479 Roo.log('Invalid Exif data: Invalid segment size.');
28482 // Check for the two null bytes:
28483 if (dataView.getUint16(offset + 8) !== 0x0000) {
28484 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28487 // Check the byte alignment:
28488 switch (dataView.getUint16(tiffOffset)) {
28490 littleEndian = true;
28493 littleEndian = false;
28496 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28499 // Check for the TIFF tag marker (0x002A):
28500 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28501 Roo.log('Invalid Exif data: Missing TIFF marker.');
28504 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28505 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28507 this.parseExifTags(
28510 tiffOffset + dirOffset,
28515 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28520 if (dirOffset + 6 > dataView.byteLength) {
28521 Roo.log('Invalid Exif data: Invalid directory offset.');
28524 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28525 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28526 if (dirEndOffset + 4 > dataView.byteLength) {
28527 Roo.log('Invalid Exif data: Invalid directory size.');
28530 for (i = 0; i < tagsNumber; i += 1) {
28534 dirOffset + 2 + 12 * i, // tag offset
28538 // Return the offset to the next directory:
28539 return dataView.getUint32(dirEndOffset, littleEndian);
28542 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28544 var tag = dataView.getUint16(offset, littleEndian);
28546 this.exif[tag] = this.getExifValue(
28550 dataView.getUint16(offset + 2, littleEndian), // tag type
28551 dataView.getUint32(offset + 4, littleEndian), // tag length
28556 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28558 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28567 Roo.log('Invalid Exif data: Invalid tag type.');
28571 tagSize = tagType.size * length;
28572 // Determine if the value is contained in the dataOffset bytes,
28573 // or if the value at the dataOffset is a pointer to the actual data:
28574 dataOffset = tagSize > 4 ?
28575 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28576 if (dataOffset + tagSize > dataView.byteLength) {
28577 Roo.log('Invalid Exif data: Invalid data offset.');
28580 if (length === 1) {
28581 return tagType.getValue(dataView, dataOffset, littleEndian);
28584 for (i = 0; i < length; i += 1) {
28585 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28588 if (tagType.ascii) {
28590 // Concatenate the chars:
28591 for (i = 0; i < values.length; i += 1) {
28593 // Ignore the terminating NULL byte(s):
28594 if (c === '\u0000') {
28606 Roo.apply(Roo.bootstrap.UploadCropbox, {
28608 'Orientation': 0x0112
28612 1: 0, //'top-left',
28614 3: 180, //'bottom-right',
28615 // 4: 'bottom-left',
28617 6: 90, //'right-top',
28618 // 7: 'right-bottom',
28619 8: 270 //'left-bottom'
28623 // byte, 8-bit unsigned int:
28625 getValue: function (dataView, dataOffset) {
28626 return dataView.getUint8(dataOffset);
28630 // ascii, 8-bit byte:
28632 getValue: function (dataView, dataOffset) {
28633 return String.fromCharCode(dataView.getUint8(dataOffset));
28638 // short, 16 bit int:
28640 getValue: function (dataView, dataOffset, littleEndian) {
28641 return dataView.getUint16(dataOffset, littleEndian);
28645 // long, 32 bit int:
28647 getValue: function (dataView, dataOffset, littleEndian) {
28648 return dataView.getUint32(dataOffset, littleEndian);
28652 // rational = two long values, first is numerator, second is denominator:
28654 getValue: function (dataView, dataOffset, littleEndian) {
28655 return dataView.getUint32(dataOffset, littleEndian) /
28656 dataView.getUint32(dataOffset + 4, littleEndian);
28660 // slong, 32 bit signed int:
28662 getValue: function (dataView, dataOffset, littleEndian) {
28663 return dataView.getInt32(dataOffset, littleEndian);
28667 // srational, two slongs, first is numerator, second is denominator:
28669 getValue: function (dataView, dataOffset, littleEndian) {
28670 return dataView.getInt32(dataOffset, littleEndian) /
28671 dataView.getInt32(dataOffset + 4, littleEndian);
28681 cls : 'btn-group roo-upload-cropbox-rotate-left',
28682 action : 'rotate-left',
28686 cls : 'btn btn-default',
28687 html : '<i class="fa fa-undo"></i>'
28693 cls : 'btn-group roo-upload-cropbox-picture',
28694 action : 'picture',
28698 cls : 'btn btn-default',
28699 html : '<i class="fa fa-picture-o"></i>'
28705 cls : 'btn-group roo-upload-cropbox-rotate-right',
28706 action : 'rotate-right',
28710 cls : 'btn btn-default',
28711 html : '<i class="fa fa-repeat"></i>'
28719 cls : 'btn-group roo-upload-cropbox-rotate-left',
28720 action : 'rotate-left',
28724 cls : 'btn btn-default',
28725 html : '<i class="fa fa-undo"></i>'
28731 cls : 'btn-group roo-upload-cropbox-download',
28732 action : 'download',
28736 cls : 'btn btn-default',
28737 html : '<i class="fa fa-download"></i>'
28743 cls : 'btn-group roo-upload-cropbox-crop',
28748 cls : 'btn btn-default',
28749 html : '<i class="fa fa-crop"></i>'
28755 cls : 'btn-group roo-upload-cropbox-trash',
28760 cls : 'btn btn-default',
28761 html : '<i class="fa fa-trash"></i>'
28767 cls : 'btn-group roo-upload-cropbox-rotate-right',
28768 action : 'rotate-right',
28772 cls : 'btn btn-default',
28773 html : '<i class="fa fa-repeat"></i>'
28781 cls : 'btn-group roo-upload-cropbox-rotate-left',
28782 action : 'rotate-left',
28786 cls : 'btn btn-default',
28787 html : '<i class="fa fa-undo"></i>'
28793 cls : 'btn-group roo-upload-cropbox-rotate-right',
28794 action : 'rotate-right',
28798 cls : 'btn btn-default',
28799 html : '<i class="fa fa-repeat"></i>'
28812 * @class Roo.bootstrap.DocumentManager
28813 * @extends Roo.bootstrap.Component
28814 * Bootstrap DocumentManager class
28815 * @cfg {String} paramName default 'imageUpload'
28816 * @cfg {String} toolTipName default 'filename'
28817 * @cfg {String} method default POST
28818 * @cfg {String} url action url
28819 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28820 * @cfg {Boolean} multiple multiple upload default true
28821 * @cfg {Number} thumbSize default 300
28822 * @cfg {String} fieldLabel
28823 * @cfg {Number} labelWidth default 4
28824 * @cfg {String} labelAlign (left|top) default left
28825 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28826 * @cfg {Number} labellg set the width of label (1-12)
28827 * @cfg {Number} labelmd set the width of label (1-12)
28828 * @cfg {Number} labelsm set the width of label (1-12)
28829 * @cfg {Number} labelxs set the width of label (1-12)
28832 * Create a new DocumentManager
28833 * @param {Object} config The config object
28836 Roo.bootstrap.DocumentManager = function(config){
28837 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28840 this.delegates = [];
28845 * Fire when initial the DocumentManager
28846 * @param {Roo.bootstrap.DocumentManager} this
28851 * inspect selected file
28852 * @param {Roo.bootstrap.DocumentManager} this
28853 * @param {File} file
28858 * Fire when xhr load exception
28859 * @param {Roo.bootstrap.DocumentManager} this
28860 * @param {XMLHttpRequest} xhr
28862 "exception" : true,
28864 * @event afterupload
28865 * Fire when xhr load exception
28866 * @param {Roo.bootstrap.DocumentManager} this
28867 * @param {XMLHttpRequest} xhr
28869 "afterupload" : true,
28872 * prepare the form data
28873 * @param {Roo.bootstrap.DocumentManager} this
28874 * @param {Object} formData
28879 * Fire when remove the file
28880 * @param {Roo.bootstrap.DocumentManager} this
28881 * @param {Object} file
28886 * Fire after refresh the file
28887 * @param {Roo.bootstrap.DocumentManager} this
28892 * Fire after click the image
28893 * @param {Roo.bootstrap.DocumentManager} this
28894 * @param {Object} file
28899 * Fire when upload a image and editable set to true
28900 * @param {Roo.bootstrap.DocumentManager} this
28901 * @param {Object} file
28905 * @event beforeselectfile
28906 * Fire before select file
28907 * @param {Roo.bootstrap.DocumentManager} this
28909 "beforeselectfile" : true,
28912 * Fire before process file
28913 * @param {Roo.bootstrap.DocumentManager} this
28914 * @param {Object} file
28918 * @event previewrendered
28919 * Fire when preview rendered
28920 * @param {Roo.bootstrap.DocumentManager} this
28921 * @param {Object} file
28923 "previewrendered" : true,
28926 "previewResize" : true
28931 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28940 paramName : 'imageUpload',
28941 toolTipName : 'filename',
28944 labelAlign : 'left',
28954 getAutoCreate : function()
28956 var managerWidget = {
28958 cls : 'roo-document-manager',
28962 cls : 'roo-document-manager-selector',
28967 cls : 'roo-document-manager-uploader',
28971 cls : 'roo-document-manager-upload-btn',
28972 html : '<i class="fa fa-plus"></i>'
28983 cls : 'column col-md-12',
28988 if(this.fieldLabel.length){
28993 cls : 'column col-md-12',
28994 html : this.fieldLabel
28998 cls : 'column col-md-12',
29003 if(this.labelAlign == 'left'){
29008 html : this.fieldLabel
29017 if(this.labelWidth > 12){
29018 content[0].style = "width: " + this.labelWidth + 'px';
29021 if(this.labelWidth < 13 && this.labelmd == 0){
29022 this.labelmd = this.labelWidth;
29025 if(this.labellg > 0){
29026 content[0].cls += ' col-lg-' + this.labellg;
29027 content[1].cls += ' col-lg-' + (12 - this.labellg);
29030 if(this.labelmd > 0){
29031 content[0].cls += ' col-md-' + this.labelmd;
29032 content[1].cls += ' col-md-' + (12 - this.labelmd);
29035 if(this.labelsm > 0){
29036 content[0].cls += ' col-sm-' + this.labelsm;
29037 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29040 if(this.labelxs > 0){
29041 content[0].cls += ' col-xs-' + this.labelxs;
29042 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29050 cls : 'row clearfix',
29058 initEvents : function()
29060 this.managerEl = this.el.select('.roo-document-manager', true).first();
29061 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29063 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29064 this.selectorEl.hide();
29067 this.selectorEl.attr('multiple', 'multiple');
29070 this.selectorEl.on('change', this.onFileSelected, this);
29072 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29073 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29075 this.uploader.on('click', this.onUploaderClick, this);
29077 this.renderProgressDialog();
29081 window.addEventListener("resize", function() { _this.refresh(); } );
29083 this.fireEvent('initial', this);
29086 renderProgressDialog : function()
29090 this.progressDialog = new Roo.bootstrap.Modal({
29091 cls : 'roo-document-manager-progress-dialog',
29092 allow_close : false,
29102 btnclick : function() {
29103 _this.uploadCancel();
29109 this.progressDialog.render(Roo.get(document.body));
29111 this.progress = new Roo.bootstrap.Progress({
29112 cls : 'roo-document-manager-progress',
29117 this.progress.render(this.progressDialog.getChildContainer());
29119 this.progressBar = new Roo.bootstrap.ProgressBar({
29120 cls : 'roo-document-manager-progress-bar',
29123 aria_valuemax : 12,
29127 this.progressBar.render(this.progress.getChildContainer());
29130 onUploaderClick : function(e)
29132 e.preventDefault();
29134 if(this.fireEvent('beforeselectfile', this) != false){
29135 this.selectorEl.dom.click();
29140 onFileSelected : function(e)
29142 e.preventDefault();
29144 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29148 Roo.each(this.selectorEl.dom.files, function(file){
29149 if(this.fireEvent('inspect', this, file) != false){
29150 this.files.push(file);
29160 this.selectorEl.dom.value = '';
29162 if(!this.files || !this.files.length){
29166 if(this.boxes > 0 && this.files.length > this.boxes){
29167 this.files = this.files.slice(0, this.boxes);
29170 this.uploader.show();
29172 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29173 this.uploader.hide();
29182 Roo.each(this.files, function(file){
29184 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29185 var f = this.renderPreview(file);
29190 if(file.type.indexOf('image') != -1){
29191 this.delegates.push(
29193 _this.process(file);
29194 }).createDelegate(this)
29202 _this.process(file);
29203 }).createDelegate(this)
29208 this.files = files;
29210 this.delegates = this.delegates.concat(docs);
29212 if(!this.delegates.length){
29217 this.progressBar.aria_valuemax = this.delegates.length;
29224 arrange : function()
29226 if(!this.delegates.length){
29227 this.progressDialog.hide();
29232 var delegate = this.delegates.shift();
29234 this.progressDialog.show();
29236 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29238 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29243 refresh : function()
29245 this.uploader.show();
29247 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29248 this.uploader.hide();
29251 Roo.isTouch ? this.closable(false) : this.closable(true);
29253 this.fireEvent('refresh', this);
29256 onRemove : function(e, el, o)
29258 e.preventDefault();
29260 this.fireEvent('remove', this, o);
29264 remove : function(o)
29268 Roo.each(this.files, function(file){
29269 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29278 this.files = files;
29285 Roo.each(this.files, function(file){
29290 file.target.remove();
29299 onClick : function(e, el, o)
29301 e.preventDefault();
29303 this.fireEvent('click', this, o);
29307 closable : function(closable)
29309 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29311 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29323 xhrOnLoad : function(xhr)
29325 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29329 if (xhr.readyState !== 4) {
29331 this.fireEvent('exception', this, xhr);
29335 var response = Roo.decode(xhr.responseText);
29337 if(!response.success){
29339 this.fireEvent('exception', this, xhr);
29343 var file = this.renderPreview(response.data);
29345 this.files.push(file);
29349 this.fireEvent('afterupload', this, xhr);
29353 xhrOnError : function(xhr)
29355 Roo.log('xhr on error');
29357 var response = Roo.decode(xhr.responseText);
29364 process : function(file)
29366 if(this.fireEvent('process', this, file) !== false){
29367 if(this.editable && file.type.indexOf('image') != -1){
29368 this.fireEvent('edit', this, file);
29372 this.uploadStart(file, false);
29379 uploadStart : function(file, crop)
29381 this.xhr = new XMLHttpRequest();
29383 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29388 file.xhr = this.xhr;
29390 this.managerEl.createChild({
29392 cls : 'roo-document-manager-loading',
29396 tooltip : file.name,
29397 cls : 'roo-document-manager-thumb',
29398 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29404 this.xhr.open(this.method, this.url, true);
29407 "Accept": "application/json",
29408 "Cache-Control": "no-cache",
29409 "X-Requested-With": "XMLHttpRequest"
29412 for (var headerName in headers) {
29413 var headerValue = headers[headerName];
29415 this.xhr.setRequestHeader(headerName, headerValue);
29421 this.xhr.onload = function()
29423 _this.xhrOnLoad(_this.xhr);
29426 this.xhr.onerror = function()
29428 _this.xhrOnError(_this.xhr);
29431 var formData = new FormData();
29433 formData.append('returnHTML', 'NO');
29436 formData.append('crop', crop);
29439 formData.append(this.paramName, file, file.name);
29446 if(this.fireEvent('prepare', this, formData, options) != false){
29448 if(options.manually){
29452 this.xhr.send(formData);
29456 this.uploadCancel();
29459 uploadCancel : function()
29465 this.delegates = [];
29467 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29474 renderPreview : function(file)
29476 if(typeof(file.target) != 'undefined' && file.target){
29480 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29482 var previewEl = this.managerEl.createChild({
29484 cls : 'roo-document-manager-preview',
29488 tooltip : file[this.toolTipName],
29489 cls : 'roo-document-manager-thumb',
29490 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29495 html : '<i class="fa fa-times-circle"></i>'
29500 var close = previewEl.select('button.close', true).first();
29502 close.on('click', this.onRemove, this, file);
29504 file.target = previewEl;
29506 var image = previewEl.select('img', true).first();
29510 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29512 image.on('click', this.onClick, this, file);
29514 this.fireEvent('previewrendered', this, file);
29520 onPreviewLoad : function(file, image)
29522 if(typeof(file.target) == 'undefined' || !file.target){
29526 var width = image.dom.naturalWidth || image.dom.width;
29527 var height = image.dom.naturalHeight || image.dom.height;
29529 if(!this.previewResize) {
29533 if(width > height){
29534 file.target.addClass('wide');
29538 file.target.addClass('tall');
29543 uploadFromSource : function(file, crop)
29545 this.xhr = new XMLHttpRequest();
29547 this.managerEl.createChild({
29549 cls : 'roo-document-manager-loading',
29553 tooltip : file.name,
29554 cls : 'roo-document-manager-thumb',
29555 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29561 this.xhr.open(this.method, this.url, true);
29564 "Accept": "application/json",
29565 "Cache-Control": "no-cache",
29566 "X-Requested-With": "XMLHttpRequest"
29569 for (var headerName in headers) {
29570 var headerValue = headers[headerName];
29572 this.xhr.setRequestHeader(headerName, headerValue);
29578 this.xhr.onload = function()
29580 _this.xhrOnLoad(_this.xhr);
29583 this.xhr.onerror = function()
29585 _this.xhrOnError(_this.xhr);
29588 var formData = new FormData();
29590 formData.append('returnHTML', 'NO');
29592 formData.append('crop', crop);
29594 if(typeof(file.filename) != 'undefined'){
29595 formData.append('filename', file.filename);
29598 if(typeof(file.mimetype) != 'undefined'){
29599 formData.append('mimetype', file.mimetype);
29604 if(this.fireEvent('prepare', this, formData) != false){
29605 this.xhr.send(formData);
29615 * @class Roo.bootstrap.DocumentViewer
29616 * @extends Roo.bootstrap.Component
29617 * Bootstrap DocumentViewer class
29618 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29619 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29622 * Create a new DocumentViewer
29623 * @param {Object} config The config object
29626 Roo.bootstrap.DocumentViewer = function(config){
29627 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29632 * Fire after initEvent
29633 * @param {Roo.bootstrap.DocumentViewer} this
29639 * @param {Roo.bootstrap.DocumentViewer} this
29644 * Fire after download button
29645 * @param {Roo.bootstrap.DocumentViewer} this
29650 * Fire after trash button
29651 * @param {Roo.bootstrap.DocumentViewer} this
29658 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29660 showDownload : true,
29664 getAutoCreate : function()
29668 cls : 'roo-document-viewer',
29672 cls : 'roo-document-viewer-body',
29676 cls : 'roo-document-viewer-thumb',
29680 cls : 'roo-document-viewer-image'
29688 cls : 'roo-document-viewer-footer',
29691 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29695 cls : 'btn-group roo-document-viewer-download',
29699 cls : 'btn btn-default',
29700 html : '<i class="fa fa-download"></i>'
29706 cls : 'btn-group roo-document-viewer-trash',
29710 cls : 'btn btn-default',
29711 html : '<i class="fa fa-trash"></i>'
29724 initEvents : function()
29726 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29727 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29729 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29730 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29732 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29733 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29735 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29736 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29738 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29739 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29741 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29742 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29744 this.bodyEl.on('click', this.onClick, this);
29745 this.downloadBtn.on('click', this.onDownload, this);
29746 this.trashBtn.on('click', this.onTrash, this);
29748 this.downloadBtn.hide();
29749 this.trashBtn.hide();
29751 if(this.showDownload){
29752 this.downloadBtn.show();
29755 if(this.showTrash){
29756 this.trashBtn.show();
29759 if(!this.showDownload && !this.showTrash) {
29760 this.footerEl.hide();
29765 initial : function()
29767 this.fireEvent('initial', this);
29771 onClick : function(e)
29773 e.preventDefault();
29775 this.fireEvent('click', this);
29778 onDownload : function(e)
29780 e.preventDefault();
29782 this.fireEvent('download', this);
29785 onTrash : function(e)
29787 e.preventDefault();
29789 this.fireEvent('trash', this);
29801 * @class Roo.bootstrap.NavProgressBar
29802 * @extends Roo.bootstrap.Component
29803 * Bootstrap NavProgressBar class
29806 * Create a new nav progress bar
29807 * @param {Object} config The config object
29810 Roo.bootstrap.NavProgressBar = function(config){
29811 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29813 this.bullets = this.bullets || [];
29815 // Roo.bootstrap.NavProgressBar.register(this);
29819 * Fires when the active item changes
29820 * @param {Roo.bootstrap.NavProgressBar} this
29821 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29822 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29829 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29834 getAutoCreate : function()
29836 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29840 cls : 'roo-navigation-bar-group',
29844 cls : 'roo-navigation-top-bar'
29848 cls : 'roo-navigation-bullets-bar',
29852 cls : 'roo-navigation-bar'
29859 cls : 'roo-navigation-bottom-bar'
29869 initEvents: function()
29874 onRender : function(ct, position)
29876 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29878 if(this.bullets.length){
29879 Roo.each(this.bullets, function(b){
29888 addItem : function(cfg)
29890 var item = new Roo.bootstrap.NavProgressItem(cfg);
29892 item.parentId = this.id;
29893 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29896 var top = new Roo.bootstrap.Element({
29898 cls : 'roo-navigation-bar-text'
29901 var bottom = new Roo.bootstrap.Element({
29903 cls : 'roo-navigation-bar-text'
29906 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29907 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29909 var topText = new Roo.bootstrap.Element({
29911 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29914 var bottomText = new Roo.bootstrap.Element({
29916 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29919 topText.onRender(top.el, null);
29920 bottomText.onRender(bottom.el, null);
29923 item.bottomEl = bottom;
29926 this.barItems.push(item);
29931 getActive : function()
29933 var active = false;
29935 Roo.each(this.barItems, function(v){
29937 if (!v.isActive()) {
29949 setActiveItem : function(item)
29953 Roo.each(this.barItems, function(v){
29954 if (v.rid == item.rid) {
29958 if (v.isActive()) {
29959 v.setActive(false);
29964 item.setActive(true);
29966 this.fireEvent('changed', this, item, prev);
29969 getBarItem: function(rid)
29973 Roo.each(this.barItems, function(e) {
29974 if (e.rid != rid) {
29985 indexOfItem : function(item)
29989 Roo.each(this.barItems, function(v, i){
29991 if (v.rid != item.rid) {
30002 setActiveNext : function()
30004 var i = this.indexOfItem(this.getActive());
30006 if (i > this.barItems.length) {
30010 this.setActiveItem(this.barItems[i+1]);
30013 setActivePrev : function()
30015 var i = this.indexOfItem(this.getActive());
30021 this.setActiveItem(this.barItems[i-1]);
30024 format : function()
30026 if(!this.barItems.length){
30030 var width = 100 / this.barItems.length;
30032 Roo.each(this.barItems, function(i){
30033 i.el.setStyle('width', width + '%');
30034 i.topEl.el.setStyle('width', width + '%');
30035 i.bottomEl.el.setStyle('width', width + '%');
30044 * Nav Progress Item
30049 * @class Roo.bootstrap.NavProgressItem
30050 * @extends Roo.bootstrap.Component
30051 * Bootstrap NavProgressItem class
30052 * @cfg {String} rid the reference id
30053 * @cfg {Boolean} active (true|false) Is item active default false
30054 * @cfg {Boolean} disabled (true|false) Is item active default false
30055 * @cfg {String} html
30056 * @cfg {String} position (top|bottom) text position default bottom
30057 * @cfg {String} icon show icon instead of number
30060 * Create a new NavProgressItem
30061 * @param {Object} config The config object
30063 Roo.bootstrap.NavProgressItem = function(config){
30064 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30069 * The raw click event for the entire grid.
30070 * @param {Roo.bootstrap.NavProgressItem} this
30071 * @param {Roo.EventObject} e
30078 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30084 position : 'bottom',
30087 getAutoCreate : function()
30089 var iconCls = 'roo-navigation-bar-item-icon';
30091 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30095 cls: 'roo-navigation-bar-item',
30105 cfg.cls += ' active';
30108 cfg.cls += ' disabled';
30114 disable : function()
30116 this.setDisabled(true);
30119 enable : function()
30121 this.setDisabled(false);
30124 initEvents: function()
30126 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30128 this.iconEl.on('click', this.onClick, this);
30131 onClick : function(e)
30133 e.preventDefault();
30139 if(this.fireEvent('click', this, e) === false){
30143 this.parent().setActiveItem(this);
30146 isActive: function ()
30148 return this.active;
30151 setActive : function(state)
30153 if(this.active == state){
30157 this.active = state;
30160 this.el.addClass('active');
30164 this.el.removeClass('active');
30169 setDisabled : function(state)
30171 if(this.disabled == state){
30175 this.disabled = state;
30178 this.el.addClass('disabled');
30182 this.el.removeClass('disabled');
30185 tooltipEl : function()
30187 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30200 * @class Roo.bootstrap.FieldLabel
30201 * @extends Roo.bootstrap.Component
30202 * Bootstrap FieldLabel class
30203 * @cfg {String} html contents of the element
30204 * @cfg {String} tag tag of the element default label
30205 * @cfg {String} cls class of the element
30206 * @cfg {String} target label target
30207 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30208 * @cfg {String} invalidClass default "text-warning"
30209 * @cfg {String} validClass default "text-success"
30210 * @cfg {String} iconTooltip default "This field is required"
30211 * @cfg {String} indicatorpos (left|right) default left
30214 * Create a new FieldLabel
30215 * @param {Object} config The config object
30218 Roo.bootstrap.FieldLabel = function(config){
30219 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30224 * Fires after the field has been marked as invalid.
30225 * @param {Roo.form.FieldLabel} this
30226 * @param {String} msg The validation message
30231 * Fires after the field has been validated with no errors.
30232 * @param {Roo.form.FieldLabel} this
30238 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30245 invalidClass : 'has-warning',
30246 validClass : 'has-success',
30247 iconTooltip : 'This field is required',
30248 indicatorpos : 'left',
30250 getAutoCreate : function(){
30253 if (!this.allowBlank) {
30259 cls : 'roo-bootstrap-field-label ' + this.cls,
30264 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30265 tooltip : this.iconTooltip
30274 if(this.indicatorpos == 'right'){
30277 cls : 'roo-bootstrap-field-label ' + this.cls,
30286 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30287 tooltip : this.iconTooltip
30296 initEvents: function()
30298 Roo.bootstrap.Element.superclass.initEvents.call(this);
30300 this.indicator = this.indicatorEl();
30302 if(this.indicator){
30303 this.indicator.removeClass('visible');
30304 this.indicator.addClass('invisible');
30307 Roo.bootstrap.FieldLabel.register(this);
30310 indicatorEl : function()
30312 var indicator = this.el.select('i.roo-required-indicator',true).first();
30323 * Mark this field as valid
30325 markValid : function()
30327 if(this.indicator){
30328 this.indicator.removeClass('visible');
30329 this.indicator.addClass('invisible');
30332 this.el.removeClass(this.invalidClass);
30334 this.el.addClass(this.validClass);
30336 this.fireEvent('valid', this);
30340 * Mark this field as invalid
30341 * @param {String} msg The validation message
30343 markInvalid : function(msg)
30345 if(this.indicator){
30346 this.indicator.removeClass('invisible');
30347 this.indicator.addClass('visible');
30350 this.el.removeClass(this.validClass);
30352 this.el.addClass(this.invalidClass);
30354 this.fireEvent('invalid', this, msg);
30360 Roo.apply(Roo.bootstrap.FieldLabel, {
30365 * register a FieldLabel Group
30366 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30368 register : function(label)
30370 if(this.groups.hasOwnProperty(label.target)){
30374 this.groups[label.target] = label;
30378 * fetch a FieldLabel Group based on the target
30379 * @param {string} target
30380 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30382 get: function(target) {
30383 if (typeof(this.groups[target]) == 'undefined') {
30387 return this.groups[target] ;
30396 * page DateSplitField.
30402 * @class Roo.bootstrap.DateSplitField
30403 * @extends Roo.bootstrap.Component
30404 * Bootstrap DateSplitField class
30405 * @cfg {string} fieldLabel - the label associated
30406 * @cfg {Number} labelWidth set the width of label (0-12)
30407 * @cfg {String} labelAlign (top|left)
30408 * @cfg {Boolean} dayAllowBlank (true|false) default false
30409 * @cfg {Boolean} monthAllowBlank (true|false) default false
30410 * @cfg {Boolean} yearAllowBlank (true|false) default false
30411 * @cfg {string} dayPlaceholder
30412 * @cfg {string} monthPlaceholder
30413 * @cfg {string} yearPlaceholder
30414 * @cfg {string} dayFormat default 'd'
30415 * @cfg {string} monthFormat default 'm'
30416 * @cfg {string} yearFormat default 'Y'
30417 * @cfg {Number} labellg set the width of label (1-12)
30418 * @cfg {Number} labelmd set the width of label (1-12)
30419 * @cfg {Number} labelsm set the width of label (1-12)
30420 * @cfg {Number} labelxs set the width of label (1-12)
30424 * Create a new DateSplitField
30425 * @param {Object} config The config object
30428 Roo.bootstrap.DateSplitField = function(config){
30429 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30435 * getting the data of years
30436 * @param {Roo.bootstrap.DateSplitField} this
30437 * @param {Object} years
30442 * getting the data of days
30443 * @param {Roo.bootstrap.DateSplitField} this
30444 * @param {Object} days
30449 * Fires after the field has been marked as invalid.
30450 * @param {Roo.form.Field} this
30451 * @param {String} msg The validation message
30456 * Fires after the field has been validated with no errors.
30457 * @param {Roo.form.Field} this
30463 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30466 labelAlign : 'top',
30468 dayAllowBlank : false,
30469 monthAllowBlank : false,
30470 yearAllowBlank : false,
30471 dayPlaceholder : '',
30472 monthPlaceholder : '',
30473 yearPlaceholder : '',
30477 isFormField : true,
30483 getAutoCreate : function()
30487 cls : 'row roo-date-split-field-group',
30492 cls : 'form-hidden-field roo-date-split-field-group-value',
30498 var labelCls = 'col-md-12';
30499 var contentCls = 'col-md-4';
30501 if(this.fieldLabel){
30505 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30509 html : this.fieldLabel
30514 if(this.labelAlign == 'left'){
30516 if(this.labelWidth > 12){
30517 label.style = "width: " + this.labelWidth + 'px';
30520 if(this.labelWidth < 13 && this.labelmd == 0){
30521 this.labelmd = this.labelWidth;
30524 if(this.labellg > 0){
30525 labelCls = ' col-lg-' + this.labellg;
30526 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30529 if(this.labelmd > 0){
30530 labelCls = ' col-md-' + this.labelmd;
30531 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30534 if(this.labelsm > 0){
30535 labelCls = ' col-sm-' + this.labelsm;
30536 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30539 if(this.labelxs > 0){
30540 labelCls = ' col-xs-' + this.labelxs;
30541 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30545 label.cls += ' ' + labelCls;
30547 cfg.cn.push(label);
30550 Roo.each(['day', 'month', 'year'], function(t){
30553 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30560 inputEl: function ()
30562 return this.el.select('.roo-date-split-field-group-value', true).first();
30565 onRender : function(ct, position)
30569 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30571 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30573 this.dayField = new Roo.bootstrap.ComboBox({
30574 allowBlank : this.dayAllowBlank,
30575 alwaysQuery : true,
30576 displayField : 'value',
30579 forceSelection : true,
30581 placeholder : this.dayPlaceholder,
30582 selectOnFocus : true,
30583 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30584 triggerAction : 'all',
30586 valueField : 'value',
30587 store : new Roo.data.SimpleStore({
30588 data : (function() {
30590 _this.fireEvent('days', _this, days);
30593 fields : [ 'value' ]
30596 select : function (_self, record, index)
30598 _this.setValue(_this.getValue());
30603 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30605 this.monthField = new Roo.bootstrap.MonthField({
30606 after : '<i class=\"fa fa-calendar\"></i>',
30607 allowBlank : this.monthAllowBlank,
30608 placeholder : this.monthPlaceholder,
30611 render : function (_self)
30613 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30614 e.preventDefault();
30618 select : function (_self, oldvalue, newvalue)
30620 _this.setValue(_this.getValue());
30625 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30627 this.yearField = new Roo.bootstrap.ComboBox({
30628 allowBlank : this.yearAllowBlank,
30629 alwaysQuery : true,
30630 displayField : 'value',
30633 forceSelection : true,
30635 placeholder : this.yearPlaceholder,
30636 selectOnFocus : true,
30637 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30638 triggerAction : 'all',
30640 valueField : 'value',
30641 store : new Roo.data.SimpleStore({
30642 data : (function() {
30644 _this.fireEvent('years', _this, years);
30647 fields : [ 'value' ]
30650 select : function (_self, record, index)
30652 _this.setValue(_this.getValue());
30657 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30660 setValue : function(v, format)
30662 this.inputEl.dom.value = v;
30664 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30666 var d = Date.parseDate(v, f);
30673 this.setDay(d.format(this.dayFormat));
30674 this.setMonth(d.format(this.monthFormat));
30675 this.setYear(d.format(this.yearFormat));
30682 setDay : function(v)
30684 this.dayField.setValue(v);
30685 this.inputEl.dom.value = this.getValue();
30690 setMonth : function(v)
30692 this.monthField.setValue(v, true);
30693 this.inputEl.dom.value = this.getValue();
30698 setYear : function(v)
30700 this.yearField.setValue(v);
30701 this.inputEl.dom.value = this.getValue();
30706 getDay : function()
30708 return this.dayField.getValue();
30711 getMonth : function()
30713 return this.monthField.getValue();
30716 getYear : function()
30718 return this.yearField.getValue();
30721 getValue : function()
30723 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30725 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30735 this.inputEl.dom.value = '';
30740 validate : function()
30742 var d = this.dayField.validate();
30743 var m = this.monthField.validate();
30744 var y = this.yearField.validate();
30749 (!this.dayAllowBlank && !d) ||
30750 (!this.monthAllowBlank && !m) ||
30751 (!this.yearAllowBlank && !y)
30756 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30765 this.markInvalid();
30770 markValid : function()
30773 var label = this.el.select('label', true).first();
30774 var icon = this.el.select('i.fa-star', true).first();
30780 this.fireEvent('valid', this);
30784 * Mark this field as invalid
30785 * @param {String} msg The validation message
30787 markInvalid : function(msg)
30790 var label = this.el.select('label', true).first();
30791 var icon = this.el.select('i.fa-star', true).first();
30793 if(label && !icon){
30794 this.el.select('.roo-date-split-field-label', true).createChild({
30796 cls : 'text-danger fa fa-lg fa-star',
30797 tooltip : 'This field is required',
30798 style : 'margin-right:5px;'
30802 this.fireEvent('invalid', this, msg);
30805 clearInvalid : function()
30807 var label = this.el.select('label', true).first();
30808 var icon = this.el.select('i.fa-star', true).first();
30814 this.fireEvent('valid', this);
30817 getName: function()
30827 * http://masonry.desandro.com
30829 * The idea is to render all the bricks based on vertical width...
30831 * The original code extends 'outlayer' - we might need to use that....
30837 * @class Roo.bootstrap.LayoutMasonry
30838 * @extends Roo.bootstrap.Component
30839 * Bootstrap Layout Masonry class
30842 * Create a new Element
30843 * @param {Object} config The config object
30846 Roo.bootstrap.LayoutMasonry = function(config){
30848 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30852 Roo.bootstrap.LayoutMasonry.register(this);
30858 * Fire after layout the items
30859 * @param {Roo.bootstrap.LayoutMasonry} this
30860 * @param {Roo.EventObject} e
30867 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30870 * @cfg {Boolean} isLayoutInstant = no animation?
30872 isLayoutInstant : false, // needed?
30875 * @cfg {Number} boxWidth width of the columns
30880 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30885 * @cfg {Number} padWidth padding below box..
30890 * @cfg {Number} gutter gutter width..
30895 * @cfg {Number} maxCols maximum number of columns
30901 * @cfg {Boolean} isAutoInitial defalut true
30903 isAutoInitial : true,
30908 * @cfg {Boolean} isHorizontal defalut false
30910 isHorizontal : false,
30912 currentSize : null,
30918 bricks: null, //CompositeElement
30922 _isLayoutInited : false,
30924 // isAlternative : false, // only use for vertical layout...
30927 * @cfg {Number} alternativePadWidth padding below box..
30929 alternativePadWidth : 50,
30931 selectedBrick : [],
30933 getAutoCreate : function(){
30935 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30939 cls: 'blog-masonary-wrapper ' + this.cls,
30941 cls : 'mas-boxes masonary'
30948 getChildContainer: function( )
30950 if (this.boxesEl) {
30951 return this.boxesEl;
30954 this.boxesEl = this.el.select('.mas-boxes').first();
30956 return this.boxesEl;
30960 initEvents : function()
30964 if(this.isAutoInitial){
30965 Roo.log('hook children rendered');
30966 this.on('childrenrendered', function() {
30967 Roo.log('children rendered');
30973 initial : function()
30975 this.selectedBrick = [];
30977 this.currentSize = this.el.getBox(true);
30979 Roo.EventManager.onWindowResize(this.resize, this);
30981 if(!this.isAutoInitial){
30989 //this.layout.defer(500,this);
30993 resize : function()
30995 var cs = this.el.getBox(true);
30998 this.currentSize.width == cs.width &&
30999 this.currentSize.x == cs.x &&
31000 this.currentSize.height == cs.height &&
31001 this.currentSize.y == cs.y
31003 Roo.log("no change in with or X or Y");
31007 this.currentSize = cs;
31013 layout : function()
31015 this._resetLayout();
31017 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31019 this.layoutItems( isInstant );
31021 this._isLayoutInited = true;
31023 this.fireEvent('layout', this);
31027 _resetLayout : function()
31029 if(this.isHorizontal){
31030 this.horizontalMeasureColumns();
31034 this.verticalMeasureColumns();
31038 verticalMeasureColumns : function()
31040 this.getContainerWidth();
31042 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31043 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31047 var boxWidth = this.boxWidth + this.padWidth;
31049 if(this.containerWidth < this.boxWidth){
31050 boxWidth = this.containerWidth
31053 var containerWidth = this.containerWidth;
31055 var cols = Math.floor(containerWidth / boxWidth);
31057 this.cols = Math.max( cols, 1 );
31059 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31061 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31063 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31065 this.colWidth = boxWidth + avail - this.padWidth;
31067 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31068 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31071 horizontalMeasureColumns : function()
31073 this.getContainerWidth();
31075 var boxWidth = this.boxWidth;
31077 if(this.containerWidth < boxWidth){
31078 boxWidth = this.containerWidth;
31081 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31083 this.el.setHeight(boxWidth);
31087 getContainerWidth : function()
31089 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31092 layoutItems : function( isInstant )
31094 Roo.log(this.bricks);
31096 var items = Roo.apply([], this.bricks);
31098 if(this.isHorizontal){
31099 this._horizontalLayoutItems( items , isInstant );
31103 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31104 // this._verticalAlternativeLayoutItems( items , isInstant );
31108 this._verticalLayoutItems( items , isInstant );
31112 _verticalLayoutItems : function ( items , isInstant)
31114 if ( !items || !items.length ) {
31119 ['xs', 'xs', 'xs', 'tall'],
31120 ['xs', 'xs', 'tall'],
31121 ['xs', 'xs', 'sm'],
31122 ['xs', 'xs', 'xs'],
31128 ['sm', 'xs', 'xs'],
31132 ['tall', 'xs', 'xs', 'xs'],
31133 ['tall', 'xs', 'xs'],
31145 Roo.each(items, function(item, k){
31147 switch (item.size) {
31148 // these layouts take up a full box,
31159 boxes.push([item]);
31182 var filterPattern = function(box, length)
31190 var pattern = box.slice(0, length);
31194 Roo.each(pattern, function(i){
31195 format.push(i.size);
31198 Roo.each(standard, function(s){
31200 if(String(s) != String(format)){
31209 if(!match && length == 1){
31214 filterPattern(box, length - 1);
31218 queue.push(pattern);
31220 box = box.slice(length, box.length);
31222 filterPattern(box, 4);
31228 Roo.each(boxes, function(box, k){
31234 if(box.length == 1){
31239 filterPattern(box, 4);
31243 this._processVerticalLayoutQueue( queue, isInstant );
31247 // _verticalAlternativeLayoutItems : function( items , isInstant )
31249 // if ( !items || !items.length ) {
31253 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31257 _horizontalLayoutItems : function ( items , isInstant)
31259 if ( !items || !items.length || items.length < 3) {
31265 var eItems = items.slice(0, 3);
31267 items = items.slice(3, items.length);
31270 ['xs', 'xs', 'xs', 'wide'],
31271 ['xs', 'xs', 'wide'],
31272 ['xs', 'xs', 'sm'],
31273 ['xs', 'xs', 'xs'],
31279 ['sm', 'xs', 'xs'],
31283 ['wide', 'xs', 'xs', 'xs'],
31284 ['wide', 'xs', 'xs'],
31297 Roo.each(items, function(item, k){
31299 switch (item.size) {
31310 boxes.push([item]);
31334 var filterPattern = function(box, length)
31342 var pattern = box.slice(0, length);
31346 Roo.each(pattern, function(i){
31347 format.push(i.size);
31350 Roo.each(standard, function(s){
31352 if(String(s) != String(format)){
31361 if(!match && length == 1){
31366 filterPattern(box, length - 1);
31370 queue.push(pattern);
31372 box = box.slice(length, box.length);
31374 filterPattern(box, 4);
31380 Roo.each(boxes, function(box, k){
31386 if(box.length == 1){
31391 filterPattern(box, 4);
31398 var pos = this.el.getBox(true);
31402 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31404 var hit_end = false;
31406 Roo.each(queue, function(box){
31410 Roo.each(box, function(b){
31412 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31422 Roo.each(box, function(b){
31424 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31427 mx = Math.max(mx, b.x);
31431 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31435 Roo.each(box, function(b){
31437 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31451 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31454 /** Sets position of item in DOM
31455 * @param {Element} item
31456 * @param {Number} x - horizontal position
31457 * @param {Number} y - vertical position
31458 * @param {Boolean} isInstant - disables transitions
31460 _processVerticalLayoutQueue : function( queue, isInstant )
31462 var pos = this.el.getBox(true);
31467 for (var i = 0; i < this.cols; i++){
31471 Roo.each(queue, function(box, k){
31473 var col = k % this.cols;
31475 Roo.each(box, function(b,kk){
31477 b.el.position('absolute');
31479 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31480 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31482 if(b.size == 'md-left' || b.size == 'md-right'){
31483 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31484 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31487 b.el.setWidth(width);
31488 b.el.setHeight(height);
31490 b.el.select('iframe',true).setSize(width,height);
31494 for (var i = 0; i < this.cols; i++){
31496 if(maxY[i] < maxY[col]){
31501 col = Math.min(col, i);
31505 x = pos.x + col * (this.colWidth + this.padWidth);
31509 var positions = [];
31511 switch (box.length){
31513 positions = this.getVerticalOneBoxColPositions(x, y, box);
31516 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31519 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31522 positions = this.getVerticalFourBoxColPositions(x, y, box);
31528 Roo.each(box, function(b,kk){
31530 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31532 var sz = b.el.getSize();
31534 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31542 for (var i = 0; i < this.cols; i++){
31543 mY = Math.max(mY, maxY[i]);
31546 this.el.setHeight(mY - pos.y);
31550 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31552 // var pos = this.el.getBox(true);
31555 // var maxX = pos.right;
31557 // var maxHeight = 0;
31559 // Roo.each(items, function(item, k){
31563 // item.el.position('absolute');
31565 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31567 // item.el.setWidth(width);
31569 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31571 // item.el.setHeight(height);
31574 // item.el.setXY([x, y], isInstant ? false : true);
31576 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31579 // y = y + height + this.alternativePadWidth;
31581 // maxHeight = maxHeight + height + this.alternativePadWidth;
31585 // this.el.setHeight(maxHeight);
31589 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31591 var pos = this.el.getBox(true);
31596 var maxX = pos.right;
31598 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31600 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31602 Roo.each(queue, function(box, k){
31604 Roo.each(box, function(b, kk){
31606 b.el.position('absolute');
31608 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31609 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31611 if(b.size == 'md-left' || b.size == 'md-right'){
31612 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31613 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31616 b.el.setWidth(width);
31617 b.el.setHeight(height);
31625 var positions = [];
31627 switch (box.length){
31629 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31632 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31635 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31638 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31644 Roo.each(box, function(b,kk){
31646 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31648 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31656 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31658 Roo.each(eItems, function(b,k){
31660 b.size = (k == 0) ? 'sm' : 'xs';
31661 b.x = (k == 0) ? 2 : 1;
31662 b.y = (k == 0) ? 2 : 1;
31664 b.el.position('absolute');
31666 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31668 b.el.setWidth(width);
31670 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31672 b.el.setHeight(height);
31676 var positions = [];
31679 x : maxX - this.unitWidth * 2 - this.gutter,
31684 x : maxX - this.unitWidth,
31685 y : minY + (this.unitWidth + this.gutter) * 2
31689 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31693 Roo.each(eItems, function(b,k){
31695 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31701 getVerticalOneBoxColPositions : function(x, y, box)
31705 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31707 if(box[0].size == 'md-left'){
31711 if(box[0].size == 'md-right'){
31716 x : x + (this.unitWidth + this.gutter) * rand,
31723 getVerticalTwoBoxColPositions : function(x, y, box)
31727 if(box[0].size == 'xs'){
31731 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31735 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31749 x : x + (this.unitWidth + this.gutter) * 2,
31750 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31757 getVerticalThreeBoxColPositions : function(x, y, box)
31761 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31769 x : x + (this.unitWidth + this.gutter) * 1,
31774 x : x + (this.unitWidth + this.gutter) * 2,
31782 if(box[0].size == 'xs' && box[1].size == 'xs'){
31791 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31795 x : x + (this.unitWidth + this.gutter) * 1,
31809 x : x + (this.unitWidth + this.gutter) * 2,
31814 x : x + (this.unitWidth + this.gutter) * 2,
31815 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31822 getVerticalFourBoxColPositions : function(x, y, box)
31826 if(box[0].size == 'xs'){
31835 y : y + (this.unitHeight + this.gutter) * 1
31840 y : y + (this.unitHeight + this.gutter) * 2
31844 x : x + (this.unitWidth + this.gutter) * 1,
31858 x : x + (this.unitWidth + this.gutter) * 2,
31863 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31864 y : y + (this.unitHeight + this.gutter) * 1
31868 x : x + (this.unitWidth + this.gutter) * 2,
31869 y : y + (this.unitWidth + this.gutter) * 2
31876 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31880 if(box[0].size == 'md-left'){
31882 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31889 if(box[0].size == 'md-right'){
31891 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31892 y : minY + (this.unitWidth + this.gutter) * 1
31898 var rand = Math.floor(Math.random() * (4 - box[0].y));
31901 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31902 y : minY + (this.unitWidth + this.gutter) * rand
31909 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31913 if(box[0].size == 'xs'){
31916 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31921 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31922 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31930 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31935 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31936 y : minY + (this.unitWidth + this.gutter) * 2
31943 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31947 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31950 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31955 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31956 y : minY + (this.unitWidth + this.gutter) * 1
31960 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31961 y : minY + (this.unitWidth + this.gutter) * 2
31968 if(box[0].size == 'xs' && box[1].size == 'xs'){
31971 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31976 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31981 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31982 y : minY + (this.unitWidth + this.gutter) * 1
31990 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31995 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31996 y : minY + (this.unitWidth + this.gutter) * 2
32000 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32001 y : minY + (this.unitWidth + this.gutter) * 2
32008 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32012 if(box[0].size == 'xs'){
32015 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32020 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32025 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),
32030 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32031 y : minY + (this.unitWidth + this.gutter) * 1
32039 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32044 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32045 y : minY + (this.unitWidth + this.gutter) * 2
32049 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32050 y : minY + (this.unitWidth + this.gutter) * 2
32054 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),
32055 y : minY + (this.unitWidth + this.gutter) * 2
32063 * remove a Masonry Brick
32064 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32066 removeBrick : function(brick_id)
32072 for (var i = 0; i<this.bricks.length; i++) {
32073 if (this.bricks[i].id == brick_id) {
32074 this.bricks.splice(i,1);
32075 this.el.dom.removeChild(Roo.get(brick_id).dom);
32082 * adds a Masonry Brick
32083 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32085 addBrick : function(cfg)
32087 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32088 //this.register(cn);
32089 cn.parentId = this.id;
32090 cn.render(this.el);
32095 * register a Masonry Brick
32096 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32099 register : function(brick)
32101 this.bricks.push(brick);
32102 brick.masonryId = this.id;
32106 * clear all the Masonry Brick
32108 clearAll : function()
32111 //this.getChildContainer().dom.innerHTML = "";
32112 this.el.dom.innerHTML = '';
32115 getSelected : function()
32117 if (!this.selectedBrick) {
32121 return this.selectedBrick;
32125 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32129 * register a Masonry Layout
32130 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32133 register : function(layout)
32135 this.groups[layout.id] = layout;
32138 * fetch a Masonry Layout based on the masonry layout ID
32139 * @param {string} the masonry layout to add
32140 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32143 get: function(layout_id) {
32144 if (typeof(this.groups[layout_id]) == 'undefined') {
32147 return this.groups[layout_id] ;
32159 * http://masonry.desandro.com
32161 * The idea is to render all the bricks based on vertical width...
32163 * The original code extends 'outlayer' - we might need to use that....
32169 * @class Roo.bootstrap.LayoutMasonryAuto
32170 * @extends Roo.bootstrap.Component
32171 * Bootstrap Layout Masonry class
32174 * Create a new Element
32175 * @param {Object} config The config object
32178 Roo.bootstrap.LayoutMasonryAuto = function(config){
32179 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32182 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32185 * @cfg {Boolean} isFitWidth - resize the width..
32187 isFitWidth : false, // options..
32189 * @cfg {Boolean} isOriginLeft = left align?
32191 isOriginLeft : true,
32193 * @cfg {Boolean} isOriginTop = top align?
32195 isOriginTop : false,
32197 * @cfg {Boolean} isLayoutInstant = no animation?
32199 isLayoutInstant : false, // needed?
32201 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32203 isResizingContainer : true,
32205 * @cfg {Number} columnWidth width of the columns
32211 * @cfg {Number} maxCols maximum number of columns
32216 * @cfg {Number} padHeight padding below box..
32222 * @cfg {Boolean} isAutoInitial defalut true
32225 isAutoInitial : true,
32231 initialColumnWidth : 0,
32232 currentSize : null,
32234 colYs : null, // array.
32241 bricks: null, //CompositeElement
32242 cols : 0, // array?
32243 // element : null, // wrapped now this.el
32244 _isLayoutInited : null,
32247 getAutoCreate : function(){
32251 cls: 'blog-masonary-wrapper ' + this.cls,
32253 cls : 'mas-boxes masonary'
32260 getChildContainer: function( )
32262 if (this.boxesEl) {
32263 return this.boxesEl;
32266 this.boxesEl = this.el.select('.mas-boxes').first();
32268 return this.boxesEl;
32272 initEvents : function()
32276 if(this.isAutoInitial){
32277 Roo.log('hook children rendered');
32278 this.on('childrenrendered', function() {
32279 Roo.log('children rendered');
32286 initial : function()
32288 this.reloadItems();
32290 this.currentSize = this.el.getBox(true);
32292 /// was window resize... - let's see if this works..
32293 Roo.EventManager.onWindowResize(this.resize, this);
32295 if(!this.isAutoInitial){
32300 this.layout.defer(500,this);
32303 reloadItems: function()
32305 this.bricks = this.el.select('.masonry-brick', true);
32307 this.bricks.each(function(b) {
32308 //Roo.log(b.getSize());
32309 if (!b.attr('originalwidth')) {
32310 b.attr('originalwidth', b.getSize().width);
32315 Roo.log(this.bricks.elements.length);
32318 resize : function()
32321 var cs = this.el.getBox(true);
32323 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32324 Roo.log("no change in with or X");
32327 this.currentSize = cs;
32331 layout : function()
32334 this._resetLayout();
32335 //this._manageStamps();
32337 // don't animate first layout
32338 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32339 this.layoutItems( isInstant );
32341 // flag for initalized
32342 this._isLayoutInited = true;
32345 layoutItems : function( isInstant )
32347 //var items = this._getItemsForLayout( this.items );
32348 // original code supports filtering layout items.. we just ignore it..
32350 this._layoutItems( this.bricks , isInstant );
32352 this._postLayout();
32354 _layoutItems : function ( items , isInstant)
32356 //this.fireEvent( 'layout', this, items );
32359 if ( !items || !items.elements.length ) {
32360 // no items, emit event with empty array
32365 items.each(function(item) {
32366 Roo.log("layout item");
32368 // get x/y object from method
32369 var position = this._getItemLayoutPosition( item );
32371 position.item = item;
32372 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32373 queue.push( position );
32376 this._processLayoutQueue( queue );
32378 /** Sets position of item in DOM
32379 * @param {Element} item
32380 * @param {Number} x - horizontal position
32381 * @param {Number} y - vertical position
32382 * @param {Boolean} isInstant - disables transitions
32384 _processLayoutQueue : function( queue )
32386 for ( var i=0, len = queue.length; i < len; i++ ) {
32387 var obj = queue[i];
32388 obj.item.position('absolute');
32389 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32395 * Any logic you want to do after each layout,
32396 * i.e. size the container
32398 _postLayout : function()
32400 this.resizeContainer();
32403 resizeContainer : function()
32405 if ( !this.isResizingContainer ) {
32408 var size = this._getContainerSize();
32410 this.el.setSize(size.width,size.height);
32411 this.boxesEl.setSize(size.width,size.height);
32417 _resetLayout : function()
32419 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32420 this.colWidth = this.el.getWidth();
32421 //this.gutter = this.el.getWidth();
32423 this.measureColumns();
32429 this.colYs.push( 0 );
32435 measureColumns : function()
32437 this.getContainerWidth();
32438 // if columnWidth is 0, default to outerWidth of first item
32439 if ( !this.columnWidth ) {
32440 var firstItem = this.bricks.first();
32441 Roo.log(firstItem);
32442 this.columnWidth = this.containerWidth;
32443 if (firstItem && firstItem.attr('originalwidth') ) {
32444 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32446 // columnWidth fall back to item of first element
32447 Roo.log("set column width?");
32448 this.initialColumnWidth = this.columnWidth ;
32450 // if first elem has no width, default to size of container
32455 if (this.initialColumnWidth) {
32456 this.columnWidth = this.initialColumnWidth;
32461 // column width is fixed at the top - however if container width get's smaller we should
32464 // this bit calcs how man columns..
32466 var columnWidth = this.columnWidth += this.gutter;
32468 // calculate columns
32469 var containerWidth = this.containerWidth + this.gutter;
32471 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32472 // fix rounding errors, typically with gutters
32473 var excess = columnWidth - containerWidth % columnWidth;
32476 // if overshoot is less than a pixel, round up, otherwise floor it
32477 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32478 cols = Math[ mathMethod ]( cols );
32479 this.cols = Math.max( cols, 1 );
32480 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32482 // padding positioning..
32483 var totalColWidth = this.cols * this.columnWidth;
32484 var padavail = this.containerWidth - totalColWidth;
32485 // so for 2 columns - we need 3 'pads'
32487 var padNeeded = (1+this.cols) * this.padWidth;
32489 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32491 this.columnWidth += padExtra
32492 //this.padWidth = Math.floor(padavail / ( this.cols));
32494 // adjust colum width so that padding is fixed??
32496 // we have 3 columns ... total = width * 3
32497 // we have X left over... that should be used by
32499 //if (this.expandC) {
32507 getContainerWidth : function()
32509 /* // container is parent if fit width
32510 var container = this.isFitWidth ? this.element.parentNode : this.element;
32511 // check that this.size and size are there
32512 // IE8 triggers resize on body size change, so they might not be
32514 var size = getSize( container ); //FIXME
32515 this.containerWidth = size && size.innerWidth; //FIXME
32518 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32522 _getItemLayoutPosition : function( item ) // what is item?
32524 // we resize the item to our columnWidth..
32526 item.setWidth(this.columnWidth);
32527 item.autoBoxAdjust = false;
32529 var sz = item.getSize();
32531 // how many columns does this brick span
32532 var remainder = this.containerWidth % this.columnWidth;
32534 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32535 // round if off by 1 pixel, otherwise use ceil
32536 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32537 colSpan = Math.min( colSpan, this.cols );
32539 // normally this should be '1' as we dont' currently allow multi width columns..
32541 var colGroup = this._getColGroup( colSpan );
32542 // get the minimum Y value from the columns
32543 var minimumY = Math.min.apply( Math, colGroup );
32544 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32546 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32548 // position the brick
32550 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32551 y: this.currentSize.y + minimumY + this.padHeight
32555 // apply setHeight to necessary columns
32556 var setHeight = minimumY + sz.height + this.padHeight;
32557 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32559 var setSpan = this.cols + 1 - colGroup.length;
32560 for ( var i = 0; i < setSpan; i++ ) {
32561 this.colYs[ shortColIndex + i ] = setHeight ;
32568 * @param {Number} colSpan - number of columns the element spans
32569 * @returns {Array} colGroup
32571 _getColGroup : function( colSpan )
32573 if ( colSpan < 2 ) {
32574 // if brick spans only one column, use all the column Ys
32579 // how many different places could this brick fit horizontally
32580 var groupCount = this.cols + 1 - colSpan;
32581 // for each group potential horizontal position
32582 for ( var i = 0; i < groupCount; i++ ) {
32583 // make an array of colY values for that one group
32584 var groupColYs = this.colYs.slice( i, i + colSpan );
32585 // and get the max value of the array
32586 colGroup[i] = Math.max.apply( Math, groupColYs );
32591 _manageStamp : function( stamp )
32593 var stampSize = stamp.getSize();
32594 var offset = stamp.getBox();
32595 // get the columns that this stamp affects
32596 var firstX = this.isOriginLeft ? offset.x : offset.right;
32597 var lastX = firstX + stampSize.width;
32598 var firstCol = Math.floor( firstX / this.columnWidth );
32599 firstCol = Math.max( 0, firstCol );
32601 var lastCol = Math.floor( lastX / this.columnWidth );
32602 // lastCol should not go over if multiple of columnWidth #425
32603 lastCol -= lastX % this.columnWidth ? 0 : 1;
32604 lastCol = Math.min( this.cols - 1, lastCol );
32606 // set colYs to bottom of the stamp
32607 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32610 for ( var i = firstCol; i <= lastCol; i++ ) {
32611 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32616 _getContainerSize : function()
32618 this.maxY = Math.max.apply( Math, this.colYs );
32623 if ( this.isFitWidth ) {
32624 size.width = this._getContainerFitWidth();
32630 _getContainerFitWidth : function()
32632 var unusedCols = 0;
32633 // count unused columns
32636 if ( this.colYs[i] !== 0 ) {
32641 // fit container to columns that have been used
32642 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32645 needsResizeLayout : function()
32647 var previousWidth = this.containerWidth;
32648 this.getContainerWidth();
32649 return previousWidth !== this.containerWidth;
32664 * @class Roo.bootstrap.MasonryBrick
32665 * @extends Roo.bootstrap.Component
32666 * Bootstrap MasonryBrick class
32669 * Create a new MasonryBrick
32670 * @param {Object} config The config object
32673 Roo.bootstrap.MasonryBrick = function(config){
32675 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32677 Roo.bootstrap.MasonryBrick.register(this);
32683 * When a MasonryBrick is clcik
32684 * @param {Roo.bootstrap.MasonryBrick} this
32685 * @param {Roo.EventObject} e
32691 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32694 * @cfg {String} title
32698 * @cfg {String} html
32702 * @cfg {String} bgimage
32706 * @cfg {String} videourl
32710 * @cfg {String} cls
32714 * @cfg {String} href
32718 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32723 * @cfg {String} placetitle (center|bottom)
32728 * @cfg {Boolean} isFitContainer defalut true
32730 isFitContainer : true,
32733 * @cfg {Boolean} preventDefault defalut false
32735 preventDefault : false,
32738 * @cfg {Boolean} inverse defalut false
32740 maskInverse : false,
32742 getAutoCreate : function()
32744 if(!this.isFitContainer){
32745 return this.getSplitAutoCreate();
32748 var cls = 'masonry-brick masonry-brick-full';
32750 if(this.href.length){
32751 cls += ' masonry-brick-link';
32754 if(this.bgimage.length){
32755 cls += ' masonry-brick-image';
32758 if(this.maskInverse){
32759 cls += ' mask-inverse';
32762 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32763 cls += ' enable-mask';
32767 cls += ' masonry-' + this.size + '-brick';
32770 if(this.placetitle.length){
32772 switch (this.placetitle) {
32774 cls += ' masonry-center-title';
32777 cls += ' masonry-bottom-title';
32784 if(!this.html.length && !this.bgimage.length){
32785 cls += ' masonry-center-title';
32788 if(!this.html.length && this.bgimage.length){
32789 cls += ' masonry-bottom-title';
32794 cls += ' ' + this.cls;
32798 tag: (this.href.length) ? 'a' : 'div',
32803 cls: 'masonry-brick-mask'
32807 cls: 'masonry-brick-paragraph',
32813 if(this.href.length){
32814 cfg.href = this.href;
32817 var cn = cfg.cn[1].cn;
32819 if(this.title.length){
32822 cls: 'masonry-brick-title',
32827 if(this.html.length){
32830 cls: 'masonry-brick-text',
32835 if (!this.title.length && !this.html.length) {
32836 cfg.cn[1].cls += ' hide';
32839 if(this.bgimage.length){
32842 cls: 'masonry-brick-image-view',
32847 if(this.videourl.length){
32848 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32849 // youtube support only?
32852 cls: 'masonry-brick-image-view',
32855 allowfullscreen : true
32863 getSplitAutoCreate : function()
32865 var cls = 'masonry-brick masonry-brick-split';
32867 if(this.href.length){
32868 cls += ' masonry-brick-link';
32871 if(this.bgimage.length){
32872 cls += ' masonry-brick-image';
32876 cls += ' masonry-' + this.size + '-brick';
32879 switch (this.placetitle) {
32881 cls += ' masonry-center-title';
32884 cls += ' masonry-bottom-title';
32887 if(!this.bgimage.length){
32888 cls += ' masonry-center-title';
32891 if(this.bgimage.length){
32892 cls += ' masonry-bottom-title';
32898 cls += ' ' + this.cls;
32902 tag: (this.href.length) ? 'a' : 'div',
32907 cls: 'masonry-brick-split-head',
32911 cls: 'masonry-brick-paragraph',
32918 cls: 'masonry-brick-split-body',
32924 if(this.href.length){
32925 cfg.href = this.href;
32928 if(this.title.length){
32929 cfg.cn[0].cn[0].cn.push({
32931 cls: 'masonry-brick-title',
32936 if(this.html.length){
32937 cfg.cn[1].cn.push({
32939 cls: 'masonry-brick-text',
32944 if(this.bgimage.length){
32945 cfg.cn[0].cn.push({
32947 cls: 'masonry-brick-image-view',
32952 if(this.videourl.length){
32953 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32954 // youtube support only?
32955 cfg.cn[0].cn.cn.push({
32957 cls: 'masonry-brick-image-view',
32960 allowfullscreen : true
32967 initEvents: function()
32969 switch (this.size) {
33002 this.el.on('touchstart', this.onTouchStart, this);
33003 this.el.on('touchmove', this.onTouchMove, this);
33004 this.el.on('touchend', this.onTouchEnd, this);
33005 this.el.on('contextmenu', this.onContextMenu, this);
33007 this.el.on('mouseenter' ,this.enter, this);
33008 this.el.on('mouseleave', this.leave, this);
33009 this.el.on('click', this.onClick, this);
33012 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33013 this.parent().bricks.push(this);
33018 onClick: function(e, el)
33020 var time = this.endTimer - this.startTimer;
33021 // Roo.log(e.preventDefault());
33024 e.preventDefault();
33029 if(!this.preventDefault){
33033 e.preventDefault();
33035 if (this.activeClass != '') {
33036 this.selectBrick();
33039 this.fireEvent('click', this, e);
33042 enter: function(e, el)
33044 e.preventDefault();
33046 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33050 if(this.bgimage.length && this.html.length){
33051 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33055 leave: function(e, el)
33057 e.preventDefault();
33059 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33063 if(this.bgimage.length && this.html.length){
33064 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33068 onTouchStart: function(e, el)
33070 // e.preventDefault();
33072 this.touchmoved = false;
33074 if(!this.isFitContainer){
33078 if(!this.bgimage.length || !this.html.length){
33082 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33084 this.timer = new Date().getTime();
33088 onTouchMove: function(e, el)
33090 this.touchmoved = true;
33093 onContextMenu : function(e,el)
33095 e.preventDefault();
33096 e.stopPropagation();
33100 onTouchEnd: function(e, el)
33102 // e.preventDefault();
33104 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33111 if(!this.bgimage.length || !this.html.length){
33113 if(this.href.length){
33114 window.location.href = this.href;
33120 if(!this.isFitContainer){
33124 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33126 window.location.href = this.href;
33129 //selection on single brick only
33130 selectBrick : function() {
33132 if (!this.parentId) {
33136 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33137 var index = m.selectedBrick.indexOf(this.id);
33140 m.selectedBrick.splice(index,1);
33141 this.el.removeClass(this.activeClass);
33145 for(var i = 0; i < m.selectedBrick.length; i++) {
33146 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33147 b.el.removeClass(b.activeClass);
33150 m.selectedBrick = [];
33152 m.selectedBrick.push(this.id);
33153 this.el.addClass(this.activeClass);
33157 isSelected : function(){
33158 return this.el.hasClass(this.activeClass);
33163 Roo.apply(Roo.bootstrap.MasonryBrick, {
33166 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33168 * register a Masonry Brick
33169 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33172 register : function(brick)
33174 //this.groups[brick.id] = brick;
33175 this.groups.add(brick.id, brick);
33178 * fetch a masonry brick based on the masonry brick ID
33179 * @param {string} the masonry brick to add
33180 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33183 get: function(brick_id)
33185 // if (typeof(this.groups[brick_id]) == 'undefined') {
33188 // return this.groups[brick_id] ;
33190 if(this.groups.key(brick_id)) {
33191 return this.groups.key(brick_id);
33209 * @class Roo.bootstrap.Brick
33210 * @extends Roo.bootstrap.Component
33211 * Bootstrap Brick class
33214 * Create a new Brick
33215 * @param {Object} config The config object
33218 Roo.bootstrap.Brick = function(config){
33219 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33225 * When a Brick is click
33226 * @param {Roo.bootstrap.Brick} this
33227 * @param {Roo.EventObject} e
33233 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33236 * @cfg {String} title
33240 * @cfg {String} html
33244 * @cfg {String} bgimage
33248 * @cfg {String} cls
33252 * @cfg {String} href
33256 * @cfg {String} video
33260 * @cfg {Boolean} square
33264 getAutoCreate : function()
33266 var cls = 'roo-brick';
33268 if(this.href.length){
33269 cls += ' roo-brick-link';
33272 if(this.bgimage.length){
33273 cls += ' roo-brick-image';
33276 if(!this.html.length && !this.bgimage.length){
33277 cls += ' roo-brick-center-title';
33280 if(!this.html.length && this.bgimage.length){
33281 cls += ' roo-brick-bottom-title';
33285 cls += ' ' + this.cls;
33289 tag: (this.href.length) ? 'a' : 'div',
33294 cls: 'roo-brick-paragraph',
33300 if(this.href.length){
33301 cfg.href = this.href;
33304 var cn = cfg.cn[0].cn;
33306 if(this.title.length){
33309 cls: 'roo-brick-title',
33314 if(this.html.length){
33317 cls: 'roo-brick-text',
33324 if(this.bgimage.length){
33327 cls: 'roo-brick-image-view',
33335 initEvents: function()
33337 if(this.title.length || this.html.length){
33338 this.el.on('mouseenter' ,this.enter, this);
33339 this.el.on('mouseleave', this.leave, this);
33342 Roo.EventManager.onWindowResize(this.resize, this);
33344 if(this.bgimage.length){
33345 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33346 this.imageEl.on('load', this.onImageLoad, this);
33353 onImageLoad : function()
33358 resize : function()
33360 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33362 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33364 if(this.bgimage.length){
33365 var image = this.el.select('.roo-brick-image-view', true).first();
33367 image.setWidth(paragraph.getWidth());
33370 image.setHeight(paragraph.getWidth());
33373 this.el.setHeight(image.getHeight());
33374 paragraph.setHeight(image.getHeight());
33380 enter: function(e, el)
33382 e.preventDefault();
33384 if(this.bgimage.length){
33385 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33386 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33390 leave: function(e, el)
33392 e.preventDefault();
33394 if(this.bgimage.length){
33395 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33396 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33411 * @class Roo.bootstrap.NumberField
33412 * @extends Roo.bootstrap.Input
33413 * Bootstrap NumberField class
33419 * Create a new NumberField
33420 * @param {Object} config The config object
33423 Roo.bootstrap.NumberField = function(config){
33424 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33427 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33430 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33432 allowDecimals : true,
33434 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33436 decimalSeparator : ".",
33438 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33440 decimalPrecision : 2,
33442 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33444 allowNegative : true,
33447 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33451 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33453 minValue : Number.NEGATIVE_INFINITY,
33455 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33457 maxValue : Number.MAX_VALUE,
33459 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33461 minText : "The minimum value for this field is {0}",
33463 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33465 maxText : "The maximum value for this field is {0}",
33467 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33468 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33470 nanText : "{0} is not a valid number",
33472 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33474 thousandsDelimiter : false,
33476 * @cfg {String} valueAlign alignment of value
33478 valueAlign : "left",
33480 getAutoCreate : function()
33482 var hiddenInput = {
33486 cls: 'hidden-number-input'
33490 hiddenInput.name = this.name;
33495 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33497 this.name = hiddenInput.name;
33499 if(cfg.cn.length > 0) {
33500 cfg.cn.push(hiddenInput);
33507 initEvents : function()
33509 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33511 var allowed = "0123456789";
33513 if(this.allowDecimals){
33514 allowed += this.decimalSeparator;
33517 if(this.allowNegative){
33521 if(this.thousandsDelimiter) {
33525 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33527 var keyPress = function(e){
33529 var k = e.getKey();
33531 var c = e.getCharCode();
33534 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33535 allowed.indexOf(String.fromCharCode(c)) === -1
33541 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33545 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33550 this.el.on("keypress", keyPress, this);
33553 validateValue : function(value)
33556 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33560 var num = this.parseValue(value);
33563 this.markInvalid(String.format(this.nanText, value));
33567 if(num < this.minValue){
33568 this.markInvalid(String.format(this.minText, this.minValue));
33572 if(num > this.maxValue){
33573 this.markInvalid(String.format(this.maxText, this.maxValue));
33580 getValue : function()
33582 var v = this.hiddenEl().getValue();
33584 return this.fixPrecision(this.parseValue(v));
33587 parseValue : function(value)
33589 if(this.thousandsDelimiter) {
33591 r = new RegExp(",", "g");
33592 value = value.replace(r, "");
33595 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33596 return isNaN(value) ? '' : value;
33599 fixPrecision : function(value)
33601 if(this.thousandsDelimiter) {
33603 r = new RegExp(",", "g");
33604 value = value.replace(r, "");
33607 var nan = isNaN(value);
33609 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33610 return nan ? '' : value;
33612 return parseFloat(value).toFixed(this.decimalPrecision);
33615 setValue : function(v)
33617 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33623 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33625 this.inputEl().dom.value = (v == '') ? '' :
33626 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33628 if(!this.allowZero && v === '0') {
33629 this.hiddenEl().dom.value = '';
33630 this.inputEl().dom.value = '';
33637 decimalPrecisionFcn : function(v)
33639 return Math.floor(v);
33642 beforeBlur : function()
33644 var v = this.parseValue(this.getRawValue());
33646 if(v || v === 0 || v === ''){
33651 hiddenEl : function()
33653 return this.el.select('input.hidden-number-input',true).first();
33665 * @class Roo.bootstrap.DocumentSlider
33666 * @extends Roo.bootstrap.Component
33667 * Bootstrap DocumentSlider class
33670 * Create a new DocumentViewer
33671 * @param {Object} config The config object
33674 Roo.bootstrap.DocumentSlider = function(config){
33675 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33682 * Fire after initEvent
33683 * @param {Roo.bootstrap.DocumentSlider} this
33688 * Fire after update
33689 * @param {Roo.bootstrap.DocumentSlider} this
33695 * @param {Roo.bootstrap.DocumentSlider} this
33701 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33707 getAutoCreate : function()
33711 cls : 'roo-document-slider',
33715 cls : 'roo-document-slider-header',
33719 cls : 'roo-document-slider-header-title'
33725 cls : 'roo-document-slider-body',
33729 cls : 'roo-document-slider-prev',
33733 cls : 'fa fa-chevron-left'
33739 cls : 'roo-document-slider-thumb',
33743 cls : 'roo-document-slider-image'
33749 cls : 'roo-document-slider-next',
33753 cls : 'fa fa-chevron-right'
33765 initEvents : function()
33767 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33768 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33770 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33771 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33773 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33774 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33776 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33777 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33779 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33780 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33782 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33783 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33785 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33786 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33788 this.thumbEl.on('click', this.onClick, this);
33790 this.prevIndicator.on('click', this.prev, this);
33792 this.nextIndicator.on('click', this.next, this);
33796 initial : function()
33798 if(this.files.length){
33799 this.indicator = 1;
33803 this.fireEvent('initial', this);
33806 update : function()
33808 this.imageEl.attr('src', this.files[this.indicator - 1]);
33810 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33812 this.prevIndicator.show();
33814 if(this.indicator == 1){
33815 this.prevIndicator.hide();
33818 this.nextIndicator.show();
33820 if(this.indicator == this.files.length){
33821 this.nextIndicator.hide();
33824 this.thumbEl.scrollTo('top');
33826 this.fireEvent('update', this);
33829 onClick : function(e)
33831 e.preventDefault();
33833 this.fireEvent('click', this);
33838 e.preventDefault();
33840 this.indicator = Math.max(1, this.indicator - 1);
33847 e.preventDefault();
33849 this.indicator = Math.min(this.files.length, this.indicator + 1);
33863 * @class Roo.bootstrap.RadioSet
33864 * @extends Roo.bootstrap.Input
33865 * Bootstrap RadioSet class
33866 * @cfg {String} indicatorpos (left|right) default left
33867 * @cfg {Boolean} inline (true|false) inline the element (default true)
33868 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33870 * Create a new RadioSet
33871 * @param {Object} config The config object
33874 Roo.bootstrap.RadioSet = function(config){
33876 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33880 Roo.bootstrap.RadioSet.register(this);
33885 * Fires when the element is checked or unchecked.
33886 * @param {Roo.bootstrap.RadioSet} this This radio
33887 * @param {Roo.bootstrap.Radio} item The checked item
33892 * Fires when the element is click.
33893 * @param {Roo.bootstrap.RadioSet} this This radio set
33894 * @param {Roo.bootstrap.Radio} item The checked item
33895 * @param {Roo.EventObject} e The event object
33902 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33910 indicatorpos : 'left',
33912 getAutoCreate : function()
33916 cls : 'roo-radio-set-label',
33920 html : this.fieldLabel
33925 if(this.indicatorpos == 'left'){
33928 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33929 tooltip : 'This field is required'
33934 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33935 tooltip : 'This field is required'
33941 cls : 'roo-radio-set-items'
33944 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33946 if (align === 'left' && this.fieldLabel.length) {
33949 cls : "roo-radio-set-right",
33955 if(this.labelWidth > 12){
33956 label.style = "width: " + this.labelWidth + 'px';
33959 if(this.labelWidth < 13 && this.labelmd == 0){
33960 this.labelmd = this.labelWidth;
33963 if(this.labellg > 0){
33964 label.cls += ' col-lg-' + this.labellg;
33965 items.cls += ' col-lg-' + (12 - this.labellg);
33968 if(this.labelmd > 0){
33969 label.cls += ' col-md-' + this.labelmd;
33970 items.cls += ' col-md-' + (12 - this.labelmd);
33973 if(this.labelsm > 0){
33974 label.cls += ' col-sm-' + this.labelsm;
33975 items.cls += ' col-sm-' + (12 - this.labelsm);
33978 if(this.labelxs > 0){
33979 label.cls += ' col-xs-' + this.labelxs;
33980 items.cls += ' col-xs-' + (12 - this.labelxs);
33986 cls : 'roo-radio-set',
33990 cls : 'roo-radio-set-input',
33993 value : this.value ? this.value : ''
34000 if(this.weight.length){
34001 cfg.cls += ' roo-radio-' + this.weight;
34005 cfg.cls += ' roo-radio-set-inline';
34009 ['xs','sm','md','lg'].map(function(size){
34010 if (settings[size]) {
34011 cfg.cls += ' col-' + size + '-' + settings[size];
34019 initEvents : function()
34021 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34022 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34024 if(!this.fieldLabel.length){
34025 this.labelEl.hide();
34028 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34029 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34031 this.indicator = this.indicatorEl();
34033 if(this.indicator){
34034 this.indicator.addClass('invisible');
34037 this.originalValue = this.getValue();
34041 inputEl: function ()
34043 return this.el.select('.roo-radio-set-input', true).first();
34046 getChildContainer : function()
34048 return this.itemsEl;
34051 register : function(item)
34053 this.radioes.push(item);
34057 validate : function()
34059 if(this.getVisibilityEl().hasClass('hidden')){
34065 Roo.each(this.radioes, function(i){
34074 if(this.allowBlank) {
34078 if(this.disabled || valid){
34083 this.markInvalid();
34088 markValid : function()
34090 if(this.labelEl.isVisible(true)){
34091 this.indicatorEl().removeClass('visible');
34092 this.indicatorEl().addClass('invisible');
34095 this.el.removeClass([this.invalidClass, this.validClass]);
34096 this.el.addClass(this.validClass);
34098 this.fireEvent('valid', this);
34101 markInvalid : function(msg)
34103 if(this.allowBlank || this.disabled){
34107 if(this.labelEl.isVisible(true)){
34108 this.indicatorEl().removeClass('invisible');
34109 this.indicatorEl().addClass('visible');
34112 this.el.removeClass([this.invalidClass, this.validClass]);
34113 this.el.addClass(this.invalidClass);
34115 this.fireEvent('invalid', this, msg);
34119 setValue : function(v, suppressEvent)
34121 if(this.value === v){
34128 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34131 Roo.each(this.radioes, function(i){
34133 i.el.removeClass('checked');
34136 Roo.each(this.radioes, function(i){
34138 if(i.value === v || i.value.toString() === v.toString()){
34140 i.el.addClass('checked');
34142 if(suppressEvent !== true){
34143 this.fireEvent('check', this, i);
34154 clearInvalid : function(){
34156 if(!this.el || this.preventMark){
34160 this.el.removeClass([this.invalidClass]);
34162 this.fireEvent('valid', this);
34167 Roo.apply(Roo.bootstrap.RadioSet, {
34171 register : function(set)
34173 this.groups[set.name] = set;
34176 get: function(name)
34178 if (typeof(this.groups[name]) == 'undefined') {
34182 return this.groups[name] ;
34188 * Ext JS Library 1.1.1
34189 * Copyright(c) 2006-2007, Ext JS, LLC.
34191 * Originally Released Under LGPL - original licence link has changed is not relivant.
34194 * <script type="text/javascript">
34199 * @class Roo.bootstrap.SplitBar
34200 * @extends Roo.util.Observable
34201 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34205 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34206 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34207 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34208 split.minSize = 100;
34209 split.maxSize = 600;
34210 split.animate = true;
34211 split.on('moved', splitterMoved);
34214 * Create a new SplitBar
34215 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34216 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34217 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34218 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34219 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34220 position of the SplitBar).
34222 Roo.bootstrap.SplitBar = function(cfg){
34227 // dragElement : elm
34228 // resizingElement: el,
34230 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34231 // placement : Roo.bootstrap.SplitBar.LEFT ,
34232 // existingProxy ???
34235 this.el = Roo.get(cfg.dragElement, true);
34236 this.el.dom.unselectable = "on";
34238 this.resizingEl = Roo.get(cfg.resizingElement, true);
34242 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34243 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34246 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34249 * The minimum size of the resizing element. (Defaults to 0)
34255 * The maximum size of the resizing element. (Defaults to 2000)
34258 this.maxSize = 2000;
34261 * Whether to animate the transition to the new size
34264 this.animate = false;
34267 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34270 this.useShim = false;
34275 if(!cfg.existingProxy){
34277 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34279 this.proxy = Roo.get(cfg.existingProxy).dom;
34282 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34285 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34288 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34291 this.dragSpecs = {};
34294 * @private The adapter to use to positon and resize elements
34296 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34297 this.adapter.init(this);
34299 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34301 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34302 this.el.addClass("roo-splitbar-h");
34305 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34306 this.el.addClass("roo-splitbar-v");
34312 * Fires when the splitter is moved (alias for {@link #event-moved})
34313 * @param {Roo.bootstrap.SplitBar} this
34314 * @param {Number} newSize the new width or height
34319 * Fires when the splitter is moved
34320 * @param {Roo.bootstrap.SplitBar} this
34321 * @param {Number} newSize the new width or height
34325 * @event beforeresize
34326 * Fires before the splitter is dragged
34327 * @param {Roo.bootstrap.SplitBar} this
34329 "beforeresize" : true,
34331 "beforeapply" : true
34334 Roo.util.Observable.call(this);
34337 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34338 onStartProxyDrag : function(x, y){
34339 this.fireEvent("beforeresize", this);
34341 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34343 o.enableDisplayMode("block");
34344 // all splitbars share the same overlay
34345 Roo.bootstrap.SplitBar.prototype.overlay = o;
34347 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34348 this.overlay.show();
34349 Roo.get(this.proxy).setDisplayed("block");
34350 var size = this.adapter.getElementSize(this);
34351 this.activeMinSize = this.getMinimumSize();;
34352 this.activeMaxSize = this.getMaximumSize();;
34353 var c1 = size - this.activeMinSize;
34354 var c2 = Math.max(this.activeMaxSize - size, 0);
34355 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34356 this.dd.resetConstraints();
34357 this.dd.setXConstraint(
34358 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34359 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34361 this.dd.setYConstraint(0, 0);
34363 this.dd.resetConstraints();
34364 this.dd.setXConstraint(0, 0);
34365 this.dd.setYConstraint(
34366 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34367 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34370 this.dragSpecs.startSize = size;
34371 this.dragSpecs.startPoint = [x, y];
34372 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34376 * @private Called after the drag operation by the DDProxy
34378 onEndProxyDrag : function(e){
34379 Roo.get(this.proxy).setDisplayed(false);
34380 var endPoint = Roo.lib.Event.getXY(e);
34382 this.overlay.hide();
34385 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34386 newSize = this.dragSpecs.startSize +
34387 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34388 endPoint[0] - this.dragSpecs.startPoint[0] :
34389 this.dragSpecs.startPoint[0] - endPoint[0]
34392 newSize = this.dragSpecs.startSize +
34393 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34394 endPoint[1] - this.dragSpecs.startPoint[1] :
34395 this.dragSpecs.startPoint[1] - endPoint[1]
34398 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34399 if(newSize != this.dragSpecs.startSize){
34400 if(this.fireEvent('beforeapply', this, newSize) !== false){
34401 this.adapter.setElementSize(this, newSize);
34402 this.fireEvent("moved", this, newSize);
34403 this.fireEvent("resize", this, newSize);
34409 * Get the adapter this SplitBar uses
34410 * @return The adapter object
34412 getAdapter : function(){
34413 return this.adapter;
34417 * Set the adapter this SplitBar uses
34418 * @param {Object} adapter A SplitBar adapter object
34420 setAdapter : function(adapter){
34421 this.adapter = adapter;
34422 this.adapter.init(this);
34426 * Gets the minimum size for the resizing element
34427 * @return {Number} The minimum size
34429 getMinimumSize : function(){
34430 return this.minSize;
34434 * Sets the minimum size for the resizing element
34435 * @param {Number} minSize The minimum size
34437 setMinimumSize : function(minSize){
34438 this.minSize = minSize;
34442 * Gets the maximum size for the resizing element
34443 * @return {Number} The maximum size
34445 getMaximumSize : function(){
34446 return this.maxSize;
34450 * Sets the maximum size for the resizing element
34451 * @param {Number} maxSize The maximum size
34453 setMaximumSize : function(maxSize){
34454 this.maxSize = maxSize;
34458 * Sets the initialize size for the resizing element
34459 * @param {Number} size The initial size
34461 setCurrentSize : function(size){
34462 var oldAnimate = this.animate;
34463 this.animate = false;
34464 this.adapter.setElementSize(this, size);
34465 this.animate = oldAnimate;
34469 * Destroy this splitbar.
34470 * @param {Boolean} removeEl True to remove the element
34472 destroy : function(removeEl){
34474 this.shim.remove();
34477 this.proxy.parentNode.removeChild(this.proxy);
34485 * @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.
34487 Roo.bootstrap.SplitBar.createProxy = function(dir){
34488 var proxy = new Roo.Element(document.createElement("div"));
34489 proxy.unselectable();
34490 var cls = 'roo-splitbar-proxy';
34491 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34492 document.body.appendChild(proxy.dom);
34497 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34498 * Default Adapter. It assumes the splitter and resizing element are not positioned
34499 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34501 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34504 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34505 // do nothing for now
34506 init : function(s){
34510 * Called before drag operations to get the current size of the resizing element.
34511 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34513 getElementSize : function(s){
34514 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34515 return s.resizingEl.getWidth();
34517 return s.resizingEl.getHeight();
34522 * Called after drag operations to set the size of the resizing element.
34523 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34524 * @param {Number} newSize The new size to set
34525 * @param {Function} onComplete A function to be invoked when resizing is complete
34527 setElementSize : function(s, newSize, onComplete){
34528 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34530 s.resizingEl.setWidth(newSize);
34532 onComplete(s, newSize);
34535 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34540 s.resizingEl.setHeight(newSize);
34542 onComplete(s, newSize);
34545 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34552 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34553 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34554 * Adapter that moves the splitter element to align with the resized sizing element.
34555 * Used with an absolute positioned SplitBar.
34556 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34557 * document.body, make sure you assign an id to the body element.
34559 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34560 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34561 this.container = Roo.get(container);
34564 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34565 init : function(s){
34566 this.basic.init(s);
34569 getElementSize : function(s){
34570 return this.basic.getElementSize(s);
34573 setElementSize : function(s, newSize, onComplete){
34574 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34577 moveSplitter : function(s){
34578 var yes = Roo.bootstrap.SplitBar;
34579 switch(s.placement){
34581 s.el.setX(s.resizingEl.getRight());
34584 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34587 s.el.setY(s.resizingEl.getBottom());
34590 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34597 * Orientation constant - Create a vertical SplitBar
34601 Roo.bootstrap.SplitBar.VERTICAL = 1;
34604 * Orientation constant - Create a horizontal SplitBar
34608 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34611 * Placement constant - The resizing element is to the left of the splitter element
34615 Roo.bootstrap.SplitBar.LEFT = 1;
34618 * Placement constant - The resizing element is to the right of the splitter element
34622 Roo.bootstrap.SplitBar.RIGHT = 2;
34625 * Placement constant - The resizing element is positioned above the splitter element
34629 Roo.bootstrap.SplitBar.TOP = 3;
34632 * Placement constant - The resizing element is positioned under splitter element
34636 Roo.bootstrap.SplitBar.BOTTOM = 4;
34637 Roo.namespace("Roo.bootstrap.layout");/*
34639 * Ext JS Library 1.1.1
34640 * Copyright(c) 2006-2007, Ext JS, LLC.
34642 * Originally Released Under LGPL - original licence link has changed is not relivant.
34645 * <script type="text/javascript">
34649 * @class Roo.bootstrap.layout.Manager
34650 * @extends Roo.bootstrap.Component
34651 * Base class for layout managers.
34653 Roo.bootstrap.layout.Manager = function(config)
34655 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34661 /** false to disable window resize monitoring @type Boolean */
34662 this.monitorWindowResize = true;
34667 * Fires when a layout is performed.
34668 * @param {Roo.LayoutManager} this
34672 * @event regionresized
34673 * Fires when the user resizes a region.
34674 * @param {Roo.LayoutRegion} region The resized region
34675 * @param {Number} newSize The new size (width for east/west, height for north/south)
34677 "regionresized" : true,
34679 * @event regioncollapsed
34680 * Fires when a region is collapsed.
34681 * @param {Roo.LayoutRegion} region The collapsed region
34683 "regioncollapsed" : true,
34685 * @event regionexpanded
34686 * Fires when a region is expanded.
34687 * @param {Roo.LayoutRegion} region The expanded region
34689 "regionexpanded" : true
34691 this.updating = false;
34694 this.el = Roo.get(config.el);
34700 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34705 monitorWindowResize : true,
34711 onRender : function(ct, position)
34714 this.el = Roo.get(ct);
34717 //this.fireEvent('render',this);
34721 initEvents: function()
34725 // ie scrollbar fix
34726 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34727 document.body.scroll = "no";
34728 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34729 this.el.position('relative');
34731 this.id = this.el.id;
34732 this.el.addClass("roo-layout-container");
34733 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34734 if(this.el.dom != document.body ) {
34735 this.el.on('resize', this.layout,this);
34736 this.el.on('show', this.layout,this);
34742 * Returns true if this layout is currently being updated
34743 * @return {Boolean}
34745 isUpdating : function(){
34746 return this.updating;
34750 * Suspend the LayoutManager from doing auto-layouts while
34751 * making multiple add or remove calls
34753 beginUpdate : function(){
34754 this.updating = true;
34758 * Restore auto-layouts and optionally disable the manager from performing a layout
34759 * @param {Boolean} noLayout true to disable a layout update
34761 endUpdate : function(noLayout){
34762 this.updating = false;
34768 layout: function(){
34772 onRegionResized : function(region, newSize){
34773 this.fireEvent("regionresized", region, newSize);
34777 onRegionCollapsed : function(region){
34778 this.fireEvent("regioncollapsed", region);
34781 onRegionExpanded : function(region){
34782 this.fireEvent("regionexpanded", region);
34786 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34787 * performs box-model adjustments.
34788 * @return {Object} The size as an object {width: (the width), height: (the height)}
34790 getViewSize : function()
34793 if(this.el.dom != document.body){
34794 size = this.el.getSize();
34796 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34798 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34799 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34804 * Returns the Element this layout is bound to.
34805 * @return {Roo.Element}
34807 getEl : function(){
34812 * Returns the specified region.
34813 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34814 * @return {Roo.LayoutRegion}
34816 getRegion : function(target){
34817 return this.regions[target.toLowerCase()];
34820 onWindowResize : function(){
34821 if(this.monitorWindowResize){
34828 * Ext JS Library 1.1.1
34829 * Copyright(c) 2006-2007, Ext JS, LLC.
34831 * Originally Released Under LGPL - original licence link has changed is not relivant.
34834 * <script type="text/javascript">
34837 * @class Roo.bootstrap.layout.Border
34838 * @extends Roo.bootstrap.layout.Manager
34839 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34840 * please see: examples/bootstrap/nested.html<br><br>
34842 <b>The container the layout is rendered into can be either the body element or any other element.
34843 If it is not the body element, the container needs to either be an absolute positioned element,
34844 or you will need to add "position:relative" to the css of the container. You will also need to specify
34845 the container size if it is not the body element.</b>
34848 * Create a new Border
34849 * @param {Object} config Configuration options
34851 Roo.bootstrap.layout.Border = function(config){
34852 config = config || {};
34853 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34857 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34858 if(config[region]){
34859 config[region].region = region;
34860 this.addRegion(config[region]);
34866 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34868 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34870 * Creates and adds a new region if it doesn't already exist.
34871 * @param {String} target The target region key (north, south, east, west or center).
34872 * @param {Object} config The regions config object
34873 * @return {BorderLayoutRegion} The new region
34875 addRegion : function(config)
34877 if(!this.regions[config.region]){
34878 var r = this.factory(config);
34879 this.bindRegion(r);
34881 return this.regions[config.region];
34885 bindRegion : function(r){
34886 this.regions[r.config.region] = r;
34888 r.on("visibilitychange", this.layout, this);
34889 r.on("paneladded", this.layout, this);
34890 r.on("panelremoved", this.layout, this);
34891 r.on("invalidated", this.layout, this);
34892 r.on("resized", this.onRegionResized, this);
34893 r.on("collapsed", this.onRegionCollapsed, this);
34894 r.on("expanded", this.onRegionExpanded, this);
34898 * Performs a layout update.
34900 layout : function()
34902 if(this.updating) {
34906 // render all the rebions if they have not been done alreayd?
34907 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34908 if(this.regions[region] && !this.regions[region].bodyEl){
34909 this.regions[region].onRender(this.el)
34913 var size = this.getViewSize();
34914 var w = size.width;
34915 var h = size.height;
34920 //var x = 0, y = 0;
34922 var rs = this.regions;
34923 var north = rs["north"];
34924 var south = rs["south"];
34925 var west = rs["west"];
34926 var east = rs["east"];
34927 var center = rs["center"];
34928 //if(this.hideOnLayout){ // not supported anymore
34929 //c.el.setStyle("display", "none");
34931 if(north && north.isVisible()){
34932 var b = north.getBox();
34933 var m = north.getMargins();
34934 b.width = w - (m.left+m.right);
34937 centerY = b.height + b.y + m.bottom;
34938 centerH -= centerY;
34939 north.updateBox(this.safeBox(b));
34941 if(south && south.isVisible()){
34942 var b = south.getBox();
34943 var m = south.getMargins();
34944 b.width = w - (m.left+m.right);
34946 var totalHeight = (b.height + m.top + m.bottom);
34947 b.y = h - totalHeight + m.top;
34948 centerH -= totalHeight;
34949 south.updateBox(this.safeBox(b));
34951 if(west && west.isVisible()){
34952 var b = west.getBox();
34953 var m = west.getMargins();
34954 b.height = centerH - (m.top+m.bottom);
34956 b.y = centerY + m.top;
34957 var totalWidth = (b.width + m.left + m.right);
34958 centerX += totalWidth;
34959 centerW -= totalWidth;
34960 west.updateBox(this.safeBox(b));
34962 if(east && east.isVisible()){
34963 var b = east.getBox();
34964 var m = east.getMargins();
34965 b.height = centerH - (m.top+m.bottom);
34966 var totalWidth = (b.width + m.left + m.right);
34967 b.x = w - totalWidth + m.left;
34968 b.y = centerY + m.top;
34969 centerW -= totalWidth;
34970 east.updateBox(this.safeBox(b));
34973 var m = center.getMargins();
34975 x: centerX + m.left,
34976 y: centerY + m.top,
34977 width: centerW - (m.left+m.right),
34978 height: centerH - (m.top+m.bottom)
34980 //if(this.hideOnLayout){
34981 //center.el.setStyle("display", "block");
34983 center.updateBox(this.safeBox(centerBox));
34986 this.fireEvent("layout", this);
34990 safeBox : function(box){
34991 box.width = Math.max(0, box.width);
34992 box.height = Math.max(0, box.height);
34997 * Adds a ContentPanel (or subclass) to this layout.
34998 * @param {String} target The target region key (north, south, east, west or center).
34999 * @param {Roo.ContentPanel} panel The panel to add
35000 * @return {Roo.ContentPanel} The added panel
35002 add : function(target, panel){
35004 target = target.toLowerCase();
35005 return this.regions[target].add(panel);
35009 * Remove a ContentPanel (or subclass) to this layout.
35010 * @param {String} target The target region key (north, south, east, west or center).
35011 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35012 * @return {Roo.ContentPanel} The removed panel
35014 remove : function(target, panel){
35015 target = target.toLowerCase();
35016 return this.regions[target].remove(panel);
35020 * Searches all regions for a panel with the specified id
35021 * @param {String} panelId
35022 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35024 findPanel : function(panelId){
35025 var rs = this.regions;
35026 for(var target in rs){
35027 if(typeof rs[target] != "function"){
35028 var p = rs[target].getPanel(panelId);
35038 * Searches all regions for a panel with the specified id and activates (shows) it.
35039 * @param {String/ContentPanel} panelId The panels id or the panel itself
35040 * @return {Roo.ContentPanel} The shown panel or null
35042 showPanel : function(panelId) {
35043 var rs = this.regions;
35044 for(var target in rs){
35045 var r = rs[target];
35046 if(typeof r != "function"){
35047 if(r.hasPanel(panelId)){
35048 return r.showPanel(panelId);
35056 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35057 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35060 restoreState : function(provider){
35062 provider = Roo.state.Manager;
35064 var sm = new Roo.LayoutStateManager();
35065 sm.init(this, provider);
35071 * Adds a xtype elements to the layout.
35075 xtype : 'ContentPanel',
35082 xtype : 'NestedLayoutPanel',
35088 items : [ ... list of content panels or nested layout panels.. ]
35092 * @param {Object} cfg Xtype definition of item to add.
35094 addxtype : function(cfg)
35096 // basically accepts a pannel...
35097 // can accept a layout region..!?!?
35098 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35101 // theory? children can only be panels??
35103 //if (!cfg.xtype.match(/Panel$/)) {
35108 if (typeof(cfg.region) == 'undefined') {
35109 Roo.log("Failed to add Panel, region was not set");
35113 var region = cfg.region;
35119 xitems = cfg.items;
35126 case 'Content': // ContentPanel (el, cfg)
35127 case 'Scroll': // ContentPanel (el, cfg)
35129 cfg.autoCreate = true;
35130 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35132 // var el = this.el.createChild();
35133 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35136 this.add(region, ret);
35140 case 'TreePanel': // our new panel!
35141 cfg.el = this.el.createChild();
35142 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35143 this.add(region, ret);
35148 // create a new Layout (which is a Border Layout...
35150 var clayout = cfg.layout;
35151 clayout.el = this.el.createChild();
35152 clayout.items = clayout.items || [];
35156 // replace this exitems with the clayout ones..
35157 xitems = clayout.items;
35159 // force background off if it's in center...
35160 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35161 cfg.background = false;
35163 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35166 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35167 //console.log('adding nested layout panel ' + cfg.toSource());
35168 this.add(region, ret);
35169 nb = {}; /// find first...
35174 // needs grid and region
35176 //var el = this.getRegion(region).el.createChild();
35178 *var el = this.el.createChild();
35179 // create the grid first...
35180 cfg.grid.container = el;
35181 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35184 if (region == 'center' && this.active ) {
35185 cfg.background = false;
35188 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35190 this.add(region, ret);
35192 if (cfg.background) {
35193 // render grid on panel activation (if panel background)
35194 ret.on('activate', function(gp) {
35195 if (!gp.grid.rendered) {
35196 // gp.grid.render(el);
35200 // cfg.grid.render(el);
35206 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35207 // it was the old xcomponent building that caused this before.
35208 // espeically if border is the top element in the tree.
35218 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35220 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35221 this.add(region, ret);
35225 throw "Can not add '" + cfg.xtype + "' to Border";
35231 this.beginUpdate();
35235 Roo.each(xitems, function(i) {
35236 region = nb && i.region ? i.region : false;
35238 var add = ret.addxtype(i);
35241 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35242 if (!i.background) {
35243 abn[region] = nb[region] ;
35250 // make the last non-background panel active..
35251 //if (nb) { Roo.log(abn); }
35254 for(var r in abn) {
35255 region = this.getRegion(r);
35257 // tried using nb[r], but it does not work..
35259 region.showPanel(abn[r]);
35270 factory : function(cfg)
35273 var validRegions = Roo.bootstrap.layout.Border.regions;
35275 var target = cfg.region;
35278 var r = Roo.bootstrap.layout;
35282 return new r.North(cfg);
35284 return new r.South(cfg);
35286 return new r.East(cfg);
35288 return new r.West(cfg);
35290 return new r.Center(cfg);
35292 throw 'Layout region "'+target+'" not supported.';
35299 * Ext JS Library 1.1.1
35300 * Copyright(c) 2006-2007, Ext JS, LLC.
35302 * Originally Released Under LGPL - original licence link has changed is not relivant.
35305 * <script type="text/javascript">
35309 * @class Roo.bootstrap.layout.Basic
35310 * @extends Roo.util.Observable
35311 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35312 * and does not have a titlebar, tabs or any other features. All it does is size and position
35313 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35314 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35315 * @cfg {string} region the region that it inhabits..
35316 * @cfg {bool} skipConfig skip config?
35320 Roo.bootstrap.layout.Basic = function(config){
35322 this.mgr = config.mgr;
35324 this.position = config.region;
35326 var skipConfig = config.skipConfig;
35330 * @scope Roo.BasicLayoutRegion
35334 * @event beforeremove
35335 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35336 * @param {Roo.LayoutRegion} this
35337 * @param {Roo.ContentPanel} panel The panel
35338 * @param {Object} e The cancel event object
35340 "beforeremove" : true,
35342 * @event invalidated
35343 * Fires when the layout for this region is changed.
35344 * @param {Roo.LayoutRegion} this
35346 "invalidated" : true,
35348 * @event visibilitychange
35349 * Fires when this region is shown or hidden
35350 * @param {Roo.LayoutRegion} this
35351 * @param {Boolean} visibility true or false
35353 "visibilitychange" : true,
35355 * @event paneladded
35356 * Fires when a panel is added.
35357 * @param {Roo.LayoutRegion} this
35358 * @param {Roo.ContentPanel} panel The panel
35360 "paneladded" : true,
35362 * @event panelremoved
35363 * Fires when a panel is removed.
35364 * @param {Roo.LayoutRegion} this
35365 * @param {Roo.ContentPanel} panel The panel
35367 "panelremoved" : true,
35369 * @event beforecollapse
35370 * Fires when this region before collapse.
35371 * @param {Roo.LayoutRegion} this
35373 "beforecollapse" : true,
35376 * Fires when this region is collapsed.
35377 * @param {Roo.LayoutRegion} this
35379 "collapsed" : true,
35382 * Fires when this region is expanded.
35383 * @param {Roo.LayoutRegion} this
35388 * Fires when this region is slid into view.
35389 * @param {Roo.LayoutRegion} this
35391 "slideshow" : true,
35394 * Fires when this region slides out of view.
35395 * @param {Roo.LayoutRegion} this
35397 "slidehide" : true,
35399 * @event panelactivated
35400 * Fires when a panel is activated.
35401 * @param {Roo.LayoutRegion} this
35402 * @param {Roo.ContentPanel} panel The activated panel
35404 "panelactivated" : true,
35407 * Fires when the user resizes this region.
35408 * @param {Roo.LayoutRegion} this
35409 * @param {Number} newSize The new size (width for east/west, height for north/south)
35413 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35414 this.panels = new Roo.util.MixedCollection();
35415 this.panels.getKey = this.getPanelId.createDelegate(this);
35417 this.activePanel = null;
35418 // ensure listeners are added...
35420 if (config.listeners || config.events) {
35421 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35422 listeners : config.listeners || {},
35423 events : config.events || {}
35427 if(skipConfig !== true){
35428 this.applyConfig(config);
35432 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35434 getPanelId : function(p){
35438 applyConfig : function(config){
35439 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35440 this.config = config;
35445 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35446 * the width, for horizontal (north, south) the height.
35447 * @param {Number} newSize The new width or height
35449 resizeTo : function(newSize){
35450 var el = this.el ? this.el :
35451 (this.activePanel ? this.activePanel.getEl() : null);
35453 switch(this.position){
35456 el.setWidth(newSize);
35457 this.fireEvent("resized", this, newSize);
35461 el.setHeight(newSize);
35462 this.fireEvent("resized", this, newSize);
35468 getBox : function(){
35469 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35472 getMargins : function(){
35473 return this.margins;
35476 updateBox : function(box){
35478 var el = this.activePanel.getEl();
35479 el.dom.style.left = box.x + "px";
35480 el.dom.style.top = box.y + "px";
35481 this.activePanel.setSize(box.width, box.height);
35485 * Returns the container element for this region.
35486 * @return {Roo.Element}
35488 getEl : function(){
35489 return this.activePanel;
35493 * Returns true if this region is currently visible.
35494 * @return {Boolean}
35496 isVisible : function(){
35497 return this.activePanel ? true : false;
35500 setActivePanel : function(panel){
35501 panel = this.getPanel(panel);
35502 if(this.activePanel && this.activePanel != panel){
35503 this.activePanel.setActiveState(false);
35504 this.activePanel.getEl().setLeftTop(-10000,-10000);
35506 this.activePanel = panel;
35507 panel.setActiveState(true);
35509 panel.setSize(this.box.width, this.box.height);
35511 this.fireEvent("panelactivated", this, panel);
35512 this.fireEvent("invalidated");
35516 * Show the specified panel.
35517 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35518 * @return {Roo.ContentPanel} The shown panel or null
35520 showPanel : function(panel){
35521 panel = this.getPanel(panel);
35523 this.setActivePanel(panel);
35529 * Get the active panel for this region.
35530 * @return {Roo.ContentPanel} The active panel or null
35532 getActivePanel : function(){
35533 return this.activePanel;
35537 * Add the passed ContentPanel(s)
35538 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35539 * @return {Roo.ContentPanel} The panel added (if only one was added)
35541 add : function(panel){
35542 if(arguments.length > 1){
35543 for(var i = 0, len = arguments.length; i < len; i++) {
35544 this.add(arguments[i]);
35548 if(this.hasPanel(panel)){
35549 this.showPanel(panel);
35552 var el = panel.getEl();
35553 if(el.dom.parentNode != this.mgr.el.dom){
35554 this.mgr.el.dom.appendChild(el.dom);
35556 if(panel.setRegion){
35557 panel.setRegion(this);
35559 this.panels.add(panel);
35560 el.setStyle("position", "absolute");
35561 if(!panel.background){
35562 this.setActivePanel(panel);
35563 if(this.config.initialSize && this.panels.getCount()==1){
35564 this.resizeTo(this.config.initialSize);
35567 this.fireEvent("paneladded", this, panel);
35572 * Returns true if the panel is in this region.
35573 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35574 * @return {Boolean}
35576 hasPanel : function(panel){
35577 if(typeof panel == "object"){ // must be panel obj
35578 panel = panel.getId();
35580 return this.getPanel(panel) ? true : false;
35584 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35585 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35586 * @param {Boolean} preservePanel Overrides the config preservePanel option
35587 * @return {Roo.ContentPanel} The panel that was removed
35589 remove : function(panel, preservePanel){
35590 panel = this.getPanel(panel);
35595 this.fireEvent("beforeremove", this, panel, e);
35596 if(e.cancel === true){
35599 var panelId = panel.getId();
35600 this.panels.removeKey(panelId);
35605 * Returns the panel specified or null if it's not in this region.
35606 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35607 * @return {Roo.ContentPanel}
35609 getPanel : function(id){
35610 if(typeof id == "object"){ // must be panel obj
35613 return this.panels.get(id);
35617 * Returns this regions position (north/south/east/west/center).
35620 getPosition: function(){
35621 return this.position;
35625 * Ext JS Library 1.1.1
35626 * Copyright(c) 2006-2007, Ext JS, LLC.
35628 * Originally Released Under LGPL - original licence link has changed is not relivant.
35631 * <script type="text/javascript">
35635 * @class Roo.bootstrap.layout.Region
35636 * @extends Roo.bootstrap.layout.Basic
35637 * This class represents a region in a layout manager.
35639 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35640 * @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})
35641 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35642 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35643 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35644 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35645 * @cfg {String} title The title for the region (overrides panel titles)
35646 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35647 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35648 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35649 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35650 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35651 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35652 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35653 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35654 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35655 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35657 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35658 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35659 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35660 * @cfg {Number} width For East/West panels
35661 * @cfg {Number} height For North/South panels
35662 * @cfg {Boolean} split To show the splitter
35663 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35665 * @cfg {string} cls Extra CSS classes to add to region
35667 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35668 * @cfg {string} region the region that it inhabits..
35671 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35672 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35674 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35675 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35676 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35678 Roo.bootstrap.layout.Region = function(config)
35680 this.applyConfig(config);
35682 var mgr = config.mgr;
35683 var pos = config.region;
35684 config.skipConfig = true;
35685 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35688 this.onRender(mgr.el);
35691 this.visible = true;
35692 this.collapsed = false;
35693 this.unrendered_panels = [];
35696 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35698 position: '', // set by wrapper (eg. north/south etc..)
35699 unrendered_panels : null, // unrendered panels.
35700 createBody : function(){
35701 /** This region's body element
35702 * @type Roo.Element */
35703 this.bodyEl = this.el.createChild({
35705 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35709 onRender: function(ctr, pos)
35711 var dh = Roo.DomHelper;
35712 /** This region's container element
35713 * @type Roo.Element */
35714 this.el = dh.append(ctr.dom, {
35716 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35718 /** This region's title element
35719 * @type Roo.Element */
35721 this.titleEl = dh.append(this.el.dom,
35724 unselectable: "on",
35725 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35727 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35728 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35731 this.titleEl.enableDisplayMode();
35732 /** This region's title text element
35733 * @type HTMLElement */
35734 this.titleTextEl = this.titleEl.dom.firstChild;
35735 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35737 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35738 this.closeBtn.enableDisplayMode();
35739 this.closeBtn.on("click", this.closeClicked, this);
35740 this.closeBtn.hide();
35742 this.createBody(this.config);
35743 if(this.config.hideWhenEmpty){
35745 this.on("paneladded", this.validateVisibility, this);
35746 this.on("panelremoved", this.validateVisibility, this);
35748 if(this.autoScroll){
35749 this.bodyEl.setStyle("overflow", "auto");
35751 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35753 //if(c.titlebar !== false){
35754 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35755 this.titleEl.hide();
35757 this.titleEl.show();
35758 if(this.config.title){
35759 this.titleTextEl.innerHTML = this.config.title;
35763 if(this.config.collapsed){
35764 this.collapse(true);
35766 if(this.config.hidden){
35770 if (this.unrendered_panels && this.unrendered_panels.length) {
35771 for (var i =0;i< this.unrendered_panels.length; i++) {
35772 this.add(this.unrendered_panels[i]);
35774 this.unrendered_panels = null;
35780 applyConfig : function(c)
35783 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35784 var dh = Roo.DomHelper;
35785 if(c.titlebar !== false){
35786 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35787 this.collapseBtn.on("click", this.collapse, this);
35788 this.collapseBtn.enableDisplayMode();
35790 if(c.showPin === true || this.showPin){
35791 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35792 this.stickBtn.enableDisplayMode();
35793 this.stickBtn.on("click", this.expand, this);
35794 this.stickBtn.hide();
35799 /** This region's collapsed element
35800 * @type Roo.Element */
35803 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35804 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35807 if(c.floatable !== false){
35808 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35809 this.collapsedEl.on("click", this.collapseClick, this);
35812 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35813 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35814 id: "message", unselectable: "on", style:{"float":"left"}});
35815 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35817 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35818 this.expandBtn.on("click", this.expand, this);
35822 if(this.collapseBtn){
35823 this.collapseBtn.setVisible(c.collapsible == true);
35826 this.cmargins = c.cmargins || this.cmargins ||
35827 (this.position == "west" || this.position == "east" ?
35828 {top: 0, left: 2, right:2, bottom: 0} :
35829 {top: 2, left: 0, right:0, bottom: 2});
35831 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35834 this.bottomTabs = c.tabPosition != "top";
35836 this.autoScroll = c.autoScroll || false;
35841 this.duration = c.duration || .30;
35842 this.slideDuration = c.slideDuration || .45;
35847 * Returns true if this region is currently visible.
35848 * @return {Boolean}
35850 isVisible : function(){
35851 return this.visible;
35855 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35856 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35858 //setCollapsedTitle : function(title){
35859 // title = title || " ";
35860 // if(this.collapsedTitleTextEl){
35861 // this.collapsedTitleTextEl.innerHTML = title;
35865 getBox : function(){
35867 // if(!this.collapsed){
35868 b = this.el.getBox(false, true);
35870 // b = this.collapsedEl.getBox(false, true);
35875 getMargins : function(){
35876 return this.margins;
35877 //return this.collapsed ? this.cmargins : this.margins;
35880 highlight : function(){
35881 this.el.addClass("x-layout-panel-dragover");
35884 unhighlight : function(){
35885 this.el.removeClass("x-layout-panel-dragover");
35888 updateBox : function(box)
35890 if (!this.bodyEl) {
35891 return; // not rendered yet..
35895 if(!this.collapsed){
35896 this.el.dom.style.left = box.x + "px";
35897 this.el.dom.style.top = box.y + "px";
35898 this.updateBody(box.width, box.height);
35900 this.collapsedEl.dom.style.left = box.x + "px";
35901 this.collapsedEl.dom.style.top = box.y + "px";
35902 this.collapsedEl.setSize(box.width, box.height);
35905 this.tabs.autoSizeTabs();
35909 updateBody : function(w, h)
35912 this.el.setWidth(w);
35913 w -= this.el.getBorderWidth("rl");
35914 if(this.config.adjustments){
35915 w += this.config.adjustments[0];
35918 if(h !== null && h > 0){
35919 this.el.setHeight(h);
35920 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35921 h -= this.el.getBorderWidth("tb");
35922 if(this.config.adjustments){
35923 h += this.config.adjustments[1];
35925 this.bodyEl.setHeight(h);
35927 h = this.tabs.syncHeight(h);
35930 if(this.panelSize){
35931 w = w !== null ? w : this.panelSize.width;
35932 h = h !== null ? h : this.panelSize.height;
35934 if(this.activePanel){
35935 var el = this.activePanel.getEl();
35936 w = w !== null ? w : el.getWidth();
35937 h = h !== null ? h : el.getHeight();
35938 this.panelSize = {width: w, height: h};
35939 this.activePanel.setSize(w, h);
35941 if(Roo.isIE && this.tabs){
35942 this.tabs.el.repaint();
35947 * Returns the container element for this region.
35948 * @return {Roo.Element}
35950 getEl : function(){
35955 * Hides this region.
35958 //if(!this.collapsed){
35959 this.el.dom.style.left = "-2000px";
35962 // this.collapsedEl.dom.style.left = "-2000px";
35963 // this.collapsedEl.hide();
35965 this.visible = false;
35966 this.fireEvent("visibilitychange", this, false);
35970 * Shows this region if it was previously hidden.
35973 //if(!this.collapsed){
35976 // this.collapsedEl.show();
35978 this.visible = true;
35979 this.fireEvent("visibilitychange", this, true);
35982 closeClicked : function(){
35983 if(this.activePanel){
35984 this.remove(this.activePanel);
35988 collapseClick : function(e){
35990 e.stopPropagation();
35993 e.stopPropagation();
35999 * Collapses this region.
36000 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36003 collapse : function(skipAnim, skipCheck = false){
36004 if(this.collapsed) {
36008 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36010 this.collapsed = true;
36012 this.split.el.hide();
36014 if(this.config.animate && skipAnim !== true){
36015 this.fireEvent("invalidated", this);
36016 this.animateCollapse();
36018 this.el.setLocation(-20000,-20000);
36020 this.collapsedEl.show();
36021 this.fireEvent("collapsed", this);
36022 this.fireEvent("invalidated", this);
36028 animateCollapse : function(){
36033 * Expands this region if it was previously collapsed.
36034 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36035 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36038 expand : function(e, skipAnim){
36040 e.stopPropagation();
36042 if(!this.collapsed || this.el.hasActiveFx()) {
36046 this.afterSlideIn();
36049 this.collapsed = false;
36050 if(this.config.animate && skipAnim !== true){
36051 this.animateExpand();
36055 this.split.el.show();
36057 this.collapsedEl.setLocation(-2000,-2000);
36058 this.collapsedEl.hide();
36059 this.fireEvent("invalidated", this);
36060 this.fireEvent("expanded", this);
36064 animateExpand : function(){
36068 initTabs : function()
36070 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36072 var ts = new Roo.bootstrap.panel.Tabs({
36073 el: this.bodyEl.dom,
36074 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36075 disableTooltips: this.config.disableTabTips,
36076 toolbar : this.config.toolbar
36079 if(this.config.hideTabs){
36080 ts.stripWrap.setDisplayed(false);
36083 ts.resizeTabs = this.config.resizeTabs === true;
36084 ts.minTabWidth = this.config.minTabWidth || 40;
36085 ts.maxTabWidth = this.config.maxTabWidth || 250;
36086 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36087 ts.monitorResize = false;
36088 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36089 ts.bodyEl.addClass('roo-layout-tabs-body');
36090 this.panels.each(this.initPanelAsTab, this);
36093 initPanelAsTab : function(panel){
36094 var ti = this.tabs.addTab(
36098 this.config.closeOnTab && panel.isClosable(),
36101 if(panel.tabTip !== undefined){
36102 ti.setTooltip(panel.tabTip);
36104 ti.on("activate", function(){
36105 this.setActivePanel(panel);
36108 if(this.config.closeOnTab){
36109 ti.on("beforeclose", function(t, e){
36111 this.remove(panel);
36115 panel.tabItem = ti;
36120 updatePanelTitle : function(panel, title)
36122 if(this.activePanel == panel){
36123 this.updateTitle(title);
36126 var ti = this.tabs.getTab(panel.getEl().id);
36128 if(panel.tabTip !== undefined){
36129 ti.setTooltip(panel.tabTip);
36134 updateTitle : function(title){
36135 if(this.titleTextEl && !this.config.title){
36136 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36140 setActivePanel : function(panel)
36142 panel = this.getPanel(panel);
36143 if(this.activePanel && this.activePanel != panel){
36144 if(this.activePanel.setActiveState(false) === false){
36148 this.activePanel = panel;
36149 panel.setActiveState(true);
36150 if(this.panelSize){
36151 panel.setSize(this.panelSize.width, this.panelSize.height);
36154 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36156 this.updateTitle(panel.getTitle());
36158 this.fireEvent("invalidated", this);
36160 this.fireEvent("panelactivated", this, panel);
36164 * Shows the specified panel.
36165 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36166 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36168 showPanel : function(panel)
36170 panel = this.getPanel(panel);
36173 var tab = this.tabs.getTab(panel.getEl().id);
36174 if(tab.isHidden()){
36175 this.tabs.unhideTab(tab.id);
36179 this.setActivePanel(panel);
36186 * Get the active panel for this region.
36187 * @return {Roo.ContentPanel} The active panel or null
36189 getActivePanel : function(){
36190 return this.activePanel;
36193 validateVisibility : function(){
36194 if(this.panels.getCount() < 1){
36195 this.updateTitle(" ");
36196 this.closeBtn.hide();
36199 if(!this.isVisible()){
36206 * Adds the passed ContentPanel(s) to this region.
36207 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36208 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36210 add : function(panel)
36212 if(arguments.length > 1){
36213 for(var i = 0, len = arguments.length; i < len; i++) {
36214 this.add(arguments[i]);
36219 // if we have not been rendered yet, then we can not really do much of this..
36220 if (!this.bodyEl) {
36221 this.unrendered_panels.push(panel);
36228 if(this.hasPanel(panel)){
36229 this.showPanel(panel);
36232 panel.setRegion(this);
36233 this.panels.add(panel);
36234 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36235 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36236 // and hide them... ???
36237 this.bodyEl.dom.appendChild(panel.getEl().dom);
36238 if(panel.background !== true){
36239 this.setActivePanel(panel);
36241 this.fireEvent("paneladded", this, panel);
36248 this.initPanelAsTab(panel);
36252 if(panel.background !== true){
36253 this.tabs.activate(panel.getEl().id);
36255 this.fireEvent("paneladded", this, panel);
36260 * Hides the tab for the specified panel.
36261 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36263 hidePanel : function(panel){
36264 if(this.tabs && (panel = this.getPanel(panel))){
36265 this.tabs.hideTab(panel.getEl().id);
36270 * Unhides the tab for a previously hidden panel.
36271 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36273 unhidePanel : function(panel){
36274 if(this.tabs && (panel = this.getPanel(panel))){
36275 this.tabs.unhideTab(panel.getEl().id);
36279 clearPanels : function(){
36280 while(this.panels.getCount() > 0){
36281 this.remove(this.panels.first());
36286 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36287 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36288 * @param {Boolean} preservePanel Overrides the config preservePanel option
36289 * @return {Roo.ContentPanel} The panel that was removed
36291 remove : function(panel, preservePanel)
36293 panel = this.getPanel(panel);
36298 this.fireEvent("beforeremove", this, panel, e);
36299 if(e.cancel === true){
36302 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36303 var panelId = panel.getId();
36304 this.panels.removeKey(panelId);
36306 document.body.appendChild(panel.getEl().dom);
36309 this.tabs.removeTab(panel.getEl().id);
36310 }else if (!preservePanel){
36311 this.bodyEl.dom.removeChild(panel.getEl().dom);
36313 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36314 var p = this.panels.first();
36315 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36316 tempEl.appendChild(p.getEl().dom);
36317 this.bodyEl.update("");
36318 this.bodyEl.dom.appendChild(p.getEl().dom);
36320 this.updateTitle(p.getTitle());
36322 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36323 this.setActivePanel(p);
36325 panel.setRegion(null);
36326 if(this.activePanel == panel){
36327 this.activePanel = null;
36329 if(this.config.autoDestroy !== false && preservePanel !== true){
36330 try{panel.destroy();}catch(e){}
36332 this.fireEvent("panelremoved", this, panel);
36337 * Returns the TabPanel component used by this region
36338 * @return {Roo.TabPanel}
36340 getTabs : function(){
36344 createTool : function(parentEl, className){
36345 var btn = Roo.DomHelper.append(parentEl, {
36347 cls: "x-layout-tools-button",
36350 cls: "roo-layout-tools-button-inner " + className,
36354 btn.addClassOnOver("roo-layout-tools-button-over");
36359 * Ext JS Library 1.1.1
36360 * Copyright(c) 2006-2007, Ext JS, LLC.
36362 * Originally Released Under LGPL - original licence link has changed is not relivant.
36365 * <script type="text/javascript">
36371 * @class Roo.SplitLayoutRegion
36372 * @extends Roo.LayoutRegion
36373 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36375 Roo.bootstrap.layout.Split = function(config){
36376 this.cursor = config.cursor;
36377 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36380 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36382 splitTip : "Drag to resize.",
36383 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36384 useSplitTips : false,
36386 applyConfig : function(config){
36387 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36390 onRender : function(ctr,pos) {
36392 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36393 if(!this.config.split){
36398 var splitEl = Roo.DomHelper.append(ctr.dom, {
36400 id: this.el.id + "-split",
36401 cls: "roo-layout-split roo-layout-split-"+this.position,
36404 /** The SplitBar for this region
36405 * @type Roo.SplitBar */
36406 // does not exist yet...
36407 Roo.log([this.position, this.orientation]);
36409 this.split = new Roo.bootstrap.SplitBar({
36410 dragElement : splitEl,
36411 resizingElement: this.el,
36412 orientation : this.orientation
36415 this.split.on("moved", this.onSplitMove, this);
36416 this.split.useShim = this.config.useShim === true;
36417 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36418 if(this.useSplitTips){
36419 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36421 //if(config.collapsible){
36422 // this.split.el.on("dblclick", this.collapse, this);
36425 if(typeof this.config.minSize != "undefined"){
36426 this.split.minSize = this.config.minSize;
36428 if(typeof this.config.maxSize != "undefined"){
36429 this.split.maxSize = this.config.maxSize;
36431 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36432 this.hideSplitter();
36437 getHMaxSize : function(){
36438 var cmax = this.config.maxSize || 10000;
36439 var center = this.mgr.getRegion("center");
36440 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36443 getVMaxSize : function(){
36444 var cmax = this.config.maxSize || 10000;
36445 var center = this.mgr.getRegion("center");
36446 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36449 onSplitMove : function(split, newSize){
36450 this.fireEvent("resized", this, newSize);
36454 * Returns the {@link Roo.SplitBar} for this region.
36455 * @return {Roo.SplitBar}
36457 getSplitBar : function(){
36462 this.hideSplitter();
36463 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36466 hideSplitter : function(){
36468 this.split.el.setLocation(-2000,-2000);
36469 this.split.el.hide();
36475 this.split.el.show();
36477 Roo.bootstrap.layout.Split.superclass.show.call(this);
36480 beforeSlide: function(){
36481 if(Roo.isGecko){// firefox overflow auto bug workaround
36482 this.bodyEl.clip();
36484 this.tabs.bodyEl.clip();
36486 if(this.activePanel){
36487 this.activePanel.getEl().clip();
36489 if(this.activePanel.beforeSlide){
36490 this.activePanel.beforeSlide();
36496 afterSlide : function(){
36497 if(Roo.isGecko){// firefox overflow auto bug workaround
36498 this.bodyEl.unclip();
36500 this.tabs.bodyEl.unclip();
36502 if(this.activePanel){
36503 this.activePanel.getEl().unclip();
36504 if(this.activePanel.afterSlide){
36505 this.activePanel.afterSlide();
36511 initAutoHide : function(){
36512 if(this.autoHide !== false){
36513 if(!this.autoHideHd){
36514 var st = new Roo.util.DelayedTask(this.slideIn, this);
36515 this.autoHideHd = {
36516 "mouseout": function(e){
36517 if(!e.within(this.el, true)){
36521 "mouseover" : function(e){
36527 this.el.on(this.autoHideHd);
36531 clearAutoHide : function(){
36532 if(this.autoHide !== false){
36533 this.el.un("mouseout", this.autoHideHd.mouseout);
36534 this.el.un("mouseover", this.autoHideHd.mouseover);
36538 clearMonitor : function(){
36539 Roo.get(document).un("click", this.slideInIf, this);
36542 // these names are backwards but not changed for compat
36543 slideOut : function(){
36544 if(this.isSlid || this.el.hasActiveFx()){
36547 this.isSlid = true;
36548 if(this.collapseBtn){
36549 this.collapseBtn.hide();
36551 this.closeBtnState = this.closeBtn.getStyle('display');
36552 this.closeBtn.hide();
36554 this.stickBtn.show();
36557 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36558 this.beforeSlide();
36559 this.el.setStyle("z-index", 10001);
36560 this.el.slideIn(this.getSlideAnchor(), {
36561 callback: function(){
36563 this.initAutoHide();
36564 Roo.get(document).on("click", this.slideInIf, this);
36565 this.fireEvent("slideshow", this);
36572 afterSlideIn : function(){
36573 this.clearAutoHide();
36574 this.isSlid = false;
36575 this.clearMonitor();
36576 this.el.setStyle("z-index", "");
36577 if(this.collapseBtn){
36578 this.collapseBtn.show();
36580 this.closeBtn.setStyle('display', this.closeBtnState);
36582 this.stickBtn.hide();
36584 this.fireEvent("slidehide", this);
36587 slideIn : function(cb){
36588 if(!this.isSlid || this.el.hasActiveFx()){
36592 this.isSlid = false;
36593 this.beforeSlide();
36594 this.el.slideOut(this.getSlideAnchor(), {
36595 callback: function(){
36596 this.el.setLeftTop(-10000, -10000);
36598 this.afterSlideIn();
36606 slideInIf : function(e){
36607 if(!e.within(this.el)){
36612 animateCollapse : function(){
36613 this.beforeSlide();
36614 this.el.setStyle("z-index", 20000);
36615 var anchor = this.getSlideAnchor();
36616 this.el.slideOut(anchor, {
36617 callback : function(){
36618 this.el.setStyle("z-index", "");
36619 this.collapsedEl.slideIn(anchor, {duration:.3});
36621 this.el.setLocation(-10000,-10000);
36623 this.fireEvent("collapsed", this);
36630 animateExpand : function(){
36631 this.beforeSlide();
36632 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36633 this.el.setStyle("z-index", 20000);
36634 this.collapsedEl.hide({
36637 this.el.slideIn(this.getSlideAnchor(), {
36638 callback : function(){
36639 this.el.setStyle("z-index", "");
36642 this.split.el.show();
36644 this.fireEvent("invalidated", this);
36645 this.fireEvent("expanded", this);
36673 getAnchor : function(){
36674 return this.anchors[this.position];
36677 getCollapseAnchor : function(){
36678 return this.canchors[this.position];
36681 getSlideAnchor : function(){
36682 return this.sanchors[this.position];
36685 getAlignAdj : function(){
36686 var cm = this.cmargins;
36687 switch(this.position){
36703 getExpandAdj : function(){
36704 var c = this.collapsedEl, cm = this.cmargins;
36705 switch(this.position){
36707 return [-(cm.right+c.getWidth()+cm.left), 0];
36710 return [cm.right+c.getWidth()+cm.left, 0];
36713 return [0, -(cm.top+cm.bottom+c.getHeight())];
36716 return [0, cm.top+cm.bottom+c.getHeight()];
36722 * Ext JS Library 1.1.1
36723 * Copyright(c) 2006-2007, Ext JS, LLC.
36725 * Originally Released Under LGPL - original licence link has changed is not relivant.
36728 * <script type="text/javascript">
36731 * These classes are private internal classes
36733 Roo.bootstrap.layout.Center = function(config){
36734 config.region = "center";
36735 Roo.bootstrap.layout.Region.call(this, config);
36736 this.visible = true;
36737 this.minWidth = config.minWidth || 20;
36738 this.minHeight = config.minHeight || 20;
36741 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36743 // center panel can't be hidden
36747 // center panel can't be hidden
36750 getMinWidth: function(){
36751 return this.minWidth;
36754 getMinHeight: function(){
36755 return this.minHeight;
36768 Roo.bootstrap.layout.North = function(config)
36770 config.region = 'north';
36771 config.cursor = 'n-resize';
36773 Roo.bootstrap.layout.Split.call(this, config);
36777 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36778 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36779 this.split.el.addClass("roo-layout-split-v");
36781 var size = config.initialSize || config.height;
36782 if(typeof size != "undefined"){
36783 this.el.setHeight(size);
36786 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36788 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36792 getBox : function(){
36793 if(this.collapsed){
36794 return this.collapsedEl.getBox();
36796 var box = this.el.getBox();
36798 box.height += this.split.el.getHeight();
36803 updateBox : function(box){
36804 if(this.split && !this.collapsed){
36805 box.height -= this.split.el.getHeight();
36806 this.split.el.setLeft(box.x);
36807 this.split.el.setTop(box.y+box.height);
36808 this.split.el.setWidth(box.width);
36810 if(this.collapsed){
36811 this.updateBody(box.width, null);
36813 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36821 Roo.bootstrap.layout.South = function(config){
36822 config.region = 'south';
36823 config.cursor = 's-resize';
36824 Roo.bootstrap.layout.Split.call(this, config);
36826 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36827 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36828 this.split.el.addClass("roo-layout-split-v");
36830 var size = config.initialSize || config.height;
36831 if(typeof size != "undefined"){
36832 this.el.setHeight(size);
36836 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36837 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36838 getBox : function(){
36839 if(this.collapsed){
36840 return this.collapsedEl.getBox();
36842 var box = this.el.getBox();
36844 var sh = this.split.el.getHeight();
36851 updateBox : function(box){
36852 if(this.split && !this.collapsed){
36853 var sh = this.split.el.getHeight();
36856 this.split.el.setLeft(box.x);
36857 this.split.el.setTop(box.y-sh);
36858 this.split.el.setWidth(box.width);
36860 if(this.collapsed){
36861 this.updateBody(box.width, null);
36863 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36867 Roo.bootstrap.layout.East = function(config){
36868 config.region = "east";
36869 config.cursor = "e-resize";
36870 Roo.bootstrap.layout.Split.call(this, config);
36872 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36873 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36874 this.split.el.addClass("roo-layout-split-h");
36876 var size = config.initialSize || config.width;
36877 if(typeof size != "undefined"){
36878 this.el.setWidth(size);
36881 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36882 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36883 getBox : function(){
36884 if(this.collapsed){
36885 return this.collapsedEl.getBox();
36887 var box = this.el.getBox();
36889 var sw = this.split.el.getWidth();
36896 updateBox : function(box){
36897 if(this.split && !this.collapsed){
36898 var sw = this.split.el.getWidth();
36900 this.split.el.setLeft(box.x);
36901 this.split.el.setTop(box.y);
36902 this.split.el.setHeight(box.height);
36905 if(this.collapsed){
36906 this.updateBody(null, box.height);
36908 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36912 Roo.bootstrap.layout.West = function(config){
36913 config.region = "west";
36914 config.cursor = "w-resize";
36916 Roo.bootstrap.layout.Split.call(this, config);
36918 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36919 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36920 this.split.el.addClass("roo-layout-split-h");
36924 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36925 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36927 onRender: function(ctr, pos)
36929 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36930 var size = this.config.initialSize || this.config.width;
36931 if(typeof size != "undefined"){
36932 this.el.setWidth(size);
36936 getBox : function(){
36937 if(this.collapsed){
36938 return this.collapsedEl.getBox();
36940 var box = this.el.getBox();
36942 box.width += this.split.el.getWidth();
36947 updateBox : function(box){
36948 if(this.split && !this.collapsed){
36949 var sw = this.split.el.getWidth();
36951 this.split.el.setLeft(box.x+box.width);
36952 this.split.el.setTop(box.y);
36953 this.split.el.setHeight(box.height);
36955 if(this.collapsed){
36956 this.updateBody(null, box.height);
36958 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36961 Roo.namespace("Roo.bootstrap.panel");/*
36963 * Ext JS Library 1.1.1
36964 * Copyright(c) 2006-2007, Ext JS, LLC.
36966 * Originally Released Under LGPL - original licence link has changed is not relivant.
36969 * <script type="text/javascript">
36972 * @class Roo.ContentPanel
36973 * @extends Roo.util.Observable
36974 * A basic ContentPanel element.
36975 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36976 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36977 * @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
36978 * @cfg {Boolean} closable True if the panel can be closed/removed
36979 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36980 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36981 * @cfg {Toolbar} toolbar A toolbar for this panel
36982 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36983 * @cfg {String} title The title for this panel
36984 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36985 * @cfg {String} url Calls {@link #setUrl} with this value
36986 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36987 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36988 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36989 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36990 * @cfg {Boolean} badges render the badges
36993 * Create a new ContentPanel.
36994 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36995 * @param {String/Object} config A string to set only the title or a config object
36996 * @param {String} content (optional) Set the HTML content for this panel
36997 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36999 Roo.bootstrap.panel.Content = function( config){
37001 this.tpl = config.tpl || false;
37003 var el = config.el;
37004 var content = config.content;
37006 if(config.autoCreate){ // xtype is available if this is called from factory
37009 this.el = Roo.get(el);
37010 if(!this.el && config && config.autoCreate){
37011 if(typeof config.autoCreate == "object"){
37012 if(!config.autoCreate.id){
37013 config.autoCreate.id = config.id||el;
37015 this.el = Roo.DomHelper.append(document.body,
37016 config.autoCreate, true);
37018 var elcfg = { tag: "div",
37019 cls: "roo-layout-inactive-content",
37023 elcfg.html = config.html;
37027 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37030 this.closable = false;
37031 this.loaded = false;
37032 this.active = false;
37035 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37037 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37039 this.wrapEl = this.el; //this.el.wrap();
37041 if (config.toolbar.items) {
37042 ti = config.toolbar.items ;
37043 delete config.toolbar.items ;
37047 this.toolbar.render(this.wrapEl, 'before');
37048 for(var i =0;i < ti.length;i++) {
37049 // Roo.log(['add child', items[i]]);
37050 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37052 this.toolbar.items = nitems;
37053 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37054 delete config.toolbar;
37058 // xtype created footer. - not sure if will work as we normally have to render first..
37059 if (this.footer && !this.footer.el && this.footer.xtype) {
37060 if (!this.wrapEl) {
37061 this.wrapEl = this.el.wrap();
37064 this.footer.container = this.wrapEl.createChild();
37066 this.footer = Roo.factory(this.footer, Roo);
37071 if(typeof config == "string"){
37072 this.title = config;
37074 Roo.apply(this, config);
37078 this.resizeEl = Roo.get(this.resizeEl, true);
37080 this.resizeEl = this.el;
37082 // handle view.xtype
37090 * Fires when this panel is activated.
37091 * @param {Roo.ContentPanel} this
37095 * @event deactivate
37096 * Fires when this panel is activated.
37097 * @param {Roo.ContentPanel} this
37099 "deactivate" : true,
37103 * Fires when this panel is resized if fitToFrame is true.
37104 * @param {Roo.ContentPanel} this
37105 * @param {Number} width The width after any component adjustments
37106 * @param {Number} height The height after any component adjustments
37112 * Fires when this tab is created
37113 * @param {Roo.ContentPanel} this
37124 if(this.autoScroll){
37125 this.resizeEl.setStyle("overflow", "auto");
37127 // fix randome scrolling
37128 //this.el.on('scroll', function() {
37129 // Roo.log('fix random scolling');
37130 // this.scrollTo('top',0);
37133 content = content || this.content;
37135 this.setContent(content);
37137 if(config && config.url){
37138 this.setUrl(this.url, this.params, this.loadOnce);
37143 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37145 if (this.view && typeof(this.view.xtype) != 'undefined') {
37146 this.view.el = this.el.appendChild(document.createElement("div"));
37147 this.view = Roo.factory(this.view);
37148 this.view.render && this.view.render(false, '');
37152 this.fireEvent('render', this);
37155 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37159 setRegion : function(region){
37160 this.region = region;
37161 this.setActiveClass(region && !this.background);
37165 setActiveClass: function(state)
37168 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37169 this.el.setStyle('position','relative');
37171 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37172 this.el.setStyle('position', 'absolute');
37177 * Returns the toolbar for this Panel if one was configured.
37178 * @return {Roo.Toolbar}
37180 getToolbar : function(){
37181 return this.toolbar;
37184 setActiveState : function(active)
37186 this.active = active;
37187 this.setActiveClass(active);
37189 if(this.fireEvent("deactivate", this) === false){
37194 this.fireEvent("activate", this);
37198 * Updates this panel's element
37199 * @param {String} content The new content
37200 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37202 setContent : function(content, loadScripts){
37203 this.el.update(content, loadScripts);
37206 ignoreResize : function(w, h){
37207 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37210 this.lastSize = {width: w, height: h};
37215 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37216 * @return {Roo.UpdateManager} The UpdateManager
37218 getUpdateManager : function(){
37219 return this.el.getUpdateManager();
37222 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37223 * @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:
37226 url: "your-url.php",
37227 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37228 callback: yourFunction,
37229 scope: yourObject, //(optional scope)
37232 text: "Loading...",
37237 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37238 * 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.
37239 * @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}
37240 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37241 * @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.
37242 * @return {Roo.ContentPanel} this
37245 var um = this.el.getUpdateManager();
37246 um.update.apply(um, arguments);
37252 * 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.
37253 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37254 * @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)
37255 * @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)
37256 * @return {Roo.UpdateManager} The UpdateManager
37258 setUrl : function(url, params, loadOnce){
37259 if(this.refreshDelegate){
37260 this.removeListener("activate", this.refreshDelegate);
37262 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37263 this.on("activate", this.refreshDelegate);
37264 return this.el.getUpdateManager();
37267 _handleRefresh : function(url, params, loadOnce){
37268 if(!loadOnce || !this.loaded){
37269 var updater = this.el.getUpdateManager();
37270 updater.update(url, params, this._setLoaded.createDelegate(this));
37274 _setLoaded : function(){
37275 this.loaded = true;
37279 * Returns this panel's id
37282 getId : function(){
37287 * Returns this panel's element - used by regiosn to add.
37288 * @return {Roo.Element}
37290 getEl : function(){
37291 return this.wrapEl || this.el;
37296 adjustForComponents : function(width, height)
37298 //Roo.log('adjustForComponents ');
37299 if(this.resizeEl != this.el){
37300 width -= this.el.getFrameWidth('lr');
37301 height -= this.el.getFrameWidth('tb');
37304 var te = this.toolbar.getEl();
37305 te.setWidth(width);
37306 height -= te.getHeight();
37309 var te = this.footer.getEl();
37310 te.setWidth(width);
37311 height -= te.getHeight();
37315 if(this.adjustments){
37316 width += this.adjustments[0];
37317 height += this.adjustments[1];
37319 return {"width": width, "height": height};
37322 setSize : function(width, height){
37323 if(this.fitToFrame && !this.ignoreResize(width, height)){
37324 if(this.fitContainer && this.resizeEl != this.el){
37325 this.el.setSize(width, height);
37327 var size = this.adjustForComponents(width, height);
37328 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37329 this.fireEvent('resize', this, size.width, size.height);
37334 * Returns this panel's title
37337 getTitle : function(){
37339 if (typeof(this.title) != 'object') {
37344 for (var k in this.title) {
37345 if (!this.title.hasOwnProperty(k)) {
37349 if (k.indexOf('-') >= 0) {
37350 var s = k.split('-');
37351 for (var i = 0; i<s.length; i++) {
37352 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37355 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37362 * Set this panel's title
37363 * @param {String} title
37365 setTitle : function(title){
37366 this.title = title;
37368 this.region.updatePanelTitle(this, title);
37373 * Returns true is this panel was configured to be closable
37374 * @return {Boolean}
37376 isClosable : function(){
37377 return this.closable;
37380 beforeSlide : function(){
37382 this.resizeEl.clip();
37385 afterSlide : function(){
37387 this.resizeEl.unclip();
37391 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37392 * Will fail silently if the {@link #setUrl} method has not been called.
37393 * This does not activate the panel, just updates its content.
37395 refresh : function(){
37396 if(this.refreshDelegate){
37397 this.loaded = false;
37398 this.refreshDelegate();
37403 * Destroys this panel
37405 destroy : function(){
37406 this.el.removeAllListeners();
37407 var tempEl = document.createElement("span");
37408 tempEl.appendChild(this.el.dom);
37409 tempEl.innerHTML = "";
37415 * form - if the content panel contains a form - this is a reference to it.
37416 * @type {Roo.form.Form}
37420 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37421 * This contains a reference to it.
37427 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37437 * @param {Object} cfg Xtype definition of item to add.
37441 getChildContainer: function () {
37442 return this.getEl();
37447 var ret = new Roo.factory(cfg);
37452 if (cfg.xtype.match(/^Form$/)) {
37455 //if (this.footer) {
37456 // el = this.footer.container.insertSibling(false, 'before');
37458 el = this.el.createChild();
37461 this.form = new Roo.form.Form(cfg);
37464 if ( this.form.allItems.length) {
37465 this.form.render(el.dom);
37469 // should only have one of theses..
37470 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37471 // views.. should not be just added - used named prop 'view''
37473 cfg.el = this.el.appendChild(document.createElement("div"));
37476 var ret = new Roo.factory(cfg);
37478 ret.render && ret.render(false, ''); // render blank..
37488 * @class Roo.bootstrap.panel.Grid
37489 * @extends Roo.bootstrap.panel.Content
37491 * Create a new GridPanel.
37492 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37493 * @param {Object} config A the config object
37499 Roo.bootstrap.panel.Grid = function(config)
37503 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37504 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37506 config.el = this.wrapper;
37507 //this.el = this.wrapper;
37509 if (config.container) {
37510 // ctor'ed from a Border/panel.grid
37513 this.wrapper.setStyle("overflow", "hidden");
37514 this.wrapper.addClass('roo-grid-container');
37519 if(config.toolbar){
37520 var tool_el = this.wrapper.createChild();
37521 this.toolbar = Roo.factory(config.toolbar);
37523 if (config.toolbar.items) {
37524 ti = config.toolbar.items ;
37525 delete config.toolbar.items ;
37529 this.toolbar.render(tool_el);
37530 for(var i =0;i < ti.length;i++) {
37531 // Roo.log(['add child', items[i]]);
37532 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37534 this.toolbar.items = nitems;
37536 delete config.toolbar;
37539 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37540 config.grid.scrollBody = true;;
37541 config.grid.monitorWindowResize = false; // turn off autosizing
37542 config.grid.autoHeight = false;
37543 config.grid.autoWidth = false;
37545 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37547 if (config.background) {
37548 // render grid on panel activation (if panel background)
37549 this.on('activate', function(gp) {
37550 if (!gp.grid.rendered) {
37551 gp.grid.render(this.wrapper);
37552 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37557 this.grid.render(this.wrapper);
37558 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37561 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37562 // ??? needed ??? config.el = this.wrapper;
37567 // xtype created footer. - not sure if will work as we normally have to render first..
37568 if (this.footer && !this.footer.el && this.footer.xtype) {
37570 var ctr = this.grid.getView().getFooterPanel(true);
37571 this.footer.dataSource = this.grid.dataSource;
37572 this.footer = Roo.factory(this.footer, Roo);
37573 this.footer.render(ctr);
37583 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37584 getId : function(){
37585 return this.grid.id;
37589 * Returns the grid for this panel
37590 * @return {Roo.bootstrap.Table}
37592 getGrid : function(){
37596 setSize : function(width, height){
37597 if(!this.ignoreResize(width, height)){
37598 var grid = this.grid;
37599 var size = this.adjustForComponents(width, height);
37600 var gridel = grid.getGridEl();
37601 gridel.setSize(size.width, size.height);
37603 var thd = grid.getGridEl().select('thead',true).first();
37604 var tbd = grid.getGridEl().select('tbody', true).first();
37606 tbd.setSize(width, height - thd.getHeight());
37615 beforeSlide : function(){
37616 this.grid.getView().scroller.clip();
37619 afterSlide : function(){
37620 this.grid.getView().scroller.unclip();
37623 destroy : function(){
37624 this.grid.destroy();
37626 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37631 * @class Roo.bootstrap.panel.Nest
37632 * @extends Roo.bootstrap.panel.Content
37634 * Create a new Panel, that can contain a layout.Border.
37637 * @param {Roo.BorderLayout} layout The layout for this panel
37638 * @param {String/Object} config A string to set only the title or a config object
37640 Roo.bootstrap.panel.Nest = function(config)
37642 // construct with only one argument..
37643 /* FIXME - implement nicer consturctors
37644 if (layout.layout) {
37646 layout = config.layout;
37647 delete config.layout;
37649 if (layout.xtype && !layout.getEl) {
37650 // then layout needs constructing..
37651 layout = Roo.factory(layout, Roo);
37655 config.el = config.layout.getEl();
37657 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37659 config.layout.monitorWindowResize = false; // turn off autosizing
37660 this.layout = config.layout;
37661 this.layout.getEl().addClass("roo-layout-nested-layout");
37668 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37670 setSize : function(width, height){
37671 if(!this.ignoreResize(width, height)){
37672 var size = this.adjustForComponents(width, height);
37673 var el = this.layout.getEl();
37674 if (size.height < 1) {
37675 el.setWidth(size.width);
37677 el.setSize(size.width, size.height);
37679 var touch = el.dom.offsetWidth;
37680 this.layout.layout();
37681 // ie requires a double layout on the first pass
37682 if(Roo.isIE && !this.initialized){
37683 this.initialized = true;
37684 this.layout.layout();
37689 // activate all subpanels if not currently active..
37691 setActiveState : function(active){
37692 this.active = active;
37693 this.setActiveClass(active);
37696 this.fireEvent("deactivate", this);
37700 this.fireEvent("activate", this);
37701 // not sure if this should happen before or after..
37702 if (!this.layout) {
37703 return; // should not happen..
37706 for (var r in this.layout.regions) {
37707 reg = this.layout.getRegion(r);
37708 if (reg.getActivePanel()) {
37709 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37710 reg.setActivePanel(reg.getActivePanel());
37713 if (!reg.panels.length) {
37716 reg.showPanel(reg.getPanel(0));
37725 * Returns the nested BorderLayout for this panel
37726 * @return {Roo.BorderLayout}
37728 getLayout : function(){
37729 return this.layout;
37733 * Adds a xtype elements to the layout of the nested panel
37737 xtype : 'ContentPanel',
37744 xtype : 'NestedLayoutPanel',
37750 items : [ ... list of content panels or nested layout panels.. ]
37754 * @param {Object} cfg Xtype definition of item to add.
37756 addxtype : function(cfg) {
37757 return this.layout.addxtype(cfg);
37762 * Ext JS Library 1.1.1
37763 * Copyright(c) 2006-2007, Ext JS, LLC.
37765 * Originally Released Under LGPL - original licence link has changed is not relivant.
37768 * <script type="text/javascript">
37771 * @class Roo.TabPanel
37772 * @extends Roo.util.Observable
37773 * A lightweight tab container.
37777 // basic tabs 1, built from existing content
37778 var tabs = new Roo.TabPanel("tabs1");
37779 tabs.addTab("script", "View Script");
37780 tabs.addTab("markup", "View Markup");
37781 tabs.activate("script");
37783 // more advanced tabs, built from javascript
37784 var jtabs = new Roo.TabPanel("jtabs");
37785 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37787 // set up the UpdateManager
37788 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37789 var updater = tab2.getUpdateManager();
37790 updater.setDefaultUrl("ajax1.htm");
37791 tab2.on('activate', updater.refresh, updater, true);
37793 // Use setUrl for Ajax loading
37794 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37795 tab3.setUrl("ajax2.htm", null, true);
37798 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37801 jtabs.activate("jtabs-1");
37804 * Create a new TabPanel.
37805 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37806 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37808 Roo.bootstrap.panel.Tabs = function(config){
37810 * The container element for this TabPanel.
37811 * @type Roo.Element
37813 this.el = Roo.get(config.el);
37816 if(typeof config == "boolean"){
37817 this.tabPosition = config ? "bottom" : "top";
37819 Roo.apply(this, config);
37823 if(this.tabPosition == "bottom"){
37824 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37825 this.el.addClass("roo-tabs-bottom");
37827 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37828 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37829 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37831 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37833 if(this.tabPosition != "bottom"){
37834 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37835 * @type Roo.Element
37837 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37838 this.el.addClass("roo-tabs-top");
37842 this.bodyEl.setStyle("position", "relative");
37844 this.active = null;
37845 this.activateDelegate = this.activate.createDelegate(this);
37850 * Fires when the active tab changes
37851 * @param {Roo.TabPanel} this
37852 * @param {Roo.TabPanelItem} activePanel The new active tab
37856 * @event beforetabchange
37857 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37858 * @param {Roo.TabPanel} this
37859 * @param {Object} e Set cancel to true on this object to cancel the tab change
37860 * @param {Roo.TabPanelItem} tab The tab being changed to
37862 "beforetabchange" : true
37865 Roo.EventManager.onWindowResize(this.onResize, this);
37866 this.cpad = this.el.getPadding("lr");
37867 this.hiddenCount = 0;
37870 // toolbar on the tabbar support...
37871 if (this.toolbar) {
37872 alert("no toolbar support yet");
37873 this.toolbar = false;
37875 var tcfg = this.toolbar;
37876 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37877 this.toolbar = new Roo.Toolbar(tcfg);
37878 if (Roo.isSafari) {
37879 var tbl = tcfg.container.child('table', true);
37880 tbl.setAttribute('width', '100%');
37888 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37891 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37893 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37895 tabPosition : "top",
37897 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37899 currentTabWidth : 0,
37901 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37905 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37909 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37911 preferredTabWidth : 175,
37913 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37915 resizeTabs : false,
37917 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37919 monitorResize : true,
37921 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37926 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37927 * @param {String} id The id of the div to use <b>or create</b>
37928 * @param {String} text The text for the tab
37929 * @param {String} content (optional) Content to put in the TabPanelItem body
37930 * @param {Boolean} closable (optional) True to create a close icon on the tab
37931 * @return {Roo.TabPanelItem} The created TabPanelItem
37933 addTab : function(id, text, content, closable, tpl)
37935 var item = new Roo.bootstrap.panel.TabItem({
37939 closable : closable,
37942 this.addTabItem(item);
37944 item.setContent(content);
37950 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37951 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37952 * @return {Roo.TabPanelItem}
37954 getTab : function(id){
37955 return this.items[id];
37959 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37960 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37962 hideTab : function(id){
37963 var t = this.items[id];
37966 this.hiddenCount++;
37967 this.autoSizeTabs();
37972 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37973 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37975 unhideTab : function(id){
37976 var t = this.items[id];
37978 t.setHidden(false);
37979 this.hiddenCount--;
37980 this.autoSizeTabs();
37985 * Adds an existing {@link Roo.TabPanelItem}.
37986 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37988 addTabItem : function(item){
37989 this.items[item.id] = item;
37990 this.items.push(item);
37991 // if(this.resizeTabs){
37992 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37993 // this.autoSizeTabs();
37995 // item.autoSize();
38000 * Removes a {@link Roo.TabPanelItem}.
38001 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38003 removeTab : function(id){
38004 var items = this.items;
38005 var tab = items[id];
38006 if(!tab) { return; }
38007 var index = items.indexOf(tab);
38008 if(this.active == tab && items.length > 1){
38009 var newTab = this.getNextAvailable(index);
38014 this.stripEl.dom.removeChild(tab.pnode.dom);
38015 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38016 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38018 items.splice(index, 1);
38019 delete this.items[tab.id];
38020 tab.fireEvent("close", tab);
38021 tab.purgeListeners();
38022 this.autoSizeTabs();
38025 getNextAvailable : function(start){
38026 var items = this.items;
38028 // look for a next tab that will slide over to
38029 // replace the one being removed
38030 while(index < items.length){
38031 var item = items[++index];
38032 if(item && !item.isHidden()){
38036 // if one isn't found select the previous tab (on the left)
38039 var item = items[--index];
38040 if(item && !item.isHidden()){
38048 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38049 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38051 disableTab : function(id){
38052 var tab = this.items[id];
38053 if(tab && this.active != tab){
38059 * Enables a {@link Roo.TabPanelItem} that is disabled.
38060 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38062 enableTab : function(id){
38063 var tab = this.items[id];
38068 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38069 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38070 * @return {Roo.TabPanelItem} The TabPanelItem.
38072 activate : function(id){
38073 var tab = this.items[id];
38077 if(tab == this.active || tab.disabled){
38081 this.fireEvent("beforetabchange", this, e, tab);
38082 if(e.cancel !== true && !tab.disabled){
38084 this.active.hide();
38086 this.active = this.items[id];
38087 this.active.show();
38088 this.fireEvent("tabchange", this, this.active);
38094 * Gets the active {@link Roo.TabPanelItem}.
38095 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38097 getActiveTab : function(){
38098 return this.active;
38102 * Updates the tab body element to fit the height of the container element
38103 * for overflow scrolling
38104 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38106 syncHeight : function(targetHeight){
38107 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38108 var bm = this.bodyEl.getMargins();
38109 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38110 this.bodyEl.setHeight(newHeight);
38114 onResize : function(){
38115 if(this.monitorResize){
38116 this.autoSizeTabs();
38121 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38123 beginUpdate : function(){
38124 this.updating = true;
38128 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38130 endUpdate : function(){
38131 this.updating = false;
38132 this.autoSizeTabs();
38136 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38138 autoSizeTabs : function(){
38139 var count = this.items.length;
38140 var vcount = count - this.hiddenCount;
38141 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38144 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38145 var availWidth = Math.floor(w / vcount);
38146 var b = this.stripBody;
38147 if(b.getWidth() > w){
38148 var tabs = this.items;
38149 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38150 if(availWidth < this.minTabWidth){
38151 /*if(!this.sleft){ // incomplete scrolling code
38152 this.createScrollButtons();
38155 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38158 if(this.currentTabWidth < this.preferredTabWidth){
38159 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38165 * Returns the number of tabs in this TabPanel.
38168 getCount : function(){
38169 return this.items.length;
38173 * Resizes all the tabs to the passed width
38174 * @param {Number} The new width
38176 setTabWidth : function(width){
38177 this.currentTabWidth = width;
38178 for(var i = 0, len = this.items.length; i < len; i++) {
38179 if(!this.items[i].isHidden()) {
38180 this.items[i].setWidth(width);
38186 * Destroys this TabPanel
38187 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38189 destroy : function(removeEl){
38190 Roo.EventManager.removeResizeListener(this.onResize, this);
38191 for(var i = 0, len = this.items.length; i < len; i++){
38192 this.items[i].purgeListeners();
38194 if(removeEl === true){
38195 this.el.update("");
38200 createStrip : function(container)
38202 var strip = document.createElement("nav");
38203 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38204 container.appendChild(strip);
38208 createStripList : function(strip)
38210 // div wrapper for retard IE
38211 // returns the "tr" element.
38212 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38213 //'<div class="x-tabs-strip-wrap">'+
38214 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38215 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38216 return strip.firstChild; //.firstChild.firstChild.firstChild;
38218 createBody : function(container)
38220 var body = document.createElement("div");
38221 Roo.id(body, "tab-body");
38222 //Roo.fly(body).addClass("x-tabs-body");
38223 Roo.fly(body).addClass("tab-content");
38224 container.appendChild(body);
38227 createItemBody :function(bodyEl, id){
38228 var body = Roo.getDom(id);
38230 body = document.createElement("div");
38233 //Roo.fly(body).addClass("x-tabs-item-body");
38234 Roo.fly(body).addClass("tab-pane");
38235 bodyEl.insertBefore(body, bodyEl.firstChild);
38239 createStripElements : function(stripEl, text, closable, tpl)
38241 var td = document.createElement("li"); // was td..
38244 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38247 stripEl.appendChild(td);
38249 td.className = "x-tabs-closable";
38250 if(!this.closeTpl){
38251 this.closeTpl = new Roo.Template(
38252 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38253 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38254 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38257 var el = this.closeTpl.overwrite(td, {"text": text});
38258 var close = el.getElementsByTagName("div")[0];
38259 var inner = el.getElementsByTagName("em")[0];
38260 return {"el": el, "close": close, "inner": inner};
38263 // not sure what this is..
38264 // if(!this.tabTpl){
38265 //this.tabTpl = new Roo.Template(
38266 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38267 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38269 // this.tabTpl = new Roo.Template(
38270 // '<a href="#">' +
38271 // '<span unselectable="on"' +
38272 // (this.disableTooltips ? '' : ' title="{text}"') +
38273 // ' >{text}</span></a>'
38279 var template = tpl || this.tabTpl || false;
38283 template = new Roo.Template(
38285 '<span unselectable="on"' +
38286 (this.disableTooltips ? '' : ' title="{text}"') +
38287 ' >{text}</span></a>'
38291 switch (typeof(template)) {
38295 template = new Roo.Template(template);
38301 var el = template.overwrite(td, {"text": text});
38303 var inner = el.getElementsByTagName("span")[0];
38305 return {"el": el, "inner": inner};
38313 * @class Roo.TabPanelItem
38314 * @extends Roo.util.Observable
38315 * Represents an individual item (tab plus body) in a TabPanel.
38316 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38317 * @param {String} id The id of this TabPanelItem
38318 * @param {String} text The text for the tab of this TabPanelItem
38319 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38321 Roo.bootstrap.panel.TabItem = function(config){
38323 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38324 * @type Roo.TabPanel
38326 this.tabPanel = config.panel;
38328 * The id for this TabPanelItem
38331 this.id = config.id;
38333 this.disabled = false;
38335 this.text = config.text;
38337 this.loaded = false;
38338 this.closable = config.closable;
38341 * The body element for this TabPanelItem.
38342 * @type Roo.Element
38344 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38345 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38346 this.bodyEl.setStyle("display", "block");
38347 this.bodyEl.setStyle("zoom", "1");
38348 //this.hideAction();
38350 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38352 this.el = Roo.get(els.el);
38353 this.inner = Roo.get(els.inner, true);
38354 this.textEl = Roo.get(this.el.dom.firstChild, true);
38355 this.pnode = Roo.get(els.el.parentNode, true);
38356 // this.el.on("mousedown", this.onTabMouseDown, this);
38357 this.el.on("click", this.onTabClick, this);
38359 if(config.closable){
38360 var c = Roo.get(els.close, true);
38361 c.dom.title = this.closeText;
38362 c.addClassOnOver("close-over");
38363 c.on("click", this.closeClick, this);
38369 * Fires when this tab becomes the active tab.
38370 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38371 * @param {Roo.TabPanelItem} this
38375 * @event beforeclose
38376 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38377 * @param {Roo.TabPanelItem} this
38378 * @param {Object} e Set cancel to true on this object to cancel the close.
38380 "beforeclose": true,
38383 * Fires when this tab is closed.
38384 * @param {Roo.TabPanelItem} this
38388 * @event deactivate
38389 * Fires when this tab is no longer the active tab.
38390 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38391 * @param {Roo.TabPanelItem} this
38393 "deactivate" : true
38395 this.hidden = false;
38397 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38400 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38402 purgeListeners : function(){
38403 Roo.util.Observable.prototype.purgeListeners.call(this);
38404 this.el.removeAllListeners();
38407 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38410 this.pnode.addClass("active");
38413 this.tabPanel.stripWrap.repaint();
38415 this.fireEvent("activate", this.tabPanel, this);
38419 * Returns true if this tab is the active tab.
38420 * @return {Boolean}
38422 isActive : function(){
38423 return this.tabPanel.getActiveTab() == this;
38427 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38430 this.pnode.removeClass("active");
38432 this.fireEvent("deactivate", this.tabPanel, this);
38435 hideAction : function(){
38436 this.bodyEl.hide();
38437 this.bodyEl.setStyle("position", "absolute");
38438 this.bodyEl.setLeft("-20000px");
38439 this.bodyEl.setTop("-20000px");
38442 showAction : function(){
38443 this.bodyEl.setStyle("position", "relative");
38444 this.bodyEl.setTop("");
38445 this.bodyEl.setLeft("");
38446 this.bodyEl.show();
38450 * Set the tooltip for the tab.
38451 * @param {String} tooltip The tab's tooltip
38453 setTooltip : function(text){
38454 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38455 this.textEl.dom.qtip = text;
38456 this.textEl.dom.removeAttribute('title');
38458 this.textEl.dom.title = text;
38462 onTabClick : function(e){
38463 e.preventDefault();
38464 this.tabPanel.activate(this.id);
38467 onTabMouseDown : function(e){
38468 e.preventDefault();
38469 this.tabPanel.activate(this.id);
38472 getWidth : function(){
38473 return this.inner.getWidth();
38476 setWidth : function(width){
38477 var iwidth = width - this.pnode.getPadding("lr");
38478 this.inner.setWidth(iwidth);
38479 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38480 this.pnode.setWidth(width);
38484 * Show or hide the tab
38485 * @param {Boolean} hidden True to hide or false to show.
38487 setHidden : function(hidden){
38488 this.hidden = hidden;
38489 this.pnode.setStyle("display", hidden ? "none" : "");
38493 * Returns true if this tab is "hidden"
38494 * @return {Boolean}
38496 isHidden : function(){
38497 return this.hidden;
38501 * Returns the text for this tab
38504 getText : function(){
38508 autoSize : function(){
38509 //this.el.beginMeasure();
38510 this.textEl.setWidth(1);
38512 * #2804 [new] Tabs in Roojs
38513 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38515 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38516 //this.el.endMeasure();
38520 * Sets the text for the tab (Note: this also sets the tooltip text)
38521 * @param {String} text The tab's text and tooltip
38523 setText : function(text){
38525 this.textEl.update(text);
38526 this.setTooltip(text);
38527 //if(!this.tabPanel.resizeTabs){
38528 // this.autoSize();
38532 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38534 activate : function(){
38535 this.tabPanel.activate(this.id);
38539 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38541 disable : function(){
38542 if(this.tabPanel.active != this){
38543 this.disabled = true;
38544 this.pnode.addClass("disabled");
38549 * Enables this TabPanelItem if it was previously disabled.
38551 enable : function(){
38552 this.disabled = false;
38553 this.pnode.removeClass("disabled");
38557 * Sets the content for this TabPanelItem.
38558 * @param {String} content The content
38559 * @param {Boolean} loadScripts true to look for and load scripts
38561 setContent : function(content, loadScripts){
38562 this.bodyEl.update(content, loadScripts);
38566 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38567 * @return {Roo.UpdateManager} The UpdateManager
38569 getUpdateManager : function(){
38570 return this.bodyEl.getUpdateManager();
38574 * Set a URL to be used to load the content for this TabPanelItem.
38575 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38576 * @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)
38577 * @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)
38578 * @return {Roo.UpdateManager} The UpdateManager
38580 setUrl : function(url, params, loadOnce){
38581 if(this.refreshDelegate){
38582 this.un('activate', this.refreshDelegate);
38584 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38585 this.on("activate", this.refreshDelegate);
38586 return this.bodyEl.getUpdateManager();
38590 _handleRefresh : function(url, params, loadOnce){
38591 if(!loadOnce || !this.loaded){
38592 var updater = this.bodyEl.getUpdateManager();
38593 updater.update(url, params, this._setLoaded.createDelegate(this));
38598 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38599 * Will fail silently if the setUrl method has not been called.
38600 * This does not activate the panel, just updates its content.
38602 refresh : function(){
38603 if(this.refreshDelegate){
38604 this.loaded = false;
38605 this.refreshDelegate();
38610 _setLoaded : function(){
38611 this.loaded = true;
38615 closeClick : function(e){
38618 this.fireEvent("beforeclose", this, o);
38619 if(o.cancel !== true){
38620 this.tabPanel.removeTab(this.id);
38624 * The text displayed in the tooltip for the close icon.
38627 closeText : "Close this tab"
38630 * This script refer to:
38631 * Title: International Telephone Input
38632 * Author: Jack O'Connor
38633 * Code version: v12.1.12
38634 * Availability: https://github.com/jackocnr/intl-tel-input.git
38637 Roo.bootstrap.PhoneInputData = function() {
38640 "Afghanistan (افغانستان)",
38645 "Albania (Shqipëri)",
38650 "Algeria (الجزائر)",
38675 "Antigua and Barbuda",
38685 "Armenia (Հայաստան)",
38701 "Austria (Österreich)",
38706 "Azerbaijan (Azərbaycan)",
38716 "Bahrain (البحرين)",
38721 "Bangladesh (বাংলাদেশ)",
38731 "Belarus (Беларусь)",
38736 "Belgium (België)",
38766 "Bosnia and Herzegovina (Босна и Херцеговина)",
38781 "British Indian Ocean Territory",
38786 "British Virgin Islands",
38796 "Bulgaria (България)",
38806 "Burundi (Uburundi)",
38811 "Cambodia (កម្ពុជា)",
38816 "Cameroon (Cameroun)",
38825 ["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"]
38828 "Cape Verde (Kabu Verdi)",
38833 "Caribbean Netherlands",
38844 "Central African Republic (République centrafricaine)",
38864 "Christmas Island",
38870 "Cocos (Keeling) Islands",
38881 "Comoros (جزر القمر)",
38886 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38891 "Congo (Republic) (Congo-Brazzaville)",
38911 "Croatia (Hrvatska)",
38932 "Czech Republic (Česká republika)",
38937 "Denmark (Danmark)",
38952 "Dominican Republic (República Dominicana)",
38956 ["809", "829", "849"]
38974 "Equatorial Guinea (Guinea Ecuatorial)",
38994 "Falkland Islands (Islas Malvinas)",
38999 "Faroe Islands (Føroyar)",
39020 "French Guiana (Guyane française)",
39025 "French Polynesia (Polynésie française)",
39040 "Georgia (საქართველო)",
39045 "Germany (Deutschland)",
39065 "Greenland (Kalaallit Nunaat)",
39102 "Guinea-Bissau (Guiné Bissau)",
39127 "Hungary (Magyarország)",
39132 "Iceland (Ísland)",
39152 "Iraq (العراق)",
39168 "Israel (ישראל)",
39195 "Jordan (الأردن)",
39200 "Kazakhstan (Казахстан)",
39221 "Kuwait (الكويت)",
39226 "Kyrgyzstan (Кыргызстан)",
39236 "Latvia (Latvija)",
39241 "Lebanon (لبنان)",
39256 "Libya (ليبيا)",
39266 "Lithuania (Lietuva)",
39281 "Macedonia (FYROM) (Македонија)",
39286 "Madagascar (Madagasikara)",
39316 "Marshall Islands",
39326 "Mauritania (موريتانيا)",
39331 "Mauritius (Moris)",
39352 "Moldova (Republica Moldova)",
39362 "Mongolia (Монгол)",
39367 "Montenegro (Crna Gora)",
39377 "Morocco (المغرب)",
39383 "Mozambique (Moçambique)",
39388 "Myanmar (Burma) (မြန်မာ)",
39393 "Namibia (Namibië)",
39408 "Netherlands (Nederland)",
39413 "New Caledonia (Nouvelle-Calédonie)",
39448 "North Korea (조선 민주주의 인민 공화국)",
39453 "Northern Mariana Islands",
39469 "Pakistan (پاکستان)",
39479 "Palestine (فلسطين)",
39489 "Papua New Guinea",
39531 "Réunion (La Réunion)",
39537 "Romania (România)",
39553 "Saint Barthélemy",
39564 "Saint Kitts and Nevis",
39574 "Saint Martin (Saint-Martin (partie française))",
39580 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39585 "Saint Vincent and the Grenadines",
39600 "São Tomé and Príncipe (São Tomé e Príncipe)",
39605 "Saudi Arabia (المملكة العربية السعودية)",
39610 "Senegal (Sénégal)",
39640 "Slovakia (Slovensko)",
39645 "Slovenia (Slovenija)",
39655 "Somalia (Soomaaliya)",
39665 "South Korea (대한민국)",
39670 "South Sudan (جنوب السودان)",
39680 "Sri Lanka (ශ්රී ලංකාව)",
39685 "Sudan (السودان)",
39695 "Svalbard and Jan Mayen",
39706 "Sweden (Sverige)",
39711 "Switzerland (Schweiz)",
39716 "Syria (سوريا)",
39761 "Trinidad and Tobago",
39766 "Tunisia (تونس)",
39771 "Turkey (Türkiye)",
39781 "Turks and Caicos Islands",
39791 "U.S. Virgin Islands",
39801 "Ukraine (Україна)",
39806 "United Arab Emirates (الإمارات العربية المتحدة)",
39828 "Uzbekistan (Oʻzbekiston)",
39838 "Vatican City (Città del Vaticano)",
39849 "Vietnam (Việt Nam)",
39854 "Wallis and Futuna (Wallis-et-Futuna)",
39859 "Western Sahara (الصحراء الغربية)",
39865 "Yemen (اليمن)",
39889 * This script refer to:
39890 * Title: International Telephone Input
39891 * Author: Jack O'Connor
39892 * Code version: v12.1.12
39893 * Availability: https://github.com/jackocnr/intl-tel-input.git
39897 * @class Roo.bootstrap.PhoneInput
39898 * @extends Roo.bootstrap.TriggerField
39899 * An input with International dial-code selection
39901 * @cfg {String} defaultDialCode default '+852'
39902 * @cfg {Array} preferedCountries default []
39905 * Create a new PhoneInput.
39906 * @param {Object} config Configuration options
39909 Roo.bootstrap.PhoneInput = function(config) {
39910 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39913 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39915 listWidth: undefined,
39917 selectedClass: 'active',
39919 invalidClass : "has-warning",
39921 validClass: 'has-success',
39923 allowed: '0123456789',
39928 * @cfg {String} defaultDialCode The default dial code when initializing the input
39930 defaultDialCode: '+852',
39933 * @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
39935 preferedCountries: false,
39937 getAutoCreate : function()
39939 var data = Roo.bootstrap.PhoneInputData();
39940 var align = this.labelAlign || this.parentLabelAlign();
39943 this.allCountries = [];
39944 this.dialCodeMapping = [];
39946 for (var i = 0; i < data.length; i++) {
39948 this.allCountries[i] = {
39952 priority: c[3] || 0,
39953 areaCodes: c[4] || null
39955 this.dialCodeMapping[c[2]] = {
39958 priority: c[3] || 0,
39959 areaCodes: c[4] || null
39971 // type: 'number', -- do not use number - we get the flaky up/down arrows.
39972 maxlength: this.max_length,
39973 cls : 'form-control tel-input',
39974 autocomplete: 'new-password'
39977 var hiddenInput = {
39980 cls: 'hidden-tel-input'
39984 hiddenInput.name = this.name;
39987 if (this.disabled) {
39988 input.disabled = true;
39991 var flag_container = {
40008 cls: this.hasFeedback ? 'has-feedback' : '',
40014 cls: 'dial-code-holder',
40021 cls: 'roo-select2-container input-group',
40028 if (this.fieldLabel.length) {
40031 tooltip: 'This field is required'
40037 cls: 'control-label',
40043 html: this.fieldLabel
40046 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40052 if(this.indicatorpos == 'right') {
40053 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40060 if(align == 'left') {
40068 if(this.labelWidth > 12){
40069 label.style = "width: " + this.labelWidth + 'px';
40071 if(this.labelWidth < 13 && this.labelmd == 0){
40072 this.labelmd = this.labelWidth;
40074 if(this.labellg > 0){
40075 label.cls += ' col-lg-' + this.labellg;
40076 input.cls += ' col-lg-' + (12 - this.labellg);
40078 if(this.labelmd > 0){
40079 label.cls += ' col-md-' + this.labelmd;
40080 container.cls += ' col-md-' + (12 - this.labelmd);
40082 if(this.labelsm > 0){
40083 label.cls += ' col-sm-' + this.labelsm;
40084 container.cls += ' col-sm-' + (12 - this.labelsm);
40086 if(this.labelxs > 0){
40087 label.cls += ' col-xs-' + this.labelxs;
40088 container.cls += ' col-xs-' + (12 - this.labelxs);
40098 var settings = this;
40100 ['xs','sm','md','lg'].map(function(size){
40101 if (settings[size]) {
40102 cfg.cls += ' col-' + size + '-' + settings[size];
40106 this.store = new Roo.data.Store({
40107 proxy : new Roo.data.MemoryProxy({}),
40108 reader : new Roo.data.JsonReader({
40119 'name' : 'dialCode',
40123 'name' : 'priority',
40127 'name' : 'areaCodes',
40134 if(!this.preferedCountries) {
40135 this.preferedCountries = [
40142 var p = this.preferedCountries.reverse();
40145 for (var i = 0; i < p.length; i++) {
40146 for (var j = 0; j < this.allCountries.length; j++) {
40147 if(this.allCountries[j].iso2 == p[i]) {
40148 var t = this.allCountries[j];
40149 this.allCountries.splice(j,1);
40150 this.allCountries.unshift(t);
40156 this.store.proxy.data = {
40158 data: this.allCountries
40164 initEvents : function()
40167 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40169 this.indicator = this.indicatorEl();
40170 this.flag = this.flagEl();
40171 this.dialCodeHolder = this.dialCodeHolderEl();
40173 this.trigger = this.el.select('div.flag-box',true).first();
40174 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40179 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40180 _this.list.setWidth(lw);
40183 this.list.on('mouseover', this.onViewOver, this);
40184 this.list.on('mousemove', this.onViewMove, this);
40185 this.inputEl().on("keyup", this.onKeyUp, this);
40186 this.inputEl().on("keypress", this.onKeyPress, this);
40188 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40190 this.view = new Roo.View(this.list, this.tpl, {
40191 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40194 this.view.on('click', this.onViewClick, this);
40195 this.setValue(this.defaultDialCode);
40198 onTriggerClick : function(e)
40200 Roo.log('trigger click');
40205 if(this.isExpanded()){
40207 this.hasFocus = false;
40209 this.store.load({});
40210 this.hasFocus = true;
40215 isExpanded : function()
40217 return this.list.isVisible();
40220 collapse : function()
40222 if(!this.isExpanded()){
40226 Roo.get(document).un('mousedown', this.collapseIf, this);
40227 Roo.get(document).un('mousewheel', this.collapseIf, this);
40228 this.fireEvent('collapse', this);
40232 expand : function()
40236 if(this.isExpanded() || !this.hasFocus){
40240 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40241 this.list.setWidth(lw);
40244 this.restrictHeight();
40246 Roo.get(document).on('mousedown', this.collapseIf, this);
40247 Roo.get(document).on('mousewheel', this.collapseIf, this);
40249 this.fireEvent('expand', this);
40252 restrictHeight : function()
40254 this.list.alignTo(this.inputEl(), this.listAlign);
40255 this.list.alignTo(this.inputEl(), this.listAlign);
40258 onViewOver : function(e, t)
40260 if(this.inKeyMode){
40263 var item = this.view.findItemFromChild(t);
40266 var index = this.view.indexOf(item);
40267 this.select(index, false);
40272 onViewClick : function(view, doFocus, el, e)
40274 var index = this.view.getSelectedIndexes()[0];
40276 var r = this.store.getAt(index);
40279 this.onSelect(r, index);
40281 if(doFocus !== false && !this.blockFocus){
40282 this.inputEl().focus();
40286 onViewMove : function(e, t)
40288 this.inKeyMode = false;
40291 select : function(index, scrollIntoView)
40293 this.selectedIndex = index;
40294 this.view.select(index);
40295 if(scrollIntoView !== false){
40296 var el = this.view.getNode(index);
40298 this.list.scrollChildIntoView(el, false);
40303 createList : function()
40305 this.list = Roo.get(document.body).createChild({
40307 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40308 style: 'display:none'
40311 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40314 collapseIf : function(e)
40316 var in_combo = e.within(this.el);
40317 var in_list = e.within(this.list);
40318 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40320 if (in_combo || in_list || is_list) {
40326 onSelect : function(record, index)
40328 if(this.fireEvent('beforeselect', this, record, index) !== false){
40330 this.setFlagClass(record.data.iso2);
40331 this.setDialCode(record.data.dialCode);
40332 this.hasFocus = false;
40334 this.fireEvent('select', this, record, index);
40338 flagEl : function()
40340 var flag = this.el.select('div.flag',true).first();
40347 dialCodeHolderEl : function()
40349 var d = this.el.select('input.dial-code-holder',true).first();
40356 setDialCode : function(v)
40358 this.dialCodeHolder.dom.value = '+'+v;
40361 setFlagClass : function(n)
40363 this.flag.dom.className = 'flag '+n;
40366 getValue : function()
40368 var v = this.inputEl().getValue();
40369 if(this.dialCodeHolder) {
40370 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40375 setValue : function(v)
40377 var d = this.getDialCode(v);
40379 //invalid dial code
40380 if(v.length == 0 || !d || d.length == 0) {
40382 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40383 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40389 this.setFlagClass(this.dialCodeMapping[d].iso2);
40390 this.setDialCode(d);
40391 this.inputEl().dom.value = v.replace('+'+d,'');
40392 this.hiddenEl().dom.value = this.getValue();
40397 getDialCode : function(v)
40401 if (v.length == 0) {
40402 return this.dialCodeHolder.dom.value;
40406 if (v.charAt(0) != "+") {
40409 var numericChars = "";
40410 for (var i = 1; i < v.length; i++) {
40411 var c = v.charAt(i);
40414 if (this.dialCodeMapping[numericChars]) {
40415 dialCode = v.substr(1, i);
40417 if (numericChars.length == 4) {
40427 this.setValue(this.defaultDialCode);
40431 hiddenEl : function()
40433 return this.el.select('input.hidden-tel-input',true).first();
40436 // after setting val
40437 onKeyUp : function(e){
40438 this.setValue(this.getValue());
40441 onKeyPress : function(e){
40442 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40449 * @class Roo.bootstrap.MoneyField
40450 * @extends Roo.bootstrap.ComboBox
40451 * Bootstrap MoneyField class
40454 * Create a new MoneyField.
40455 * @param {Object} config Configuration options
40458 Roo.bootstrap.MoneyField = function(config) {
40460 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40464 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40467 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40469 allowDecimals : true,
40471 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40473 decimalSeparator : ".",
40475 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40477 decimalPrecision : 0,
40479 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40481 allowNegative : true,
40483 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40487 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40489 minValue : Number.NEGATIVE_INFINITY,
40491 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40493 maxValue : Number.MAX_VALUE,
40495 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40497 minText : "The minimum value for this field is {0}",
40499 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40501 maxText : "The maximum value for this field is {0}",
40503 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40504 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40506 nanText : "{0} is not a valid number",
40508 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40512 * @cfg {String} defaults currency of the MoneyField
40513 * value should be in lkey
40515 defaultCurrency : false,
40517 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40519 thousandsDelimiter : false,
40521 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40532 getAutoCreate : function()
40534 var align = this.labelAlign || this.parentLabelAlign();
40546 cls : 'form-control roo-money-amount-input',
40547 autocomplete: 'new-password'
40550 var hiddenInput = {
40554 cls: 'hidden-number-input'
40557 if(this.max_length) {
40558 input.maxlength = this.max_length;
40562 hiddenInput.name = this.name;
40565 if (this.disabled) {
40566 input.disabled = true;
40569 var clg = 12 - this.inputlg;
40570 var cmd = 12 - this.inputmd;
40571 var csm = 12 - this.inputsm;
40572 var cxs = 12 - this.inputxs;
40576 cls : 'row roo-money-field',
40580 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40584 cls: 'roo-select2-container input-group',
40588 cls : 'form-control roo-money-currency-input',
40589 autocomplete: 'new-password',
40591 name : this.currencyName
40595 cls : 'input-group-addon',
40609 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40613 cls: this.hasFeedback ? 'has-feedback' : '',
40624 if (this.fieldLabel.length) {
40627 tooltip: 'This field is required'
40633 cls: 'control-label',
40639 html: this.fieldLabel
40642 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40648 if(this.indicatorpos == 'right') {
40649 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40656 if(align == 'left') {
40664 if(this.labelWidth > 12){
40665 label.style = "width: " + this.labelWidth + 'px';
40667 if(this.labelWidth < 13 && this.labelmd == 0){
40668 this.labelmd = this.labelWidth;
40670 if(this.labellg > 0){
40671 label.cls += ' col-lg-' + this.labellg;
40672 input.cls += ' col-lg-' + (12 - this.labellg);
40674 if(this.labelmd > 0){
40675 label.cls += ' col-md-' + this.labelmd;
40676 container.cls += ' col-md-' + (12 - this.labelmd);
40678 if(this.labelsm > 0){
40679 label.cls += ' col-sm-' + this.labelsm;
40680 container.cls += ' col-sm-' + (12 - this.labelsm);
40682 if(this.labelxs > 0){
40683 label.cls += ' col-xs-' + this.labelxs;
40684 container.cls += ' col-xs-' + (12 - this.labelxs);
40695 var settings = this;
40697 ['xs','sm','md','lg'].map(function(size){
40698 if (settings[size]) {
40699 cfg.cls += ' col-' + size + '-' + settings[size];
40706 initEvents : function()
40708 this.indicator = this.indicatorEl();
40710 this.initCurrencyEvent();
40712 this.initNumberEvent();
40715 initCurrencyEvent : function()
40718 throw "can not find store for combo";
40721 this.store = Roo.factory(this.store, Roo.data);
40722 this.store.parent = this;
40726 this.triggerEl = this.el.select('.input-group-addon', true).first();
40728 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40733 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40734 _this.list.setWidth(lw);
40737 this.list.on('mouseover', this.onViewOver, this);
40738 this.list.on('mousemove', this.onViewMove, this);
40739 this.list.on('scroll', this.onViewScroll, this);
40742 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40745 this.view = new Roo.View(this.list, this.tpl, {
40746 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40749 this.view.on('click', this.onViewClick, this);
40751 this.store.on('beforeload', this.onBeforeLoad, this);
40752 this.store.on('load', this.onLoad, this);
40753 this.store.on('loadexception', this.onLoadException, this);
40755 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40756 "up" : function(e){
40757 this.inKeyMode = true;
40761 "down" : function(e){
40762 if(!this.isExpanded()){
40763 this.onTriggerClick();
40765 this.inKeyMode = true;
40770 "enter" : function(e){
40773 if(this.fireEvent("specialkey", this, e)){
40774 this.onViewClick(false);
40780 "esc" : function(e){
40784 "tab" : function(e){
40787 if(this.fireEvent("specialkey", this, e)){
40788 this.onViewClick(false);
40796 doRelay : function(foo, bar, hname){
40797 if(hname == 'down' || this.scope.isExpanded()){
40798 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40806 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40810 initNumberEvent : function(e)
40812 this.inputEl().on("keydown" , this.fireKey, this);
40813 this.inputEl().on("focus", this.onFocus, this);
40814 this.inputEl().on("blur", this.onBlur, this);
40816 this.inputEl().relayEvent('keyup', this);
40818 if(this.indicator){
40819 this.indicator.addClass('invisible');
40822 this.originalValue = this.getValue();
40824 if(this.validationEvent == 'keyup'){
40825 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40826 this.inputEl().on('keyup', this.filterValidation, this);
40828 else if(this.validationEvent !== false){
40829 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40832 if(this.selectOnFocus){
40833 this.on("focus", this.preFocus, this);
40836 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40837 this.inputEl().on("keypress", this.filterKeys, this);
40839 this.inputEl().relayEvent('keypress', this);
40842 var allowed = "0123456789";
40844 if(this.allowDecimals){
40845 allowed += this.decimalSeparator;
40848 if(this.allowNegative){
40852 if(this.thousandsDelimiter) {
40856 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40858 var keyPress = function(e){
40860 var k = e.getKey();
40862 var c = e.getCharCode();
40865 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40866 allowed.indexOf(String.fromCharCode(c)) === -1
40872 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40876 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40881 this.inputEl().on("keypress", keyPress, this);
40885 onTriggerClick : function(e)
40892 this.loadNext = false;
40894 if(this.isExpanded()){
40899 this.hasFocus = true;
40901 if(this.triggerAction == 'all') {
40902 this.doQuery(this.allQuery, true);
40906 this.doQuery(this.getRawValue());
40909 getCurrency : function()
40911 var v = this.currencyEl().getValue();
40916 restrictHeight : function()
40918 this.list.alignTo(this.currencyEl(), this.listAlign);
40919 this.list.alignTo(this.currencyEl(), this.listAlign);
40922 onViewClick : function(view, doFocus, el, e)
40924 var index = this.view.getSelectedIndexes()[0];
40926 var r = this.store.getAt(index);
40929 this.onSelect(r, index);
40933 onSelect : function(record, index){
40935 if(this.fireEvent('beforeselect', this, record, index) !== false){
40937 this.setFromCurrencyData(index > -1 ? record.data : false);
40941 this.fireEvent('select', this, record, index);
40945 setFromCurrencyData : function(o)
40949 this.lastCurrency = o;
40951 if (this.currencyField) {
40952 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40954 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40957 this.lastSelectionText = currency;
40959 //setting default currency
40960 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40961 this.setCurrency(this.defaultCurrency);
40965 this.setCurrency(currency);
40968 setFromData : function(o)
40972 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40974 this.setFromCurrencyData(c);
40979 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40981 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40984 this.setValue(value);
40988 setCurrency : function(v)
40990 this.currencyValue = v;
40993 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40998 setValue : function(v)
41000 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41006 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41008 this.inputEl().dom.value = (v == '') ? '' :
41009 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41011 if(!this.allowZero && v === '0') {
41012 this.hiddenEl().dom.value = '';
41013 this.inputEl().dom.value = '';
41020 getRawValue : function()
41022 var v = this.inputEl().getValue();
41027 getValue : function()
41029 return this.fixPrecision(this.parseValue(this.getRawValue()));
41032 parseValue : function(value)
41034 if(this.thousandsDelimiter) {
41036 r = new RegExp(",", "g");
41037 value = value.replace(r, "");
41040 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41041 return isNaN(value) ? '' : value;
41045 fixPrecision : function(value)
41047 if(this.thousandsDelimiter) {
41049 r = new RegExp(",", "g");
41050 value = value.replace(r, "");
41053 var nan = isNaN(value);
41055 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41056 return nan ? '' : value;
41058 return parseFloat(value).toFixed(this.decimalPrecision);
41061 decimalPrecisionFcn : function(v)
41063 return Math.floor(v);
41066 validateValue : function(value)
41068 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41072 var num = this.parseValue(value);
41075 this.markInvalid(String.format(this.nanText, value));
41079 if(num < this.minValue){
41080 this.markInvalid(String.format(this.minText, this.minValue));
41084 if(num > this.maxValue){
41085 this.markInvalid(String.format(this.maxText, this.maxValue));
41092 validate : function()
41094 if(this.disabled || this.allowBlank){
41099 var currency = this.getCurrency();
41101 if(this.validateValue(this.getRawValue()) && currency.length){
41106 this.markInvalid();
41110 getName: function()
41115 beforeBlur : function()
41121 var v = this.parseValue(this.getRawValue());
41128 onBlur : function()
41132 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41133 //this.el.removeClass(this.focusClass);
41136 this.hasFocus = false;
41138 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41142 var v = this.getValue();
41144 if(String(v) !== String(this.startValue)){
41145 this.fireEvent('change', this, v, this.startValue);
41148 this.fireEvent("blur", this);
41151 inputEl : function()
41153 return this.el.select('.roo-money-amount-input', true).first();
41156 currencyEl : function()
41158 return this.el.select('.roo-money-currency-input', true).first();
41161 hiddenEl : function()
41163 return this.el.select('input.hidden-number-input',true).first();