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 && Roo.bootstrap.version == 3) {
2783 if (this.allow_close && Roo.bootstrap.version == 4) {
2793 if(this.size.length){
2794 size = 'modal-' + this.size;
2801 cls: "modal-dialog " + size,
2804 cls : "modal-content",
2807 cls : 'modal-header',
2812 cls : 'modal-footer',
2816 cls: 'btn-' + this.buttonPosition
2833 modal.cls += ' fade';
2839 getChildContainer : function() {
2844 getButtonContainer : function() {
2845 return this.el.select('.modal-footer div',true).first();
2848 initEvents : function()
2850 if (this.allow_close) {
2851 this.closeEl.on('click', this.hide, this);
2853 Roo.EventManager.onWindowResize(this.resize, this, true);
2860 this.maskEl.setSize(
2861 Roo.lib.Dom.getViewWidth(true),
2862 Roo.lib.Dom.getViewHeight(true)
2865 if (this.fitwindow) {
2867 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2868 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2873 if(this.max_width !== 0) {
2875 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2878 this.setSize(w, this.height);
2882 if(this.max_height) {
2883 this.setSize(w,Math.min(
2885 Roo.lib.Dom.getViewportHeight(true) - 60
2891 if(!this.fit_content) {
2892 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2896 this.setSize(w, Math.min(
2898 this.headerEl.getHeight() +
2899 this.footerEl.getHeight() +
2900 this.getChildHeight(this.bodyEl.dom.childNodes),
2901 Roo.lib.Dom.getViewportHeight(true) - 60)
2907 setSize : function(w,h)
2918 if (!this.rendered) {
2922 //this.el.setStyle('display', 'block');
2923 this.el.removeClass('hideing');
2924 this.el.addClass('show d-block');
2925 Roo.get(document.body).addClass('modal-open');
2927 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2930 this.el.addClass('in');
2933 this.el.addClass('in');
2936 // not sure how we can show data in here..
2938 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2941 Roo.get(document.body).addClass("x-body-masked");
2943 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2944 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2945 this.maskEl.addClass('show d-block');
2949 this.fireEvent('show', this);
2951 // set zindex here - otherwise it appears to be ignored...
2952 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2955 this.items.forEach( function(e) {
2956 e.layout ? e.layout() : false;
2964 if(this.fireEvent("beforehide", this) !== false){
2965 this.maskEl.removeClass('show d-block');
2966 Roo.get(document.body).removeClass("x-body-masked");
2967 this.el.removeClass('in');
2968 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2970 if(this.animate){ // why
2971 this.el.addClass('hideing');
2973 if (!this.el.hasClass('hideing')) {
2974 return; // it's been shown again...
2976 this.el.removeClass('show d-block');
2978 Roo.get(document.body).removeClass('modal-open');
2979 this.el.removeClass('hideing');
2983 this.el.removeClass('show d-block');
2984 Roo.get(document.body).removeClass('modal-open');
2987 this.fireEvent('hide', this);
2990 isVisible : function()
2993 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2997 addButton : function(str, cb)
3001 var b = Roo.apply({}, { html : str } );
3002 b.xns = b.xns || Roo.bootstrap;
3003 b.xtype = b.xtype || 'Button';
3004 if (typeof(b.listeners) == 'undefined') {
3005 b.listeners = { click : cb.createDelegate(this) };
3008 var btn = Roo.factory(b);
3010 btn.render(this.el.select('.modal-footer div').first());
3016 setDefaultButton : function(btn)
3018 //this.el.select('.modal-footer').()
3022 resizeTo: function(w,h)
3026 this.dialogEl.setWidth(w);
3027 if (this.diff === false) {
3028 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3031 this.bodyEl.setHeight(h - this.diff);
3033 this.fireEvent('resize', this);
3036 setContentSize : function(w, h)
3040 onButtonClick: function(btn,e)
3043 this.fireEvent('btnclick', btn.name, e);
3046 * Set the title of the Dialog
3047 * @param {String} str new Title
3049 setTitle: function(str) {
3050 this.titleEl.dom.innerHTML = str;
3053 * Set the body of the Dialog
3054 * @param {String} str new Title
3056 setBody: function(str) {
3057 this.bodyEl.dom.innerHTML = str;
3060 * Set the body of the Dialog using the template
3061 * @param {Obj} data - apply this data to the template and replace the body contents.
3063 applyBody: function(obj)
3066 Roo.log("Error - using apply Body without a template");
3069 this.tmpl.overwrite(this.bodyEl, obj);
3072 getChildHeight : function(child_nodes)
3076 child_nodes.length == 0
3081 var child_height = 0;
3083 for(var i = 0; i < child_nodes.length; i++) {
3086 * for modal with tabs...
3087 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3089 var layout_childs = child_nodes[i].childNodes;
3091 for(var j = 0; j < layout_childs.length; j++) {
3093 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3095 var layout_body_childs = layout_childs[j].childNodes;
3097 for(var k = 0; k < layout_body_childs.length; k++) {
3099 if(layout_body_childs[k].classList.contains('navbar')) {
3100 child_height += layout_body_childs[k].offsetHeight;
3104 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3106 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3108 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3110 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3111 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3126 child_height += child_nodes[i].offsetHeight;
3127 // Roo.log(child_nodes[i].offsetHeight);
3130 return child_height;
3136 Roo.apply(Roo.bootstrap.Modal, {
3138 * Button config that displays a single OK button
3147 * Button config that displays Yes and No buttons
3163 * Button config that displays OK and Cancel buttons
3178 * Button config that displays Yes, No and Cancel buttons
3202 * messagebox - can be used as a replace
3206 * @class Roo.MessageBox
3207 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3211 Roo.Msg.alert('Status', 'Changes saved successfully.');
3213 // Prompt for user data:
3214 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3216 // process text value...
3220 // Show a dialog using config options:
3222 title:'Save Changes?',
3223 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3224 buttons: Roo.Msg.YESNOCANCEL,
3231 Roo.bootstrap.MessageBox = function(){
3232 var dlg, opt, mask, waitTimer;
3233 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3234 var buttons, activeTextEl, bwidth;
3238 var handleButton = function(button){
3240 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3244 var handleHide = function(){
3246 dlg.el.removeClass(opt.cls);
3249 // Roo.TaskMgr.stop(waitTimer);
3250 // waitTimer = null;
3255 var updateButtons = function(b){
3258 buttons["ok"].hide();
3259 buttons["cancel"].hide();
3260 buttons["yes"].hide();
3261 buttons["no"].hide();
3262 //dlg.footer.dom.style.display = 'none';
3265 dlg.footerEl.dom.style.display = '';
3266 for(var k in buttons){
3267 if(typeof buttons[k] != "function"){
3270 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3271 width += buttons[k].el.getWidth()+15;
3281 var handleEsc = function(d, k, e){
3282 if(opt && opt.closable !== false){
3292 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3293 * @return {Roo.BasicDialog} The BasicDialog element
3295 getDialog : function(){
3297 dlg = new Roo.bootstrap.Modal( {
3300 //constraintoviewport:false,
3302 //collapsible : false,
3307 //buttonAlign:"center",
3308 closeClick : function(){
3309 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3312 handleButton("cancel");
3317 dlg.on("hide", handleHide);
3319 //dlg.addKeyListener(27, handleEsc);
3321 this.buttons = buttons;
3322 var bt = this.buttonText;
3323 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3324 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3325 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3326 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3328 bodyEl = dlg.bodyEl.createChild({
3330 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3331 '<textarea class="roo-mb-textarea"></textarea>' +
3332 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3334 msgEl = bodyEl.dom.firstChild;
3335 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3336 textboxEl.enableDisplayMode();
3337 textboxEl.addKeyListener([10,13], function(){
3338 if(dlg.isVisible() && opt && opt.buttons){
3341 }else if(opt.buttons.yes){
3342 handleButton("yes");
3346 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3347 textareaEl.enableDisplayMode();
3348 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3349 progressEl.enableDisplayMode();
3351 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3352 var pf = progressEl.dom.firstChild;
3354 pp = Roo.get(pf.firstChild);
3355 pp.setHeight(pf.offsetHeight);
3363 * Updates the message box body text
3364 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3365 * the XHTML-compliant non-breaking space character '&#160;')
3366 * @return {Roo.MessageBox} This message box
3368 updateText : function(text)
3370 if(!dlg.isVisible() && !opt.width){
3371 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3372 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3374 msgEl.innerHTML = text || ' ';
3376 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3377 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3379 Math.min(opt.width || cw , this.maxWidth),
3380 Math.max(opt.minWidth || this.minWidth, bwidth)
3383 activeTextEl.setWidth(w);
3385 if(dlg.isVisible()){
3386 dlg.fixedcenter = false;
3388 // to big, make it scroll. = But as usual stupid IE does not support
3391 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3392 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3393 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3395 bodyEl.dom.style.height = '';
3396 bodyEl.dom.style.overflowY = '';
3399 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3401 bodyEl.dom.style.overflowX = '';
3404 dlg.setContentSize(w, bodyEl.getHeight());
3405 if(dlg.isVisible()){
3406 dlg.fixedcenter = true;
3412 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3413 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3414 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3415 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3416 * @return {Roo.MessageBox} This message box
3418 updateProgress : function(value, text){
3420 this.updateText(text);
3423 if (pp) { // weird bug on my firefox - for some reason this is not defined
3424 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3425 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3431 * Returns true if the message box is currently displayed
3432 * @return {Boolean} True if the message box is visible, else false
3434 isVisible : function(){
3435 return dlg && dlg.isVisible();
3439 * Hides the message box if it is displayed
3442 if(this.isVisible()){
3448 * Displays a new message box, or reinitializes an existing message box, based on the config options
3449 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3450 * The following config object properties are supported:
3452 Property Type Description
3453 ---------- --------------- ------------------------------------------------------------------------------------
3454 animEl String/Element An id or Element from which the message box should animate as it opens and
3455 closes (defaults to undefined)
3456 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3457 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3458 closable Boolean False to hide the top-right close button (defaults to true). Note that
3459 progress and wait dialogs will ignore this property and always hide the
3460 close button as they can only be closed programmatically.
3461 cls String A custom CSS class to apply to the message box element
3462 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3463 displayed (defaults to 75)
3464 fn Function A callback function to execute after closing the dialog. The arguments to the
3465 function will be btn (the name of the button that was clicked, if applicable,
3466 e.g. "ok"), and text (the value of the active text field, if applicable).
3467 Progress and wait dialogs will ignore this option since they do not respond to
3468 user actions and can only be closed programmatically, so any required function
3469 should be called by the same code after it closes the dialog.
3470 icon String A CSS class that provides a background image to be used as an icon for
3471 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3472 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3473 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3474 modal Boolean False to allow user interaction with the page while the message box is
3475 displayed (defaults to true)
3476 msg String A string that will replace the existing message box body text (defaults
3477 to the XHTML-compliant non-breaking space character ' ')
3478 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3479 progress Boolean True to display a progress bar (defaults to false)
3480 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3481 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3482 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3483 title String The title text
3484 value String The string value to set into the active textbox element if displayed
3485 wait Boolean True to display a progress bar (defaults to false)
3486 width Number The width of the dialog in pixels
3493 msg: 'Please enter your address:',
3495 buttons: Roo.MessageBox.OKCANCEL,
3498 animEl: 'addAddressBtn'
3501 * @param {Object} config Configuration options
3502 * @return {Roo.MessageBox} This message box
3504 show : function(options)
3507 // this causes nightmares if you show one dialog after another
3508 // especially on callbacks..
3510 if(this.isVisible()){
3513 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3514 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3515 Roo.log("New Dialog Message:" + options.msg )
3516 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3517 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3520 var d = this.getDialog();
3522 d.setTitle(opt.title || " ");
3523 d.closeEl.setDisplayed(opt.closable !== false);
3524 activeTextEl = textboxEl;
3525 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3530 textareaEl.setHeight(typeof opt.multiline == "number" ?
3531 opt.multiline : this.defaultTextHeight);
3532 activeTextEl = textareaEl;
3541 progressEl.setDisplayed(opt.progress === true);
3542 this.updateProgress(0);
3543 activeTextEl.dom.value = opt.value || "";
3545 dlg.setDefaultButton(activeTextEl);
3547 var bs = opt.buttons;
3551 }else if(bs && bs.yes){
3552 db = buttons["yes"];
3554 dlg.setDefaultButton(db);
3556 bwidth = updateButtons(opt.buttons);
3557 this.updateText(opt.msg);
3559 d.el.addClass(opt.cls);
3561 d.proxyDrag = opt.proxyDrag === true;
3562 d.modal = opt.modal !== false;
3563 d.mask = opt.modal !== false ? mask : false;
3565 // force it to the end of the z-index stack so it gets a cursor in FF
3566 document.body.appendChild(dlg.el.dom);
3567 d.animateTarget = null;
3568 d.show(options.animEl);
3574 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3575 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3576 * and closing the message box when the process is complete.
3577 * @param {String} title The title bar text
3578 * @param {String} msg The message box body text
3579 * @return {Roo.MessageBox} This message box
3581 progress : function(title, msg){
3588 minWidth: this.minProgressWidth,
3595 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3596 * If a callback function is passed it will be called after the user clicks the button, and the
3597 * id of the button that was clicked will be passed as the only parameter to the callback
3598 * (could also be the top-right close button).
3599 * @param {String} title The title bar text
3600 * @param {String} msg The message box body text
3601 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3602 * @param {Object} scope (optional) The scope of the callback function
3603 * @return {Roo.MessageBox} This message box
3605 alert : function(title, msg, fn, scope)
3620 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3621 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3622 * You are responsible for closing the message box when the process is complete.
3623 * @param {String} msg The message box body text
3624 * @param {String} title (optional) The title bar text
3625 * @return {Roo.MessageBox} This message box
3627 wait : function(msg, title){
3638 waitTimer = Roo.TaskMgr.start({
3640 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3648 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3649 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3650 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3651 * @param {String} title The title bar text
3652 * @param {String} msg The message box body text
3653 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3654 * @param {Object} scope (optional) The scope of the callback function
3655 * @return {Roo.MessageBox} This message box
3657 confirm : function(title, msg, fn, scope){
3661 buttons: this.YESNO,
3670 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3671 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3672 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3673 * (could also be the top-right close button) and the text that was entered will be passed as the two
3674 * parameters to the callback.
3675 * @param {String} title The title bar text
3676 * @param {String} msg The message box body text
3677 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3678 * @param {Object} scope (optional) The scope of the callback function
3679 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3680 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3681 * @return {Roo.MessageBox} This message box
3683 prompt : function(title, msg, fn, scope, multiline){
3687 buttons: this.OKCANCEL,
3692 multiline: multiline,
3699 * Button config that displays a single OK button
3704 * Button config that displays Yes and No buttons
3707 YESNO : {yes:true, no:true},
3709 * Button config that displays OK and Cancel buttons
3712 OKCANCEL : {ok:true, cancel:true},
3714 * Button config that displays Yes, No and Cancel buttons
3717 YESNOCANCEL : {yes:true, no:true, cancel:true},
3720 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3723 defaultTextHeight : 75,
3725 * The maximum width in pixels of the message box (defaults to 600)
3730 * The minimum width in pixels of the message box (defaults to 100)
3735 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3736 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3739 minProgressWidth : 250,
3741 * An object containing the default button text strings that can be overriden for localized language support.
3742 * Supported properties are: ok, cancel, yes and no.
3743 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3756 * Shorthand for {@link Roo.MessageBox}
3758 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3759 Roo.Msg = Roo.Msg || Roo.MessageBox;
3768 * @class Roo.bootstrap.Navbar
3769 * @extends Roo.bootstrap.Component
3770 * Bootstrap Navbar class
3773 * Create a new Navbar
3774 * @param {Object} config The config object
3778 Roo.bootstrap.Navbar = function(config){
3779 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3783 * @event beforetoggle
3784 * Fire before toggle the menu
3785 * @param {Roo.EventObject} e
3787 "beforetoggle" : true
3791 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3800 getAutoCreate : function(){
3803 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3807 initEvents :function ()
3809 //Roo.log(this.el.select('.navbar-toggle',true));
3810 this.el.select('.navbar-toggle',true).on('click', function() {
3811 if(this.fireEvent('beforetoggle', this) !== false){
3812 this.el.select('.navbar-collapse',true).toggleClass('in');
3822 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3824 var size = this.el.getSize();
3825 this.maskEl.setSize(size.width, size.height);
3826 this.maskEl.enableDisplayMode("block");
3835 getChildContainer : function()
3837 if (this.el.select('.collapse').getCount()) {
3838 return this.el.select('.collapse',true).first();
3871 * @class Roo.bootstrap.NavSimplebar
3872 * @extends Roo.bootstrap.Navbar
3873 * Bootstrap Sidebar class
3875 * @cfg {Boolean} inverse is inverted color
3877 * @cfg {String} type (nav | pills | tabs)
3878 * @cfg {Boolean} arrangement stacked | justified
3879 * @cfg {String} align (left | right) alignment
3881 * @cfg {Boolean} main (true|false) main nav bar? default false
3882 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3884 * @cfg {String} tag (header|footer|nav|div) default is nav
3890 * Create a new Sidebar
3891 * @param {Object} config The config object
3895 Roo.bootstrap.NavSimplebar = function(config){
3896 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3899 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3915 getAutoCreate : function(){
3919 tag : this.tag || 'div',
3932 this.type = this.type || 'nav';
3933 if (['tabs','pills'].indexOf(this.type)!==-1) {
3934 cfg.cn[0].cls += ' nav-' + this.type
3938 if (this.type!=='nav') {
3939 Roo.log('nav type must be nav/tabs/pills')
3941 cfg.cn[0].cls += ' navbar-nav'
3947 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3948 cfg.cn[0].cls += ' nav-' + this.arrangement;
3952 if (this.align === 'right') {
3953 cfg.cn[0].cls += ' navbar-right';
3957 cfg.cls += ' navbar-inverse';
3981 * navbar-expand-md fixed-top
3985 * @class Roo.bootstrap.NavHeaderbar
3986 * @extends Roo.bootstrap.NavSimplebar
3987 * Bootstrap Sidebar class
3989 * @cfg {String} brand what is brand
3990 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3991 * @cfg {String} brand_href href of the brand
3992 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3993 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3994 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3995 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3998 * Create a new Sidebar
3999 * @param {Object} config The config object
4003 Roo.bootstrap.NavHeaderbar = function(config){
4004 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4008 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4015 desktopCenter : false,
4018 getAutoCreate : function(){
4021 tag: this.nav || 'nav',
4022 cls: 'navbar navbar-expand-md',
4028 if (this.desktopCenter) {
4029 cn.push({cls : 'container', cn : []});
4036 cls: 'navbar-header',
4041 cls: 'navbar-toggle navbar-toggler',
4042 'data-toggle': 'collapse',
4047 html: 'Toggle navigation'
4051 cls: 'icon-bar navbar-toggler-icon'
4069 cls: 'collapse navbar-collapse',
4073 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4075 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4076 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4078 // tag can override this..
4080 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4083 if (this.brand !== '') {
4086 href: this.brand_href ? this.brand_href : '#',
4087 cls: 'navbar-brand',
4095 cfg.cls += ' main-nav';
4103 getHeaderChildContainer : function()
4105 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4106 return this.el.select('.navbar-header',true).first();
4109 return this.getChildContainer();
4113 initEvents : function()
4115 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4117 if (this.autohide) {
4122 Roo.get(document).on('scroll',function(e) {
4123 var ns = Roo.get(document).getScroll().top;
4124 var os = prevScroll;
4128 ft.removeClass('slideDown');
4129 ft.addClass('slideUp');
4132 ft.removeClass('slideUp');
4133 ft.addClass('slideDown');
4154 * @class Roo.bootstrap.NavSidebar
4155 * @extends Roo.bootstrap.Navbar
4156 * Bootstrap Sidebar class
4159 * Create a new Sidebar
4160 * @param {Object} config The config object
4164 Roo.bootstrap.NavSidebar = function(config){
4165 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4168 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4170 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4172 getAutoCreate : function(){
4177 cls: 'sidebar sidebar-nav'
4199 * @class Roo.bootstrap.NavGroup
4200 * @extends Roo.bootstrap.Component
4201 * Bootstrap NavGroup class
4202 * @cfg {String} align (left|right)
4203 * @cfg {Boolean} inverse
4204 * @cfg {String} type (nav|pills|tab) default nav
4205 * @cfg {String} navId - reference Id for navbar.
4209 * Create a new nav group
4210 * @param {Object} config The config object
4213 Roo.bootstrap.NavGroup = function(config){
4214 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4217 Roo.bootstrap.NavGroup.register(this);
4221 * Fires when the active item changes
4222 * @param {Roo.bootstrap.NavGroup} this
4223 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4224 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4231 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4242 getAutoCreate : function()
4244 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4251 if (['tabs','pills'].indexOf(this.type)!==-1) {
4252 cfg.cls += ' nav-' + this.type
4254 if (this.type!=='nav') {
4255 Roo.log('nav type must be nav/tabs/pills')
4257 cfg.cls += ' navbar-nav'
4260 if (this.parent() && this.parent().sidebar) {
4263 cls: 'dashboard-menu sidebar-menu'
4269 if (this.form === true) {
4275 if (this.align === 'right') {
4276 cfg.cls += ' navbar-right ml-md-auto';
4278 cfg.cls += ' navbar-left';
4282 if (this.align === 'right') {
4283 cfg.cls += ' navbar-right ml-md-auto';
4285 cfg.cls += ' mr-auto';
4289 cfg.cls += ' navbar-inverse';
4297 * sets the active Navigation item
4298 * @param {Roo.bootstrap.NavItem} the new current navitem
4300 setActiveItem : function(item)
4303 Roo.each(this.navItems, function(v){
4308 v.setActive(false, true);
4315 item.setActive(true, true);
4316 this.fireEvent('changed', this, item, prev);
4321 * gets the active Navigation item
4322 * @return {Roo.bootstrap.NavItem} the current navitem
4324 getActive : function()
4328 Roo.each(this.navItems, function(v){
4339 indexOfNav : function()
4343 Roo.each(this.navItems, function(v,i){
4354 * adds a Navigation item
4355 * @param {Roo.bootstrap.NavItem} the navitem to add
4357 addItem : function(cfg)
4359 var cn = new Roo.bootstrap.NavItem(cfg);
4361 cn.parentId = this.id;
4362 cn.onRender(this.el, null);
4366 * register a Navigation item
4367 * @param {Roo.bootstrap.NavItem} the navitem to add
4369 register : function(item)
4371 this.navItems.push( item);
4372 item.navId = this.navId;
4377 * clear all the Navigation item
4380 clearAll : function()
4383 this.el.dom.innerHTML = '';
4386 getNavItem: function(tabId)
4389 Roo.each(this.navItems, function(e) {
4390 if (e.tabId == tabId) {
4400 setActiveNext : function()
4402 var i = this.indexOfNav(this.getActive());
4403 if (i > this.navItems.length) {
4406 this.setActiveItem(this.navItems[i+1]);
4408 setActivePrev : function()
4410 var i = this.indexOfNav(this.getActive());
4414 this.setActiveItem(this.navItems[i-1]);
4416 clearWasActive : function(except) {
4417 Roo.each(this.navItems, function(e) {
4418 if (e.tabId != except.tabId && e.was_active) {
4419 e.was_active = false;
4426 getWasActive : function ()
4429 Roo.each(this.navItems, function(e) {
4444 Roo.apply(Roo.bootstrap.NavGroup, {
4448 * register a Navigation Group
4449 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4451 register : function(navgrp)
4453 this.groups[navgrp.navId] = navgrp;
4457 * fetch a Navigation Group based on the navigation ID
4458 * @param {string} the navgroup to add
4459 * @returns {Roo.bootstrap.NavGroup} the navgroup
4461 get: function(navId) {
4462 if (typeof(this.groups[navId]) == 'undefined') {
4464 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4466 return this.groups[navId] ;
4481 * @class Roo.bootstrap.NavItem
4482 * @extends Roo.bootstrap.Component
4483 * Bootstrap Navbar.NavItem class
4484 * @cfg {String} href link to
4485 * @cfg {String} html content of button
4486 * @cfg {String} badge text inside badge
4487 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4488 * @cfg {String} glyphicon name of glyphicon
4489 * @cfg {String} icon name of font awesome icon
4490 * @cfg {Boolean} active Is item active
4491 * @cfg {Boolean} disabled Is item disabled
4493 * @cfg {Boolean} preventDefault (true | false) default false
4494 * @cfg {String} tabId the tab that this item activates.
4495 * @cfg {String} tagtype (a|span) render as a href or span?
4496 * @cfg {Boolean} animateRef (true|false) link to element default false
4499 * Create a new Navbar Item
4500 * @param {Object} config The config object
4502 Roo.bootstrap.NavItem = function(config){
4503 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4508 * The raw click event for the entire grid.
4509 * @param {Roo.EventObject} e
4514 * Fires when the active item active state changes
4515 * @param {Roo.bootstrap.NavItem} this
4516 * @param {boolean} state the new state
4522 * Fires when scroll to element
4523 * @param {Roo.bootstrap.NavItem} this
4524 * @param {Object} options
4525 * @param {Roo.EventObject} e
4533 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4541 preventDefault : false,
4548 getAutoCreate : function(){
4557 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4559 if (this.disabled) {
4560 cfg.cls += ' disabled';
4563 if (this.href || this.html || this.glyphicon || this.icon) {
4567 href : this.href || "#",
4568 html: this.html || ''
4571 if (this.tagtype == 'a') {
4572 cfg.cn[0].cls = 'nav-link';
4575 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4578 if(this.glyphicon) {
4579 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4584 cfg.cn[0].html += " <span class='caret'></span>";
4588 if (this.badge !== '') {
4590 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4598 initEvents: function()
4600 if (typeof (this.menu) != 'undefined') {
4601 this.menu.parentType = this.xtype;
4602 this.menu.triggerEl = this.el;
4603 this.menu = this.addxtype(Roo.apply({}, this.menu));
4606 this.el.select('a',true).on('click', this.onClick, this);
4608 if(this.tagtype == 'span'){
4609 this.el.select('span',true).on('click', this.onClick, this);
4612 // at this point parent should be available..
4613 this.parent().register(this);
4616 onClick : function(e)
4618 if (e.getTarget('.dropdown-menu-item')) {
4619 // did you click on a menu itemm.... - then don't trigger onclick..
4624 this.preventDefault ||
4627 Roo.log("NavItem - prevent Default?");
4631 if (this.disabled) {
4635 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4636 if (tg && tg.transition) {
4637 Roo.log("waiting for the transitionend");
4643 //Roo.log("fire event clicked");
4644 if(this.fireEvent('click', this, e) === false){
4648 if(this.tagtype == 'span'){
4652 //Roo.log(this.href);
4653 var ael = this.el.select('a',true).first();
4656 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4657 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4658 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4659 return; // ignore... - it's a 'hash' to another page.
4661 Roo.log("NavItem - prevent Default?");
4663 this.scrollToElement(e);
4667 var p = this.parent();
4669 if (['tabs','pills'].indexOf(p.type)!==-1) {
4670 if (typeof(p.setActiveItem) !== 'undefined') {
4671 p.setActiveItem(this);
4675 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4676 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4677 // remove the collapsed menu expand...
4678 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4682 isActive: function () {
4685 setActive : function(state, fire, is_was_active)
4687 if (this.active && !state && this.navId) {
4688 this.was_active = true;
4689 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4691 nv.clearWasActive(this);
4695 this.active = state;
4698 this.el.removeClass('active');
4699 } else if (!this.el.hasClass('active')) {
4700 this.el.addClass('active');
4703 this.fireEvent('changed', this, state);
4706 // show a panel if it's registered and related..
4708 if (!this.navId || !this.tabId || !state || is_was_active) {
4712 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4716 var pan = tg.getPanelByName(this.tabId);
4720 // if we can not flip to new panel - go back to old nav highlight..
4721 if (false == tg.showPanel(pan)) {
4722 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4724 var onav = nv.getWasActive();
4726 onav.setActive(true, false, true);
4735 // this should not be here...
4736 setDisabled : function(state)
4738 this.disabled = state;
4740 this.el.removeClass('disabled');
4741 } else if (!this.el.hasClass('disabled')) {
4742 this.el.addClass('disabled');
4748 * Fetch the element to display the tooltip on.
4749 * @return {Roo.Element} defaults to this.el
4751 tooltipEl : function()
4753 return this.el.select('' + this.tagtype + '', true).first();
4756 scrollToElement : function(e)
4758 var c = document.body;
4761 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4763 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4764 c = document.documentElement;
4767 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4773 var o = target.calcOffsetsTo(c);
4780 this.fireEvent('scrollto', this, options, e);
4782 Roo.get(c).scrollTo('top', options.value, true);
4795 * <span> icon </span>
4796 * <span> text </span>
4797 * <span>badge </span>
4801 * @class Roo.bootstrap.NavSidebarItem
4802 * @extends Roo.bootstrap.NavItem
4803 * Bootstrap Navbar.NavSidebarItem class
4804 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4805 * {Boolean} open is the menu open
4806 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4807 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4808 * {String} buttonSize (sm|md|lg)the extra classes for the button
4809 * {Boolean} showArrow show arrow next to the text (default true)
4811 * Create a new Navbar Button
4812 * @param {Object} config The config object
4814 Roo.bootstrap.NavSidebarItem = function(config){
4815 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4820 * The raw click event for the entire grid.
4821 * @param {Roo.EventObject} e
4826 * Fires when the active item active state changes
4827 * @param {Roo.bootstrap.NavSidebarItem} this
4828 * @param {boolean} state the new state
4836 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4838 badgeWeight : 'default',
4844 buttonWeight : 'default',
4850 getAutoCreate : function(){
4855 href : this.href || '#',
4861 if(this.buttonView){
4864 href : this.href || '#',
4865 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4878 cfg.cls += ' active';
4881 if (this.disabled) {
4882 cfg.cls += ' disabled';
4885 cfg.cls += ' open x-open';
4888 if (this.glyphicon || this.icon) {
4889 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4890 a.cn.push({ tag : 'i', cls : c }) ;
4893 if(!this.buttonView){
4896 html : this.html || ''
4903 if (this.badge !== '') {
4904 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4910 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4913 a.cls += ' dropdown-toggle treeview' ;
4919 initEvents : function()
4921 if (typeof (this.menu) != 'undefined') {
4922 this.menu.parentType = this.xtype;
4923 this.menu.triggerEl = this.el;
4924 this.menu = this.addxtype(Roo.apply({}, this.menu));
4927 this.el.on('click', this.onClick, this);
4929 if(this.badge !== ''){
4930 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4935 onClick : function(e)
4942 if(this.preventDefault){
4946 this.fireEvent('click', this);
4949 disable : function()
4951 this.setDisabled(true);
4956 this.setDisabled(false);
4959 setDisabled : function(state)
4961 if(this.disabled == state){
4965 this.disabled = state;
4968 this.el.addClass('disabled');
4972 this.el.removeClass('disabled');
4977 setActive : function(state)
4979 if(this.active == state){
4983 this.active = state;
4986 this.el.addClass('active');
4990 this.el.removeClass('active');
4995 isActive: function ()
5000 setBadge : function(str)
5006 this.badgeEl.dom.innerHTML = str;
5023 * @class Roo.bootstrap.Row
5024 * @extends Roo.bootstrap.Component
5025 * Bootstrap Row class (contains columns...)
5029 * @param {Object} config The config object
5032 Roo.bootstrap.Row = function(config){
5033 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5036 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5038 getAutoCreate : function(){
5057 * @class Roo.bootstrap.Element
5058 * @extends Roo.bootstrap.Component
5059 * Bootstrap Element class
5060 * @cfg {String} html contents of the element
5061 * @cfg {String} tag tag of the element
5062 * @cfg {String} cls class of the element
5063 * @cfg {Boolean} preventDefault (true|false) default false
5064 * @cfg {Boolean} clickable (true|false) default false
5067 * Create a new Element
5068 * @param {Object} config The config object
5071 Roo.bootstrap.Element = function(config){
5072 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5078 * When a element is chick
5079 * @param {Roo.bootstrap.Element} this
5080 * @param {Roo.EventObject} e
5086 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5091 preventDefault: false,
5094 getAutoCreate : function(){
5098 // cls: this.cls, double assign in parent class Component.js :: onRender
5105 initEvents: function()
5107 Roo.bootstrap.Element.superclass.initEvents.call(this);
5110 this.el.on('click', this.onClick, this);
5115 onClick : function(e)
5117 if(this.preventDefault){
5121 this.fireEvent('click', this, e);
5124 getValue : function()
5126 return this.el.dom.innerHTML;
5129 setValue : function(value)
5131 this.el.dom.innerHTML = value;
5146 * @class Roo.bootstrap.Pagination
5147 * @extends Roo.bootstrap.Component
5148 * Bootstrap Pagination class
5149 * @cfg {String} size xs | sm | md | lg
5150 * @cfg {Boolean} inverse false | true
5153 * Create a new Pagination
5154 * @param {Object} config The config object
5157 Roo.bootstrap.Pagination = function(config){
5158 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5161 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5167 getAutoCreate : function(){
5173 cfg.cls += ' inverse';
5179 cfg.cls += " " + this.cls;
5197 * @class Roo.bootstrap.PaginationItem
5198 * @extends Roo.bootstrap.Component
5199 * Bootstrap PaginationItem class
5200 * @cfg {String} html text
5201 * @cfg {String} href the link
5202 * @cfg {Boolean} preventDefault (true | false) default true
5203 * @cfg {Boolean} active (true | false) default false
5204 * @cfg {Boolean} disabled default false
5208 * Create a new PaginationItem
5209 * @param {Object} config The config object
5213 Roo.bootstrap.PaginationItem = function(config){
5214 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5219 * The raw click event for the entire grid.
5220 * @param {Roo.EventObject} e
5226 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5230 preventDefault: true,
5235 getAutoCreate : function(){
5241 href : this.href ? this.href : '#',
5242 html : this.html ? this.html : ''
5252 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5256 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5262 initEvents: function() {
5264 this.el.on('click', this.onClick, this);
5267 onClick : function(e)
5269 Roo.log('PaginationItem on click ');
5270 if(this.preventDefault){
5278 this.fireEvent('click', this, e);
5294 * @class Roo.bootstrap.Slider
5295 * @extends Roo.bootstrap.Component
5296 * Bootstrap Slider class
5299 * Create a new Slider
5300 * @param {Object} config The config object
5303 Roo.bootstrap.Slider = function(config){
5304 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5307 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5309 getAutoCreate : function(){
5313 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5317 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5329 * Ext JS Library 1.1.1
5330 * Copyright(c) 2006-2007, Ext JS, LLC.
5332 * Originally Released Under LGPL - original licence link has changed is not relivant.
5335 * <script type="text/javascript">
5340 * @class Roo.grid.ColumnModel
5341 * @extends Roo.util.Observable
5342 * This is the default implementation of a ColumnModel used by the Grid. It defines
5343 * the columns in the grid.
5346 var colModel = new Roo.grid.ColumnModel([
5347 {header: "Ticker", width: 60, sortable: true, locked: true},
5348 {header: "Company Name", width: 150, sortable: true},
5349 {header: "Market Cap.", width: 100, sortable: true},
5350 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5351 {header: "Employees", width: 100, sortable: true, resizable: false}
5356 * The config options listed for this class are options which may appear in each
5357 * individual column definition.
5358 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5360 * @param {Object} config An Array of column config objects. See this class's
5361 * config objects for details.
5363 Roo.grid.ColumnModel = function(config){
5365 * The config passed into the constructor
5367 this.config = config;
5370 // if no id, create one
5371 // if the column does not have a dataIndex mapping,
5372 // map it to the order it is in the config
5373 for(var i = 0, len = config.length; i < len; i++){
5375 if(typeof c.dataIndex == "undefined"){
5378 if(typeof c.renderer == "string"){
5379 c.renderer = Roo.util.Format[c.renderer];
5381 if(typeof c.id == "undefined"){
5384 if(c.editor && c.editor.xtype){
5385 c.editor = Roo.factory(c.editor, Roo.grid);
5387 if(c.editor && c.editor.isFormField){
5388 c.editor = new Roo.grid.GridEditor(c.editor);
5390 this.lookup[c.id] = c;
5394 * The width of columns which have no width specified (defaults to 100)
5397 this.defaultWidth = 100;
5400 * Default sortable of columns which have no sortable specified (defaults to false)
5403 this.defaultSortable = false;
5407 * @event widthchange
5408 * Fires when the width of a column changes.
5409 * @param {ColumnModel} this
5410 * @param {Number} columnIndex The column index
5411 * @param {Number} newWidth The new width
5413 "widthchange": true,
5415 * @event headerchange
5416 * Fires when the text of a header changes.
5417 * @param {ColumnModel} this
5418 * @param {Number} columnIndex The column index
5419 * @param {Number} newText The new header text
5421 "headerchange": true,
5423 * @event hiddenchange
5424 * Fires when a column is hidden or "unhidden".
5425 * @param {ColumnModel} this
5426 * @param {Number} columnIndex The column index
5427 * @param {Boolean} hidden true if hidden, false otherwise
5429 "hiddenchange": true,
5431 * @event columnmoved
5432 * Fires when a column is moved.
5433 * @param {ColumnModel} this
5434 * @param {Number} oldIndex
5435 * @param {Number} newIndex
5437 "columnmoved" : true,
5439 * @event columlockchange
5440 * Fires when a column's locked state is changed
5441 * @param {ColumnModel} this
5442 * @param {Number} colIndex
5443 * @param {Boolean} locked true if locked
5445 "columnlockchange" : true
5447 Roo.grid.ColumnModel.superclass.constructor.call(this);
5449 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5451 * @cfg {String} header The header text to display in the Grid view.
5454 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5455 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5456 * specified, the column's index is used as an index into the Record's data Array.
5459 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5460 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5463 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5464 * Defaults to the value of the {@link #defaultSortable} property.
5465 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5468 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5471 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5474 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5477 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5480 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5481 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5482 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5483 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5486 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5489 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5492 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5495 * @cfg {String} cursor (Optional)
5498 * @cfg {String} tooltip (Optional)
5501 * @cfg {Number} xs (Optional)
5504 * @cfg {Number} sm (Optional)
5507 * @cfg {Number} md (Optional)
5510 * @cfg {Number} lg (Optional)
5513 * Returns the id of the column at the specified index.
5514 * @param {Number} index The column index
5515 * @return {String} the id
5517 getColumnId : function(index){
5518 return this.config[index].id;
5522 * Returns the column for a specified id.
5523 * @param {String} id The column id
5524 * @return {Object} the column
5526 getColumnById : function(id){
5527 return this.lookup[id];
5532 * Returns the column for a specified dataIndex.
5533 * @param {String} dataIndex The column dataIndex
5534 * @return {Object|Boolean} the column or false if not found
5536 getColumnByDataIndex: function(dataIndex){
5537 var index = this.findColumnIndex(dataIndex);
5538 return index > -1 ? this.config[index] : false;
5542 * Returns the index for a specified column id.
5543 * @param {String} id The column id
5544 * @return {Number} the index, or -1 if not found
5546 getIndexById : function(id){
5547 for(var i = 0, len = this.config.length; i < len; i++){
5548 if(this.config[i].id == id){
5556 * Returns the index for a specified column dataIndex.
5557 * @param {String} dataIndex The column dataIndex
5558 * @return {Number} the index, or -1 if not found
5561 findColumnIndex : function(dataIndex){
5562 for(var i = 0, len = this.config.length; i < len; i++){
5563 if(this.config[i].dataIndex == dataIndex){
5571 moveColumn : function(oldIndex, newIndex){
5572 var c = this.config[oldIndex];
5573 this.config.splice(oldIndex, 1);
5574 this.config.splice(newIndex, 0, c);
5575 this.dataMap = null;
5576 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5579 isLocked : function(colIndex){
5580 return this.config[colIndex].locked === true;
5583 setLocked : function(colIndex, value, suppressEvent){
5584 if(this.isLocked(colIndex) == value){
5587 this.config[colIndex].locked = value;
5589 this.fireEvent("columnlockchange", this, colIndex, value);
5593 getTotalLockedWidth : function(){
5595 for(var i = 0; i < this.config.length; i++){
5596 if(this.isLocked(i) && !this.isHidden(i)){
5597 this.totalWidth += this.getColumnWidth(i);
5603 getLockedCount : function(){
5604 for(var i = 0, len = this.config.length; i < len; i++){
5605 if(!this.isLocked(i)){
5610 return this.config.length;
5614 * Returns the number of columns.
5617 getColumnCount : function(visibleOnly){
5618 if(visibleOnly === true){
5620 for(var i = 0, len = this.config.length; i < len; i++){
5621 if(!this.isHidden(i)){
5627 return this.config.length;
5631 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5632 * @param {Function} fn
5633 * @param {Object} scope (optional)
5634 * @return {Array} result
5636 getColumnsBy : function(fn, scope){
5638 for(var i = 0, len = this.config.length; i < len; i++){
5639 var c = this.config[i];
5640 if(fn.call(scope||this, c, i) === true){
5648 * Returns true if the specified column is sortable.
5649 * @param {Number} col The column index
5652 isSortable : function(col){
5653 if(typeof this.config[col].sortable == "undefined"){
5654 return this.defaultSortable;
5656 return this.config[col].sortable;
5660 * Returns the rendering (formatting) function defined for the column.
5661 * @param {Number} col The column index.
5662 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5664 getRenderer : function(col){
5665 if(!this.config[col].renderer){
5666 return Roo.grid.ColumnModel.defaultRenderer;
5668 return this.config[col].renderer;
5672 * Sets the rendering (formatting) function for a column.
5673 * @param {Number} col The column index
5674 * @param {Function} fn The function to use to process the cell's raw data
5675 * to return HTML markup for the grid view. The render function is called with
5676 * the following parameters:<ul>
5677 * <li>Data value.</li>
5678 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5679 * <li>css A CSS style string to apply to the table cell.</li>
5680 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5681 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5682 * <li>Row index</li>
5683 * <li>Column index</li>
5684 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5686 setRenderer : function(col, fn){
5687 this.config[col].renderer = fn;
5691 * Returns the width for the specified column.
5692 * @param {Number} col The column index
5695 getColumnWidth : function(col){
5696 return this.config[col].width * 1 || this.defaultWidth;
5700 * Sets the width for a column.
5701 * @param {Number} col The column index
5702 * @param {Number} width The new width
5704 setColumnWidth : function(col, width, suppressEvent){
5705 this.config[col].width = width;
5706 this.totalWidth = null;
5708 this.fireEvent("widthchange", this, col, width);
5713 * Returns the total width of all columns.
5714 * @param {Boolean} includeHidden True to include hidden column widths
5717 getTotalWidth : function(includeHidden){
5718 if(!this.totalWidth){
5719 this.totalWidth = 0;
5720 for(var i = 0, len = this.config.length; i < len; i++){
5721 if(includeHidden || !this.isHidden(i)){
5722 this.totalWidth += this.getColumnWidth(i);
5726 return this.totalWidth;
5730 * Returns the header for the specified column.
5731 * @param {Number} col The column index
5734 getColumnHeader : function(col){
5735 return this.config[col].header;
5739 * Sets the header for a column.
5740 * @param {Number} col The column index
5741 * @param {String} header The new header
5743 setColumnHeader : function(col, header){
5744 this.config[col].header = header;
5745 this.fireEvent("headerchange", this, col, header);
5749 * Returns the tooltip for the specified column.
5750 * @param {Number} col The column index
5753 getColumnTooltip : function(col){
5754 return this.config[col].tooltip;
5757 * Sets the tooltip for a column.
5758 * @param {Number} col The column index
5759 * @param {String} tooltip The new tooltip
5761 setColumnTooltip : function(col, tooltip){
5762 this.config[col].tooltip = tooltip;
5766 * Returns the dataIndex for the specified column.
5767 * @param {Number} col The column index
5770 getDataIndex : function(col){
5771 return this.config[col].dataIndex;
5775 * Sets the dataIndex for a column.
5776 * @param {Number} col The column index
5777 * @param {Number} dataIndex The new dataIndex
5779 setDataIndex : function(col, dataIndex){
5780 this.config[col].dataIndex = dataIndex;
5786 * Returns true if the cell is editable.
5787 * @param {Number} colIndex The column index
5788 * @param {Number} rowIndex The row index - this is nto actually used..?
5791 isCellEditable : function(colIndex, rowIndex){
5792 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5796 * Returns the editor defined for the cell/column.
5797 * return false or null to disable editing.
5798 * @param {Number} colIndex The column index
5799 * @param {Number} rowIndex The row index
5802 getCellEditor : function(colIndex, rowIndex){
5803 return this.config[colIndex].editor;
5807 * Sets if a column is editable.
5808 * @param {Number} col The column index
5809 * @param {Boolean} editable True if the column is editable
5811 setEditable : function(col, editable){
5812 this.config[col].editable = editable;
5817 * Returns true if the column is hidden.
5818 * @param {Number} colIndex The column index
5821 isHidden : function(colIndex){
5822 return this.config[colIndex].hidden;
5827 * Returns true if the column width cannot be changed
5829 isFixed : function(colIndex){
5830 return this.config[colIndex].fixed;
5834 * Returns true if the column can be resized
5837 isResizable : function(colIndex){
5838 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5841 * Sets if a column is hidden.
5842 * @param {Number} colIndex The column index
5843 * @param {Boolean} hidden True if the column is hidden
5845 setHidden : function(colIndex, hidden){
5846 this.config[colIndex].hidden = hidden;
5847 this.totalWidth = null;
5848 this.fireEvent("hiddenchange", this, colIndex, hidden);
5852 * Sets the editor for a column.
5853 * @param {Number} col The column index
5854 * @param {Object} editor The editor object
5856 setEditor : function(col, editor){
5857 this.config[col].editor = editor;
5861 Roo.grid.ColumnModel.defaultRenderer = function(value)
5863 if(typeof value == "object") {
5866 if(typeof value == "string" && value.length < 1){
5870 return String.format("{0}", value);
5873 // Alias for backwards compatibility
5874 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5877 * Ext JS Library 1.1.1
5878 * Copyright(c) 2006-2007, Ext JS, LLC.
5880 * Originally Released Under LGPL - original licence link has changed is not relivant.
5883 * <script type="text/javascript">
5887 * @class Roo.LoadMask
5888 * A simple utility class for generically masking elements while loading data. If the element being masked has
5889 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5890 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5891 * element's UpdateManager load indicator and will be destroyed after the initial load.
5893 * Create a new LoadMask
5894 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5895 * @param {Object} config The config object
5897 Roo.LoadMask = function(el, config){
5898 this.el = Roo.get(el);
5899 Roo.apply(this, config);
5901 this.store.on('beforeload', this.onBeforeLoad, this);
5902 this.store.on('load', this.onLoad, this);
5903 this.store.on('loadexception', this.onLoadException, this);
5904 this.removeMask = false;
5906 var um = this.el.getUpdateManager();
5907 um.showLoadIndicator = false; // disable the default indicator
5908 um.on('beforeupdate', this.onBeforeLoad, this);
5909 um.on('update', this.onLoad, this);
5910 um.on('failure', this.onLoad, this);
5911 this.removeMask = true;
5915 Roo.LoadMask.prototype = {
5917 * @cfg {Boolean} removeMask
5918 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5919 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5923 * The text to display in a centered loading message box (defaults to 'Loading...')
5927 * @cfg {String} msgCls
5928 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5930 msgCls : 'x-mask-loading',
5933 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5939 * Disables the mask to prevent it from being displayed
5941 disable : function(){
5942 this.disabled = true;
5946 * Enables the mask so that it can be displayed
5948 enable : function(){
5949 this.disabled = false;
5952 onLoadException : function()
5956 if (typeof(arguments[3]) != 'undefined') {
5957 Roo.MessageBox.alert("Error loading",arguments[3]);
5961 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5962 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5969 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5974 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5978 onBeforeLoad : function(){
5980 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5985 destroy : function(){
5987 this.store.un('beforeload', this.onBeforeLoad, this);
5988 this.store.un('load', this.onLoad, this);
5989 this.store.un('loadexception', this.onLoadException, this);
5991 var um = this.el.getUpdateManager();
5992 um.un('beforeupdate', this.onBeforeLoad, this);
5993 um.un('update', this.onLoad, this);
5994 um.un('failure', this.onLoad, this);
6005 * @class Roo.bootstrap.Table
6006 * @extends Roo.bootstrap.Component
6007 * Bootstrap Table class
6008 * @cfg {String} cls table class
6009 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6010 * @cfg {String} bgcolor Specifies the background color for a table
6011 * @cfg {Number} border Specifies whether the table cells should have borders or not
6012 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6013 * @cfg {Number} cellspacing Specifies the space between cells
6014 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6015 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6016 * @cfg {String} sortable Specifies that the table should be sortable
6017 * @cfg {String} summary Specifies a summary of the content of a table
6018 * @cfg {Number} width Specifies the width of a table
6019 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6021 * @cfg {boolean} striped Should the rows be alternative striped
6022 * @cfg {boolean} bordered Add borders to the table
6023 * @cfg {boolean} hover Add hover highlighting
6024 * @cfg {boolean} condensed Format condensed
6025 * @cfg {boolean} responsive Format condensed
6026 * @cfg {Boolean} loadMask (true|false) default false
6027 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6028 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6029 * @cfg {Boolean} rowSelection (true|false) default false
6030 * @cfg {Boolean} cellSelection (true|false) default false
6031 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6032 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6033 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6034 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6038 * Create a new Table
6039 * @param {Object} config The config object
6042 Roo.bootstrap.Table = function(config){
6043 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6048 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6049 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6050 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6051 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6053 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6055 this.sm.grid = this;
6056 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6057 this.sm = this.selModel;
6058 this.sm.xmodule = this.xmodule || false;
6061 if (this.cm && typeof(this.cm.config) == 'undefined') {
6062 this.colModel = new Roo.grid.ColumnModel(this.cm);
6063 this.cm = this.colModel;
6064 this.cm.xmodule = this.xmodule || false;
6067 this.store= Roo.factory(this.store, Roo.data);
6068 this.ds = this.store;
6069 this.ds.xmodule = this.xmodule || false;
6072 if (this.footer && this.store) {
6073 this.footer.dataSource = this.ds;
6074 this.footer = Roo.factory(this.footer);
6081 * Fires when a cell is clicked
6082 * @param {Roo.bootstrap.Table} this
6083 * @param {Roo.Element} el
6084 * @param {Number} rowIndex
6085 * @param {Number} columnIndex
6086 * @param {Roo.EventObject} e
6090 * @event celldblclick
6091 * Fires when a cell is double clicked
6092 * @param {Roo.bootstrap.Table} this
6093 * @param {Roo.Element} el
6094 * @param {Number} rowIndex
6095 * @param {Number} columnIndex
6096 * @param {Roo.EventObject} e
6098 "celldblclick" : true,
6101 * Fires when a row is clicked
6102 * @param {Roo.bootstrap.Table} this
6103 * @param {Roo.Element} el
6104 * @param {Number} rowIndex
6105 * @param {Roo.EventObject} e
6109 * @event rowdblclick
6110 * Fires when a row is double clicked
6111 * @param {Roo.bootstrap.Table} this
6112 * @param {Roo.Element} el
6113 * @param {Number} rowIndex
6114 * @param {Roo.EventObject} e
6116 "rowdblclick" : true,
6119 * Fires when a mouseover occur
6120 * @param {Roo.bootstrap.Table} this
6121 * @param {Roo.Element} el
6122 * @param {Number} rowIndex
6123 * @param {Number} columnIndex
6124 * @param {Roo.EventObject} e
6129 * Fires when a mouseout occur
6130 * @param {Roo.bootstrap.Table} this
6131 * @param {Roo.Element} el
6132 * @param {Number} rowIndex
6133 * @param {Number} columnIndex
6134 * @param {Roo.EventObject} e
6139 * Fires when a row is rendered, so you can change add a style to it.
6140 * @param {Roo.bootstrap.Table} this
6141 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6145 * @event rowsrendered
6146 * Fires when all the rows have been rendered
6147 * @param {Roo.bootstrap.Table} this
6149 'rowsrendered' : true,
6151 * @event contextmenu
6152 * The raw contextmenu event for the entire grid.
6153 * @param {Roo.EventObject} e
6155 "contextmenu" : true,
6157 * @event rowcontextmenu
6158 * Fires when a row is right clicked
6159 * @param {Roo.bootstrap.Table} this
6160 * @param {Number} rowIndex
6161 * @param {Roo.EventObject} e
6163 "rowcontextmenu" : true,
6165 * @event cellcontextmenu
6166 * Fires when a cell is right clicked
6167 * @param {Roo.bootstrap.Table} this
6168 * @param {Number} rowIndex
6169 * @param {Number} cellIndex
6170 * @param {Roo.EventObject} e
6172 "cellcontextmenu" : true,
6174 * @event headercontextmenu
6175 * Fires when a header is right clicked
6176 * @param {Roo.bootstrap.Table} this
6177 * @param {Number} columnIndex
6178 * @param {Roo.EventObject} e
6180 "headercontextmenu" : true
6184 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6210 rowSelection : false,
6211 cellSelection : false,
6214 // Roo.Element - the tbody
6216 // Roo.Element - thead element
6219 container: false, // used by gridpanel...
6225 auto_hide_footer : false,
6227 getAutoCreate : function()
6229 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6236 if (this.scrollBody) {
6237 cfg.cls += ' table-body-fixed';
6240 cfg.cls += ' table-striped';
6244 cfg.cls += ' table-hover';
6246 if (this.bordered) {
6247 cfg.cls += ' table-bordered';
6249 if (this.condensed) {
6250 cfg.cls += ' table-condensed';
6252 if (this.responsive) {
6253 cfg.cls += ' table-responsive';
6257 cfg.cls+= ' ' +this.cls;
6260 // this lot should be simplifed...
6273 ].forEach(function(k) {
6281 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6284 if(this.store || this.cm){
6285 if(this.headerShow){
6286 cfg.cn.push(this.renderHeader());
6289 cfg.cn.push(this.renderBody());
6291 if(this.footerShow){
6292 cfg.cn.push(this.renderFooter());
6294 // where does this come from?
6295 //cfg.cls+= ' TableGrid';
6298 return { cn : [ cfg ] };
6301 initEvents : function()
6303 if(!this.store || !this.cm){
6306 if (this.selModel) {
6307 this.selModel.initEvents();
6311 //Roo.log('initEvents with ds!!!!');
6313 this.mainBody = this.el.select('tbody', true).first();
6314 this.mainHead = this.el.select('thead', true).first();
6315 this.mainFoot = this.el.select('tfoot', true).first();
6321 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6322 e.on('click', _this.sort, _this);
6325 this.mainBody.on("click", this.onClick, this);
6326 this.mainBody.on("dblclick", this.onDblClick, this);
6328 // why is this done????? = it breaks dialogs??
6329 //this.parent().el.setStyle('position', 'relative');
6333 this.footer.parentId = this.id;
6334 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6337 this.el.select('tfoot tr td').first().addClass('hide');
6342 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6345 this.store.on('load', this.onLoad, this);
6346 this.store.on('beforeload', this.onBeforeLoad, this);
6347 this.store.on('update', this.onUpdate, this);
6348 this.store.on('add', this.onAdd, this);
6349 this.store.on("clear", this.clear, this);
6351 this.el.on("contextmenu", this.onContextMenu, this);
6353 this.mainBody.on('scroll', this.onBodyScroll, this);
6355 this.cm.on("headerchange", this.onHeaderChange, this);
6357 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6361 onContextMenu : function(e, t)
6363 this.processEvent("contextmenu", e);
6366 processEvent : function(name, e)
6368 if (name != 'touchstart' ) {
6369 this.fireEvent(name, e);
6372 var t = e.getTarget();
6374 var cell = Roo.get(t);
6380 if(cell.findParent('tfoot', false, true)){
6384 if(cell.findParent('thead', false, true)){
6386 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6387 cell = Roo.get(t).findParent('th', false, true);
6389 Roo.log("failed to find th in thead?");
6390 Roo.log(e.getTarget());
6395 var cellIndex = cell.dom.cellIndex;
6397 var ename = name == 'touchstart' ? 'click' : name;
6398 this.fireEvent("header" + ename, this, cellIndex, e);
6403 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6404 cell = Roo.get(t).findParent('td', false, true);
6406 Roo.log("failed to find th in tbody?");
6407 Roo.log(e.getTarget());
6412 var row = cell.findParent('tr', false, true);
6413 var cellIndex = cell.dom.cellIndex;
6414 var rowIndex = row.dom.rowIndex - 1;
6418 this.fireEvent("row" + name, this, rowIndex, e);
6422 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6428 onMouseover : function(e, el)
6430 var cell = Roo.get(el);
6436 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6437 cell = cell.findParent('td', false, true);
6440 var row = cell.findParent('tr', false, true);
6441 var cellIndex = cell.dom.cellIndex;
6442 var rowIndex = row.dom.rowIndex - 1; // start from 0
6444 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6448 onMouseout : function(e, el)
6450 var cell = Roo.get(el);
6456 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6457 cell = cell.findParent('td', false, true);
6460 var row = cell.findParent('tr', false, true);
6461 var cellIndex = cell.dom.cellIndex;
6462 var rowIndex = row.dom.rowIndex - 1; // start from 0
6464 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6468 onClick : function(e, el)
6470 var cell = Roo.get(el);
6472 if(!cell || (!this.cellSelection && !this.rowSelection)){
6476 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6477 cell = cell.findParent('td', false, true);
6480 if(!cell || typeof(cell) == 'undefined'){
6484 var row = cell.findParent('tr', false, true);
6486 if(!row || typeof(row) == 'undefined'){
6490 var cellIndex = cell.dom.cellIndex;
6491 var rowIndex = this.getRowIndex(row);
6493 // why??? - should these not be based on SelectionModel?
6494 if(this.cellSelection){
6495 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6498 if(this.rowSelection){
6499 this.fireEvent('rowclick', this, row, rowIndex, e);
6505 onDblClick : function(e,el)
6507 var cell = Roo.get(el);
6509 if(!cell || (!this.cellSelection && !this.rowSelection)){
6513 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6514 cell = cell.findParent('td', false, true);
6517 if(!cell || typeof(cell) == 'undefined'){
6521 var row = cell.findParent('tr', false, true);
6523 if(!row || typeof(row) == 'undefined'){
6527 var cellIndex = cell.dom.cellIndex;
6528 var rowIndex = this.getRowIndex(row);
6530 if(this.cellSelection){
6531 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6534 if(this.rowSelection){
6535 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6539 sort : function(e,el)
6541 var col = Roo.get(el);
6543 if(!col.hasClass('sortable')){
6547 var sort = col.attr('sort');
6550 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6554 this.store.sortInfo = {field : sort, direction : dir};
6557 Roo.log("calling footer first");
6558 this.footer.onClick('first');
6561 this.store.load({ params : { start : 0 } });
6565 renderHeader : function()
6573 this.totalWidth = 0;
6575 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6577 var config = cm.config[i];
6581 cls : 'x-hcol-' + i,
6583 html: cm.getColumnHeader(i)
6588 if(typeof(config.sortable) != 'undefined' && config.sortable){
6590 c.html = '<i class="glyphicon"></i>' + c.html;
6593 if(typeof(config.lgHeader) != 'undefined'){
6594 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6597 if(typeof(config.mdHeader) != 'undefined'){
6598 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6601 if(typeof(config.smHeader) != 'undefined'){
6602 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6605 if(typeof(config.xsHeader) != 'undefined'){
6606 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6613 if(typeof(config.tooltip) != 'undefined'){
6614 c.tooltip = config.tooltip;
6617 if(typeof(config.colspan) != 'undefined'){
6618 c.colspan = config.colspan;
6621 if(typeof(config.hidden) != 'undefined' && config.hidden){
6622 c.style += ' display:none;';
6625 if(typeof(config.dataIndex) != 'undefined'){
6626 c.sort = config.dataIndex;
6631 if(typeof(config.align) != 'undefined' && config.align.length){
6632 c.style += ' text-align:' + config.align + ';';
6635 if(typeof(config.width) != 'undefined'){
6636 c.style += ' width:' + config.width + 'px;';
6637 this.totalWidth += config.width;
6639 this.totalWidth += 100; // assume minimum of 100 per column?
6642 if(typeof(config.cls) != 'undefined'){
6643 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6646 ['xs','sm','md','lg'].map(function(size){
6648 if(typeof(config[size]) == 'undefined'){
6652 if (!config[size]) { // 0 = hidden
6653 c.cls += ' hidden-' + size;
6657 c.cls += ' col-' + size + '-' + config[size];
6667 renderBody : function()
6677 colspan : this.cm.getColumnCount()
6687 renderFooter : function()
6697 colspan : this.cm.getColumnCount()
6711 // Roo.log('ds onload');
6716 var ds = this.store;
6718 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6719 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6720 if (_this.store.sortInfo) {
6722 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6723 e.select('i', true).addClass(['glyphicon-arrow-up']);
6726 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6727 e.select('i', true).addClass(['glyphicon-arrow-down']);
6732 var tbody = this.mainBody;
6734 if(ds.getCount() > 0){
6735 ds.data.each(function(d,rowIndex){
6736 var row = this.renderRow(cm, ds, rowIndex);
6738 tbody.createChild(row);
6742 if(row.cellObjects.length){
6743 Roo.each(row.cellObjects, function(r){
6744 _this.renderCellObject(r);
6751 var tfoot = this.el.select('tfoot', true).first();
6753 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6755 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6757 var total = this.ds.getTotalCount();
6759 if(this.footer.pageSize < total){
6760 this.mainFoot.show();
6764 Roo.each(this.el.select('tbody td', true).elements, function(e){
6765 e.on('mouseover', _this.onMouseover, _this);
6768 Roo.each(this.el.select('tbody td', true).elements, function(e){
6769 e.on('mouseout', _this.onMouseout, _this);
6771 this.fireEvent('rowsrendered', this);
6777 onUpdate : function(ds,record)
6779 this.refreshRow(record);
6783 onRemove : function(ds, record, index, isUpdate){
6784 if(isUpdate !== true){
6785 this.fireEvent("beforerowremoved", this, index, record);
6787 var bt = this.mainBody.dom;
6789 var rows = this.el.select('tbody > tr', true).elements;
6791 if(typeof(rows[index]) != 'undefined'){
6792 bt.removeChild(rows[index].dom);
6795 // if(bt.rows[index]){
6796 // bt.removeChild(bt.rows[index]);
6799 if(isUpdate !== true){
6800 //this.stripeRows(index);
6801 //this.syncRowHeights(index, index);
6803 this.fireEvent("rowremoved", this, index, record);
6807 onAdd : function(ds, records, rowIndex)
6809 //Roo.log('on Add called');
6810 // - note this does not handle multiple adding very well..
6811 var bt = this.mainBody.dom;
6812 for (var i =0 ; i < records.length;i++) {
6813 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6814 //Roo.log(records[i]);
6815 //Roo.log(this.store.getAt(rowIndex+i));
6816 this.insertRow(this.store, rowIndex + i, false);
6823 refreshRow : function(record){
6824 var ds = this.store, index;
6825 if(typeof record == 'number'){
6827 record = ds.getAt(index);
6829 index = ds.indexOf(record);
6831 this.insertRow(ds, index, true);
6833 this.onRemove(ds, record, index+1, true);
6835 //this.syncRowHeights(index, index);
6837 this.fireEvent("rowupdated", this, index, record);
6840 insertRow : function(dm, rowIndex, isUpdate){
6843 this.fireEvent("beforerowsinserted", this, rowIndex);
6845 //var s = this.getScrollState();
6846 var row = this.renderRow(this.cm, this.store, rowIndex);
6847 // insert before rowIndex..
6848 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6852 if(row.cellObjects.length){
6853 Roo.each(row.cellObjects, function(r){
6854 _this.renderCellObject(r);
6859 this.fireEvent("rowsinserted", this, rowIndex);
6860 //this.syncRowHeights(firstRow, lastRow);
6861 //this.stripeRows(firstRow);
6868 getRowDom : function(rowIndex)
6870 var rows = this.el.select('tbody > tr', true).elements;
6872 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6875 // returns the object tree for a tr..
6878 renderRow : function(cm, ds, rowIndex)
6880 var d = ds.getAt(rowIndex);
6884 cls : 'x-row-' + rowIndex,
6888 var cellObjects = [];
6890 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6891 var config = cm.config[i];
6893 var renderer = cm.getRenderer(i);
6897 if(typeof(renderer) !== 'undefined'){
6898 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6900 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6901 // and are rendered into the cells after the row is rendered - using the id for the element.
6903 if(typeof(value) === 'object'){
6913 rowIndex : rowIndex,
6918 this.fireEvent('rowclass', this, rowcfg);
6922 cls : rowcfg.rowClass + ' x-col-' + i,
6924 html: (typeof(value) === 'object') ? '' : value
6931 if(typeof(config.colspan) != 'undefined'){
6932 td.colspan = config.colspan;
6935 if(typeof(config.hidden) != 'undefined' && config.hidden){
6936 td.style += ' display:none;';
6939 if(typeof(config.align) != 'undefined' && config.align.length){
6940 td.style += ' text-align:' + config.align + ';';
6942 if(typeof(config.valign) != 'undefined' && config.valign.length){
6943 td.style += ' vertical-align:' + config.valign + ';';
6946 if(typeof(config.width) != 'undefined'){
6947 td.style += ' width:' + config.width + 'px;';
6950 if(typeof(config.cursor) != 'undefined'){
6951 td.style += ' cursor:' + config.cursor + ';';
6954 if(typeof(config.cls) != 'undefined'){
6955 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6958 ['xs','sm','md','lg'].map(function(size){
6960 if(typeof(config[size]) == 'undefined'){
6964 if (!config[size]) { // 0 = hidden
6965 td.cls += ' hidden-' + size;
6969 td.cls += ' col-' + size + '-' + config[size];
6977 row.cellObjects = cellObjects;
6985 onBeforeLoad : function()
6994 this.el.select('tbody', true).first().dom.innerHTML = '';
6997 * Show or hide a row.
6998 * @param {Number} rowIndex to show or hide
6999 * @param {Boolean} state hide
7001 setRowVisibility : function(rowIndex, state)
7003 var bt = this.mainBody.dom;
7005 var rows = this.el.select('tbody > tr', true).elements;
7007 if(typeof(rows[rowIndex]) == 'undefined'){
7010 rows[rowIndex].dom.style.display = state ? '' : 'none';
7014 getSelectionModel : function(){
7016 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7018 return this.selModel;
7021 * Render the Roo.bootstrap object from renderder
7023 renderCellObject : function(r)
7027 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7029 var t = r.cfg.render(r.container);
7032 Roo.each(r.cfg.cn, function(c){
7034 container: t.getChildContainer(),
7037 _this.renderCellObject(child);
7042 getRowIndex : function(row)
7046 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7057 * Returns the grid's underlying element = used by panel.Grid
7058 * @return {Element} The element
7060 getGridEl : function(){
7064 * Forces a resize - used by panel.Grid
7065 * @return {Element} The element
7067 autoSize : function()
7069 //var ctr = Roo.get(this.container.dom.parentElement);
7070 var ctr = Roo.get(this.el.dom);
7072 var thd = this.getGridEl().select('thead',true).first();
7073 var tbd = this.getGridEl().select('tbody', true).first();
7074 var tfd = this.getGridEl().select('tfoot', true).first();
7076 var cw = ctr.getWidth();
7080 tbd.setSize(ctr.getWidth(),
7081 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7083 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7086 cw = Math.max(cw, this.totalWidth);
7087 this.getGridEl().select('tr',true).setWidth(cw);
7088 // resize 'expandable coloumn?
7090 return; // we doe not have a view in this design..
7093 onBodyScroll: function()
7095 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7097 this.mainHead.setStyle({
7098 'position' : 'relative',
7099 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7105 var scrollHeight = this.mainBody.dom.scrollHeight;
7107 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7109 var height = this.mainBody.getHeight();
7111 if(scrollHeight - height == scrollTop) {
7113 var total = this.ds.getTotalCount();
7115 if(this.footer.cursor + this.footer.pageSize < total){
7117 this.footer.ds.load({
7119 start : this.footer.cursor + this.footer.pageSize,
7120 limit : this.footer.pageSize
7130 onHeaderChange : function()
7132 var header = this.renderHeader();
7133 var table = this.el.select('table', true).first();
7135 this.mainHead.remove();
7136 this.mainHead = table.createChild(header, this.mainBody, false);
7139 onHiddenChange : function(colModel, colIndex, hidden)
7141 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7142 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7144 this.CSS.updateRule(thSelector, "display", "");
7145 this.CSS.updateRule(tdSelector, "display", "");
7148 this.CSS.updateRule(thSelector, "display", "none");
7149 this.CSS.updateRule(tdSelector, "display", "none");
7152 this.onHeaderChange();
7156 setColumnWidth: function(col_index, width)
7158 // width = "md-2 xs-2..."
7159 if(!this.colModel.config[col_index]) {
7163 var w = width.split(" ");
7165 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7167 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7170 for(var j = 0; j < w.length; j++) {
7176 var size_cls = w[j].split("-");
7178 if(!Number.isInteger(size_cls[1] * 1)) {
7182 if(!this.colModel.config[col_index][size_cls[0]]) {
7186 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7190 h_row[0].classList.replace(
7191 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7192 "col-"+size_cls[0]+"-"+size_cls[1]
7195 for(var i = 0; i < rows.length; i++) {
7197 var size_cls = w[j].split("-");
7199 if(!Number.isInteger(size_cls[1] * 1)) {
7203 if(!this.colModel.config[col_index][size_cls[0]]) {
7207 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7211 rows[i].classList.replace(
7212 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7213 "col-"+size_cls[0]+"-"+size_cls[1]
7217 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7232 * @class Roo.bootstrap.TableCell
7233 * @extends Roo.bootstrap.Component
7234 * Bootstrap TableCell class
7235 * @cfg {String} html cell contain text
7236 * @cfg {String} cls cell class
7237 * @cfg {String} tag cell tag (td|th) default td
7238 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7239 * @cfg {String} align Aligns the content in a cell
7240 * @cfg {String} axis Categorizes cells
7241 * @cfg {String} bgcolor Specifies the background color of a cell
7242 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7243 * @cfg {Number} colspan Specifies the number of columns a cell should span
7244 * @cfg {String} headers Specifies one or more header cells a cell is related to
7245 * @cfg {Number} height Sets the height of a cell
7246 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7247 * @cfg {Number} rowspan Sets the number of rows a cell should span
7248 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7249 * @cfg {String} valign Vertical aligns the content in a cell
7250 * @cfg {Number} width Specifies the width of a cell
7253 * Create a new TableCell
7254 * @param {Object} config The config object
7257 Roo.bootstrap.TableCell = function(config){
7258 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7261 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7281 getAutoCreate : function(){
7282 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7302 cfg.align=this.align
7308 cfg.bgcolor=this.bgcolor
7311 cfg.charoff=this.charoff
7314 cfg.colspan=this.colspan
7317 cfg.headers=this.headers
7320 cfg.height=this.height
7323 cfg.nowrap=this.nowrap
7326 cfg.rowspan=this.rowspan
7329 cfg.scope=this.scope
7332 cfg.valign=this.valign
7335 cfg.width=this.width
7354 * @class Roo.bootstrap.TableRow
7355 * @extends Roo.bootstrap.Component
7356 * Bootstrap TableRow class
7357 * @cfg {String} cls row class
7358 * @cfg {String} align Aligns the content in a table row
7359 * @cfg {String} bgcolor Specifies a background color for a table row
7360 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7361 * @cfg {String} valign Vertical aligns the content in a table row
7364 * Create a new TableRow
7365 * @param {Object} config The config object
7368 Roo.bootstrap.TableRow = function(config){
7369 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7372 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7380 getAutoCreate : function(){
7381 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7391 cfg.align = this.align;
7394 cfg.bgcolor = this.bgcolor;
7397 cfg.charoff = this.charoff;
7400 cfg.valign = this.valign;
7418 * @class Roo.bootstrap.TableBody
7419 * @extends Roo.bootstrap.Component
7420 * Bootstrap TableBody class
7421 * @cfg {String} cls element class
7422 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7423 * @cfg {String} align Aligns the content inside the element
7424 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7425 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7428 * Create a new TableBody
7429 * @param {Object} config The config object
7432 Roo.bootstrap.TableBody = function(config){
7433 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7436 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7444 getAutoCreate : function(){
7445 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7459 cfg.align = this.align;
7462 cfg.charoff = this.charoff;
7465 cfg.valign = this.valign;
7472 // initEvents : function()
7479 // this.store = Roo.factory(this.store, Roo.data);
7480 // this.store.on('load', this.onLoad, this);
7482 // this.store.load();
7486 // onLoad: function ()
7488 // this.fireEvent('load', this);
7498 * Ext JS Library 1.1.1
7499 * Copyright(c) 2006-2007, Ext JS, LLC.
7501 * Originally Released Under LGPL - original licence link has changed is not relivant.
7504 * <script type="text/javascript">
7507 // as we use this in bootstrap.
7508 Roo.namespace('Roo.form');
7510 * @class Roo.form.Action
7511 * Internal Class used to handle form actions
7513 * @param {Roo.form.BasicForm} el The form element or its id
7514 * @param {Object} config Configuration options
7519 // define the action interface
7520 Roo.form.Action = function(form, options){
7522 this.options = options || {};
7525 * Client Validation Failed
7528 Roo.form.Action.CLIENT_INVALID = 'client';
7530 * Server Validation Failed
7533 Roo.form.Action.SERVER_INVALID = 'server';
7535 * Connect to Server Failed
7538 Roo.form.Action.CONNECT_FAILURE = 'connect';
7540 * Reading Data from Server Failed
7543 Roo.form.Action.LOAD_FAILURE = 'load';
7545 Roo.form.Action.prototype = {
7547 failureType : undefined,
7548 response : undefined,
7552 run : function(options){
7557 success : function(response){
7562 handleResponse : function(response){
7566 // default connection failure
7567 failure : function(response){
7569 this.response = response;
7570 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7571 this.form.afterAction(this, false);
7574 processResponse : function(response){
7575 this.response = response;
7576 if(!response.responseText){
7579 this.result = this.handleResponse(response);
7583 // utility functions used internally
7584 getUrl : function(appendParams){
7585 var url = this.options.url || this.form.url || this.form.el.dom.action;
7587 var p = this.getParams();
7589 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7595 getMethod : function(){
7596 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7599 getParams : function(){
7600 var bp = this.form.baseParams;
7601 var p = this.options.params;
7603 if(typeof p == "object"){
7604 p = Roo.urlEncode(Roo.applyIf(p, bp));
7605 }else if(typeof p == 'string' && bp){
7606 p += '&' + Roo.urlEncode(bp);
7609 p = Roo.urlEncode(bp);
7614 createCallback : function(){
7616 success: this.success,
7617 failure: this.failure,
7619 timeout: (this.form.timeout*1000),
7620 upload: this.form.fileUpload ? this.success : undefined
7625 Roo.form.Action.Submit = function(form, options){
7626 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7629 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7632 haveProgress : false,
7633 uploadComplete : false,
7635 // uploadProgress indicator.
7636 uploadProgress : function()
7638 if (!this.form.progressUrl) {
7642 if (!this.haveProgress) {
7643 Roo.MessageBox.progress("Uploading", "Uploading");
7645 if (this.uploadComplete) {
7646 Roo.MessageBox.hide();
7650 this.haveProgress = true;
7652 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7654 var c = new Roo.data.Connection();
7656 url : this.form.progressUrl,
7661 success : function(req){
7662 //console.log(data);
7666 rdata = Roo.decode(req.responseText)
7668 Roo.log("Invalid data from server..");
7672 if (!rdata || !rdata.success) {
7674 Roo.MessageBox.alert(Roo.encode(rdata));
7677 var data = rdata.data;
7679 if (this.uploadComplete) {
7680 Roo.MessageBox.hide();
7685 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7686 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7689 this.uploadProgress.defer(2000,this);
7692 failure: function(data) {
7693 Roo.log('progress url failed ');
7704 // run get Values on the form, so it syncs any secondary forms.
7705 this.form.getValues();
7707 var o = this.options;
7708 var method = this.getMethod();
7709 var isPost = method == 'POST';
7710 if(o.clientValidation === false || this.form.isValid()){
7712 if (this.form.progressUrl) {
7713 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7714 (new Date() * 1) + '' + Math.random());
7719 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7720 form:this.form.el.dom,
7721 url:this.getUrl(!isPost),
7723 params:isPost ? this.getParams() : null,
7724 isUpload: this.form.fileUpload
7727 this.uploadProgress();
7729 }else if (o.clientValidation !== false){ // client validation failed
7730 this.failureType = Roo.form.Action.CLIENT_INVALID;
7731 this.form.afterAction(this, false);
7735 success : function(response)
7737 this.uploadComplete= true;
7738 if (this.haveProgress) {
7739 Roo.MessageBox.hide();
7743 var result = this.processResponse(response);
7744 if(result === true || result.success){
7745 this.form.afterAction(this, true);
7749 this.form.markInvalid(result.errors);
7750 this.failureType = Roo.form.Action.SERVER_INVALID;
7752 this.form.afterAction(this, false);
7754 failure : function(response)
7756 this.uploadComplete= true;
7757 if (this.haveProgress) {
7758 Roo.MessageBox.hide();
7761 this.response = response;
7762 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7763 this.form.afterAction(this, false);
7766 handleResponse : function(response){
7767 if(this.form.errorReader){
7768 var rs = this.form.errorReader.read(response);
7771 for(var i = 0, len = rs.records.length; i < len; i++) {
7772 var r = rs.records[i];
7776 if(errors.length < 1){
7780 success : rs.success,
7786 ret = Roo.decode(response.responseText);
7790 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7800 Roo.form.Action.Load = function(form, options){
7801 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7802 this.reader = this.form.reader;
7805 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7810 Roo.Ajax.request(Roo.apply(
7811 this.createCallback(), {
7812 method:this.getMethod(),
7813 url:this.getUrl(false),
7814 params:this.getParams()
7818 success : function(response){
7820 var result = this.processResponse(response);
7821 if(result === true || !result.success || !result.data){
7822 this.failureType = Roo.form.Action.LOAD_FAILURE;
7823 this.form.afterAction(this, false);
7826 this.form.clearInvalid();
7827 this.form.setValues(result.data);
7828 this.form.afterAction(this, true);
7831 handleResponse : function(response){
7832 if(this.form.reader){
7833 var rs = this.form.reader.read(response);
7834 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7836 success : rs.success,
7840 return Roo.decode(response.responseText);
7844 Roo.form.Action.ACTION_TYPES = {
7845 'load' : Roo.form.Action.Load,
7846 'submit' : Roo.form.Action.Submit
7855 * @class Roo.bootstrap.Form
7856 * @extends Roo.bootstrap.Component
7857 * Bootstrap Form class
7858 * @cfg {String} method GET | POST (default POST)
7859 * @cfg {String} labelAlign top | left (default top)
7860 * @cfg {String} align left | right - for navbars
7861 * @cfg {Boolean} loadMask load mask when submit (default true)
7866 * @param {Object} config The config object
7870 Roo.bootstrap.Form = function(config){
7872 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7874 Roo.bootstrap.Form.popover.apply();
7878 * @event clientvalidation
7879 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7880 * @param {Form} this
7881 * @param {Boolean} valid true if the form has passed client-side validation
7883 clientvalidation: true,
7885 * @event beforeaction
7886 * Fires before any action is performed. Return false to cancel the action.
7887 * @param {Form} this
7888 * @param {Action} action The action to be performed
7892 * @event actionfailed
7893 * Fires when an action fails.
7894 * @param {Form} this
7895 * @param {Action} action The action that failed
7897 actionfailed : true,
7899 * @event actioncomplete
7900 * Fires when an action is completed.
7901 * @param {Form} this
7902 * @param {Action} action The action that completed
7904 actioncomplete : true
7908 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7911 * @cfg {String} method
7912 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7917 * The URL to use for form actions if one isn't supplied in the action options.
7920 * @cfg {Boolean} fileUpload
7921 * Set to true if this form is a file upload.
7925 * @cfg {Object} baseParams
7926 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7930 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7934 * @cfg {Sting} align (left|right) for navbar forms
7939 activeAction : null,
7942 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7943 * element by passing it or its id or mask the form itself by passing in true.
7946 waitMsgTarget : false,
7951 * @cfg {Boolean} errorMask (true|false) default false
7956 * @cfg {Number} maskOffset Default 100
7961 * @cfg {Boolean} maskBody
7965 getAutoCreate : function(){
7969 method : this.method || 'POST',
7970 id : this.id || Roo.id(),
7973 if (this.parent().xtype.match(/^Nav/)) {
7974 cfg.cls = 'navbar-form navbar-' + this.align;
7978 if (this.labelAlign == 'left' ) {
7979 cfg.cls += ' form-horizontal';
7985 initEvents : function()
7987 this.el.on('submit', this.onSubmit, this);
7988 // this was added as random key presses on the form where triggering form submit.
7989 this.el.on('keypress', function(e) {
7990 if (e.getCharCode() != 13) {
7993 // we might need to allow it for textareas.. and some other items.
7994 // check e.getTarget().
7996 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8000 Roo.log("keypress blocked");
8008 onSubmit : function(e){
8013 * Returns true if client-side validation on the form is successful.
8016 isValid : function(){
8017 var items = this.getItems();
8021 items.each(function(f){
8027 Roo.log('invalid field: ' + f.name);
8031 if(!target && f.el.isVisible(true)){
8037 if(this.errorMask && !valid){
8038 Roo.bootstrap.Form.popover.mask(this, target);
8045 * Returns true if any fields in this form have changed since their original load.
8048 isDirty : function(){
8050 var items = this.getItems();
8051 items.each(function(f){
8061 * Performs a predefined action (submit or load) or custom actions you define on this form.
8062 * @param {String} actionName The name of the action type
8063 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8064 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8065 * accept other config options):
8067 Property Type Description
8068 ---------------- --------------- ----------------------------------------------------------------------------------
8069 url String The url for the action (defaults to the form's url)
8070 method String The form method to use (defaults to the form's method, or POST if not defined)
8071 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8072 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8073 validate the form on the client (defaults to false)
8075 * @return {BasicForm} this
8077 doAction : function(action, options){
8078 if(typeof action == 'string'){
8079 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8081 if(this.fireEvent('beforeaction', this, action) !== false){
8082 this.beforeAction(action);
8083 action.run.defer(100, action);
8089 beforeAction : function(action){
8090 var o = action.options;
8095 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8097 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8100 // not really supported yet.. ??
8102 //if(this.waitMsgTarget === true){
8103 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8104 //}else if(this.waitMsgTarget){
8105 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8106 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8108 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8114 afterAction : function(action, success){
8115 this.activeAction = null;
8116 var o = action.options;
8121 Roo.get(document.body).unmask();
8127 //if(this.waitMsgTarget === true){
8128 // this.el.unmask();
8129 //}else if(this.waitMsgTarget){
8130 // this.waitMsgTarget.unmask();
8132 // Roo.MessageBox.updateProgress(1);
8133 // Roo.MessageBox.hide();
8140 Roo.callback(o.success, o.scope, [this, action]);
8141 this.fireEvent('actioncomplete', this, action);
8145 // failure condition..
8146 // we have a scenario where updates need confirming.
8147 // eg. if a locking scenario exists..
8148 // we look for { errors : { needs_confirm : true }} in the response.
8150 (typeof(action.result) != 'undefined') &&
8151 (typeof(action.result.errors) != 'undefined') &&
8152 (typeof(action.result.errors.needs_confirm) != 'undefined')
8155 Roo.log("not supported yet");
8158 Roo.MessageBox.confirm(
8159 "Change requires confirmation",
8160 action.result.errorMsg,
8165 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8175 Roo.callback(o.failure, o.scope, [this, action]);
8176 // show an error message if no failed handler is set..
8177 if (!this.hasListener('actionfailed')) {
8178 Roo.log("need to add dialog support");
8180 Roo.MessageBox.alert("Error",
8181 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8182 action.result.errorMsg :
8183 "Saving Failed, please check your entries or try again"
8188 this.fireEvent('actionfailed', this, action);
8193 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8194 * @param {String} id The value to search for
8197 findField : function(id){
8198 var items = this.getItems();
8199 var field = items.get(id);
8201 items.each(function(f){
8202 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8209 return field || null;
8212 * Mark fields in this form invalid in bulk.
8213 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8214 * @return {BasicForm} this
8216 markInvalid : function(errors){
8217 if(errors instanceof Array){
8218 for(var i = 0, len = errors.length; i < len; i++){
8219 var fieldError = errors[i];
8220 var f = this.findField(fieldError.id);
8222 f.markInvalid(fieldError.msg);
8228 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8229 field.markInvalid(errors[id]);
8233 //Roo.each(this.childForms || [], function (f) {
8234 // f.markInvalid(errors);
8241 * Set values for fields in this form in bulk.
8242 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8243 * @return {BasicForm} this
8245 setValues : function(values){
8246 if(values instanceof Array){ // array of objects
8247 for(var i = 0, len = values.length; i < len; i++){
8249 var f = this.findField(v.id);
8251 f.setValue(v.value);
8252 if(this.trackResetOnLoad){
8253 f.originalValue = f.getValue();
8257 }else{ // object hash
8260 if(typeof values[id] != 'function' && (field = this.findField(id))){
8262 if (field.setFromData &&
8264 field.displayField &&
8265 // combos' with local stores can
8266 // be queried via setValue()
8267 // to set their value..
8268 (field.store && !field.store.isLocal)
8272 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8273 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8274 field.setFromData(sd);
8276 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8278 field.setFromData(values);
8281 field.setValue(values[id]);
8285 if(this.trackResetOnLoad){
8286 field.originalValue = field.getValue();
8292 //Roo.each(this.childForms || [], function (f) {
8293 // f.setValues(values);
8300 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8301 * they are returned as an array.
8302 * @param {Boolean} asString
8305 getValues : function(asString){
8306 //if (this.childForms) {
8307 // copy values from the child forms
8308 // Roo.each(this.childForms, function (f) {
8309 // this.setValues(f.getValues());
8315 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8316 if(asString === true){
8319 return Roo.urlDecode(fs);
8323 * Returns the fields in this form as an object with key/value pairs.
8324 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8327 getFieldValues : function(with_hidden)
8329 var items = this.getItems();
8331 items.each(function(f){
8337 var v = f.getValue();
8339 if (f.inputType =='radio') {
8340 if (typeof(ret[f.getName()]) == 'undefined') {
8341 ret[f.getName()] = ''; // empty..
8344 if (!f.el.dom.checked) {
8352 if(f.xtype == 'MoneyField'){
8353 ret[f.currencyName] = f.getCurrency();
8356 // not sure if this supported any more..
8357 if ((typeof(v) == 'object') && f.getRawValue) {
8358 v = f.getRawValue() ; // dates..
8360 // combo boxes where name != hiddenName...
8361 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8362 ret[f.name] = f.getRawValue();
8364 ret[f.getName()] = v;
8371 * Clears all invalid messages in this form.
8372 * @return {BasicForm} this
8374 clearInvalid : function(){
8375 var items = this.getItems();
8377 items.each(function(f){
8386 * @return {BasicForm} this
8389 var items = this.getItems();
8390 items.each(function(f){
8394 Roo.each(this.childForms || [], function (f) {
8402 getItems : function()
8404 var r=new Roo.util.MixedCollection(false, function(o){
8405 return o.id || (o.id = Roo.id());
8407 var iter = function(el) {
8414 Roo.each(el.items,function(e) {
8423 hideFields : function(items)
8425 Roo.each(items, function(i){
8427 var f = this.findField(i);
8438 showFields : function(items)
8440 Roo.each(items, function(i){
8442 var f = this.findField(i);
8455 Roo.apply(Roo.bootstrap.Form, {
8482 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8483 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8484 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8485 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8488 this.maskEl.top.enableDisplayMode("block");
8489 this.maskEl.left.enableDisplayMode("block");
8490 this.maskEl.bottom.enableDisplayMode("block");
8491 this.maskEl.right.enableDisplayMode("block");
8493 this.toolTip = new Roo.bootstrap.Tooltip({
8494 cls : 'roo-form-error-popover',
8496 'left' : ['r-l', [-2,0], 'right'],
8497 'right' : ['l-r', [2,0], 'left'],
8498 'bottom' : ['tl-bl', [0,2], 'top'],
8499 'top' : [ 'bl-tl', [0,-2], 'bottom']
8503 this.toolTip.render(Roo.get(document.body));
8505 this.toolTip.el.enableDisplayMode("block");
8507 Roo.get(document.body).on('click', function(){
8511 Roo.get(document.body).on('touchstart', function(){
8515 this.isApplied = true
8518 mask : function(form, target)
8522 this.target = target;
8524 if(!this.form.errorMask || !target.el){
8528 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8530 Roo.log(scrollable);
8532 var ot = this.target.el.calcOffsetsTo(scrollable);
8534 var scrollTo = ot[1] - this.form.maskOffset;
8536 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8538 scrollable.scrollTo('top', scrollTo);
8540 var box = this.target.el.getBox();
8542 var zIndex = Roo.bootstrap.Modal.zIndex++;
8545 this.maskEl.top.setStyle('position', 'absolute');
8546 this.maskEl.top.setStyle('z-index', zIndex);
8547 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8548 this.maskEl.top.setLeft(0);
8549 this.maskEl.top.setTop(0);
8550 this.maskEl.top.show();
8552 this.maskEl.left.setStyle('position', 'absolute');
8553 this.maskEl.left.setStyle('z-index', zIndex);
8554 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8555 this.maskEl.left.setLeft(0);
8556 this.maskEl.left.setTop(box.y - this.padding);
8557 this.maskEl.left.show();
8559 this.maskEl.bottom.setStyle('position', 'absolute');
8560 this.maskEl.bottom.setStyle('z-index', zIndex);
8561 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8562 this.maskEl.bottom.setLeft(0);
8563 this.maskEl.bottom.setTop(box.bottom + this.padding);
8564 this.maskEl.bottom.show();
8566 this.maskEl.right.setStyle('position', 'absolute');
8567 this.maskEl.right.setStyle('z-index', zIndex);
8568 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8569 this.maskEl.right.setLeft(box.right + this.padding);
8570 this.maskEl.right.setTop(box.y - this.padding);
8571 this.maskEl.right.show();
8573 this.toolTip.bindEl = this.target.el;
8575 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8577 var tip = this.target.blankText;
8579 if(this.target.getValue() !== '' ) {
8581 if (this.target.invalidText.length) {
8582 tip = this.target.invalidText;
8583 } else if (this.target.regexText.length){
8584 tip = this.target.regexText;
8588 this.toolTip.show(tip);
8590 this.intervalID = window.setInterval(function() {
8591 Roo.bootstrap.Form.popover.unmask();
8594 window.onwheel = function(){ return false;};
8596 (function(){ this.isMasked = true; }).defer(500, this);
8602 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8606 this.maskEl.top.setStyle('position', 'absolute');
8607 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8608 this.maskEl.top.hide();
8610 this.maskEl.left.setStyle('position', 'absolute');
8611 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8612 this.maskEl.left.hide();
8614 this.maskEl.bottom.setStyle('position', 'absolute');
8615 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8616 this.maskEl.bottom.hide();
8618 this.maskEl.right.setStyle('position', 'absolute');
8619 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8620 this.maskEl.right.hide();
8622 this.toolTip.hide();
8624 this.toolTip.el.hide();
8626 window.onwheel = function(){ return true;};
8628 if(this.intervalID){
8629 window.clearInterval(this.intervalID);
8630 this.intervalID = false;
8633 this.isMasked = false;
8643 * Ext JS Library 1.1.1
8644 * Copyright(c) 2006-2007, Ext JS, LLC.
8646 * Originally Released Under LGPL - original licence link has changed is not relivant.
8649 * <script type="text/javascript">
8652 * @class Roo.form.VTypes
8653 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8656 Roo.form.VTypes = function(){
8657 // closure these in so they are only created once.
8658 var alpha = /^[a-zA-Z_]+$/;
8659 var alphanum = /^[a-zA-Z0-9_]+$/;
8660 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8661 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8663 // All these messages and functions are configurable
8666 * The function used to validate email addresses
8667 * @param {String} value The email address
8669 'email' : function(v){
8670 return email.test(v);
8673 * The error text to display when the email validation function returns false
8676 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8678 * The keystroke filter mask to be applied on email input
8681 'emailMask' : /[a-z0-9_\.\-@]/i,
8684 * The function used to validate URLs
8685 * @param {String} value The URL
8687 'url' : function(v){
8691 * The error text to display when the url validation function returns false
8694 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8697 * The function used to validate alpha values
8698 * @param {String} value The value
8700 'alpha' : function(v){
8701 return alpha.test(v);
8704 * The error text to display when the alpha validation function returns false
8707 'alphaText' : 'This field should only contain letters and _',
8709 * The keystroke filter mask to be applied on alpha input
8712 'alphaMask' : /[a-z_]/i,
8715 * The function used to validate alphanumeric values
8716 * @param {String} value The value
8718 'alphanum' : function(v){
8719 return alphanum.test(v);
8722 * The error text to display when the alphanumeric validation function returns false
8725 'alphanumText' : 'This field should only contain letters, numbers and _',
8727 * The keystroke filter mask to be applied on alphanumeric input
8730 'alphanumMask' : /[a-z0-9_]/i
8740 * @class Roo.bootstrap.Input
8741 * @extends Roo.bootstrap.Component
8742 * Bootstrap Input class
8743 * @cfg {Boolean} disabled is it disabled
8744 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8745 * @cfg {String} name name of the input
8746 * @cfg {string} fieldLabel - the label associated
8747 * @cfg {string} placeholder - placeholder to put in text.
8748 * @cfg {string} before - input group add on before
8749 * @cfg {string} after - input group add on after
8750 * @cfg {string} size - (lg|sm) or leave empty..
8751 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8752 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8753 * @cfg {Number} md colspan out of 12 for computer-sized screens
8754 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8755 * @cfg {string} value default value of the input
8756 * @cfg {Number} labelWidth set the width of label
8757 * @cfg {Number} labellg set the width of label (1-12)
8758 * @cfg {Number} labelmd set the width of label (1-12)
8759 * @cfg {Number} labelsm set the width of label (1-12)
8760 * @cfg {Number} labelxs set the width of label (1-12)
8761 * @cfg {String} labelAlign (top|left)
8762 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8763 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8764 * @cfg {String} indicatorpos (left|right) default left
8765 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8766 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8768 * @cfg {String} align (left|center|right) Default left
8769 * @cfg {Boolean} forceFeedback (true|false) Default false
8772 * Create a new Input
8773 * @param {Object} config The config object
8776 Roo.bootstrap.Input = function(config){
8778 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8783 * Fires when this field receives input focus.
8784 * @param {Roo.form.Field} this
8789 * Fires when this field loses input focus.
8790 * @param {Roo.form.Field} this
8795 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8796 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8797 * @param {Roo.form.Field} this
8798 * @param {Roo.EventObject} e The event object
8803 * Fires just before the field blurs if the field value has changed.
8804 * @param {Roo.form.Field} this
8805 * @param {Mixed} newValue The new value
8806 * @param {Mixed} oldValue The original value
8811 * Fires after the field has been marked as invalid.
8812 * @param {Roo.form.Field} this
8813 * @param {String} msg The validation message
8818 * Fires after the field has been validated with no errors.
8819 * @param {Roo.form.Field} this
8824 * Fires after the key up
8825 * @param {Roo.form.Field} this
8826 * @param {Roo.EventObject} e The event Object
8832 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8834 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8835 automatic validation (defaults to "keyup").
8837 validationEvent : "keyup",
8839 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8841 validateOnBlur : true,
8843 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8845 validationDelay : 250,
8847 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8849 focusClass : "x-form-focus", // not needed???
8853 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8855 invalidClass : "has-warning",
8858 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8860 validClass : "has-success",
8863 * @cfg {Boolean} hasFeedback (true|false) default true
8868 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8870 invalidFeedbackClass : "glyphicon-warning-sign",
8873 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8875 validFeedbackClass : "glyphicon-ok",
8878 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8880 selectOnFocus : false,
8883 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8887 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8892 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8894 disableKeyFilter : false,
8897 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8901 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8905 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8907 blankText : "Please complete this mandatory field",
8910 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8914 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8916 maxLength : Number.MAX_VALUE,
8918 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8920 minLengthText : "The minimum length for this field is {0}",
8922 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8924 maxLengthText : "The maximum length for this field is {0}",
8928 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8929 * If available, this function will be called only after the basic validators all return true, and will be passed the
8930 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8934 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8935 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8936 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8940 * @cfg {String} regexText -- Depricated - use Invalid Text
8945 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8951 autocomplete: false,
8970 formatedValue : false,
8971 forceFeedback : false,
8973 indicatorpos : 'left',
8983 parentLabelAlign : function()
8986 while (parent.parent()) {
8987 parent = parent.parent();
8988 if (typeof(parent.labelAlign) !='undefined') {
8989 return parent.labelAlign;
8996 getAutoCreate : function()
8998 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9004 if(this.inputType != 'hidden'){
9005 cfg.cls = 'form-group' //input-group
9011 type : this.inputType,
9013 cls : 'form-control',
9014 placeholder : this.placeholder || '',
9015 autocomplete : this.autocomplete || 'new-password'
9018 if(this.capture.length){
9019 input.capture = this.capture;
9022 if(this.accept.length){
9023 input.accept = this.accept + "/*";
9027 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9030 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9031 input.maxLength = this.maxLength;
9034 if (this.disabled) {
9035 input.disabled=true;
9038 if (this.readOnly) {
9039 input.readonly=true;
9043 input.name = this.name;
9047 input.cls += ' input-' + this.size;
9051 ['xs','sm','md','lg'].map(function(size){
9052 if (settings[size]) {
9053 cfg.cls += ' col-' + size + '-' + settings[size];
9057 var inputblock = input;
9061 cls: 'glyphicon form-control-feedback'
9064 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9067 cls : 'has-feedback',
9075 if (this.before || this.after) {
9078 cls : 'input-group',
9082 if (this.before && typeof(this.before) == 'string') {
9084 inputblock.cn.push({
9086 cls : 'roo-input-before input-group-addon',
9090 if (this.before && typeof(this.before) == 'object') {
9091 this.before = Roo.factory(this.before);
9093 inputblock.cn.push({
9095 cls : 'roo-input-before input-group-' +
9096 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9100 inputblock.cn.push(input);
9102 if (this.after && typeof(this.after) == 'string') {
9103 inputblock.cn.push({
9105 cls : 'roo-input-after input-group-addon',
9109 if (this.after && typeof(this.after) == 'object') {
9110 this.after = Roo.factory(this.after);
9112 inputblock.cn.push({
9114 cls : 'roo-input-after input-group-' +
9115 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9119 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9120 inputblock.cls += ' has-feedback';
9121 inputblock.cn.push(feedback);
9125 if (align ==='left' && this.fieldLabel.length) {
9127 cfg.cls += ' roo-form-group-label-left';
9132 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9133 tooltip : 'This field is required'
9138 cls : 'control-label',
9139 html : this.fieldLabel
9150 var labelCfg = cfg.cn[1];
9151 var contentCfg = cfg.cn[2];
9153 if(this.indicatorpos == 'right'){
9158 cls : 'control-label',
9162 html : this.fieldLabel
9166 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9167 tooltip : 'This field is required'
9180 labelCfg = cfg.cn[0];
9181 contentCfg = cfg.cn[1];
9185 if(this.labelWidth > 12){
9186 labelCfg.style = "width: " + this.labelWidth + 'px';
9189 if(this.labelWidth < 13 && this.labelmd == 0){
9190 this.labelmd = this.labelWidth;
9193 if(this.labellg > 0){
9194 labelCfg.cls += ' col-lg-' + this.labellg;
9195 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9198 if(this.labelmd > 0){
9199 labelCfg.cls += ' col-md-' + this.labelmd;
9200 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9203 if(this.labelsm > 0){
9204 labelCfg.cls += ' col-sm-' + this.labelsm;
9205 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9208 if(this.labelxs > 0){
9209 labelCfg.cls += ' col-xs-' + this.labelxs;
9210 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9214 } else if ( this.fieldLabel.length) {
9219 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9220 tooltip : 'This field is required'
9224 //cls : 'input-group-addon',
9225 html : this.fieldLabel
9233 if(this.indicatorpos == 'right'){
9238 //cls : 'input-group-addon',
9239 html : this.fieldLabel
9244 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9245 tooltip : 'This field is required'
9265 if (this.parentType === 'Navbar' && this.parent().bar) {
9266 cfg.cls += ' navbar-form';
9269 if (this.parentType === 'NavGroup') {
9270 cfg.cls += ' navbar-form';
9278 * return the real input element.
9280 inputEl: function ()
9282 return this.el.select('input.form-control',true).first();
9285 tooltipEl : function()
9287 return this.inputEl();
9290 indicatorEl : function()
9292 var indicator = this.el.select('i.roo-required-indicator',true).first();
9302 setDisabled : function(v)
9304 var i = this.inputEl().dom;
9306 i.removeAttribute('disabled');
9310 i.setAttribute('disabled','true');
9312 initEvents : function()
9315 this.inputEl().on("keydown" , this.fireKey, this);
9316 this.inputEl().on("focus", this.onFocus, this);
9317 this.inputEl().on("blur", this.onBlur, this);
9319 this.inputEl().relayEvent('keyup', this);
9321 this.indicator = this.indicatorEl();
9324 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9327 // reference to original value for reset
9328 this.originalValue = this.getValue();
9329 //Roo.form.TextField.superclass.initEvents.call(this);
9330 if(this.validationEvent == 'keyup'){
9331 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9332 this.inputEl().on('keyup', this.filterValidation, this);
9334 else if(this.validationEvent !== false){
9335 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9338 if(this.selectOnFocus){
9339 this.on("focus", this.preFocus, this);
9342 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9343 this.inputEl().on("keypress", this.filterKeys, this);
9345 this.inputEl().relayEvent('keypress', this);
9348 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9349 this.el.on("click", this.autoSize, this);
9352 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9353 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9356 if (typeof(this.before) == 'object') {
9357 this.before.render(this.el.select('.roo-input-before',true).first());
9359 if (typeof(this.after) == 'object') {
9360 this.after.render(this.el.select('.roo-input-after',true).first());
9363 this.inputEl().on('change', this.onChange, this);
9366 filterValidation : function(e){
9367 if(!e.isNavKeyPress()){
9368 this.validationTask.delay(this.validationDelay);
9372 * Validates the field value
9373 * @return {Boolean} True if the value is valid, else false
9375 validate : function(){
9376 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9377 if(this.disabled || this.validateValue(this.getRawValue())){
9388 * Validates a value according to the field's validation rules and marks the field as invalid
9389 * if the validation fails
9390 * @param {Mixed} value The value to validate
9391 * @return {Boolean} True if the value is valid, else false
9393 validateValue : function(value)
9395 if(this.getVisibilityEl().hasClass('hidden')){
9399 if(value.length < 1) { // if it's blank
9400 if(this.allowBlank){
9406 if(value.length < this.minLength){
9409 if(value.length > this.maxLength){
9413 var vt = Roo.form.VTypes;
9414 if(!vt[this.vtype](value, this)){
9418 if(typeof this.validator == "function"){
9419 var msg = this.validator(value);
9423 if (typeof(msg) == 'string') {
9424 this.invalidText = msg;
9428 if(this.regex && !this.regex.test(value)){
9436 fireKey : function(e){
9437 //Roo.log('field ' + e.getKey());
9438 if(e.isNavKeyPress()){
9439 this.fireEvent("specialkey", this, e);
9442 focus : function (selectText){
9444 this.inputEl().focus();
9445 if(selectText === true){
9446 this.inputEl().dom.select();
9452 onFocus : function(){
9453 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9454 // this.el.addClass(this.focusClass);
9457 this.hasFocus = true;
9458 this.startValue = this.getValue();
9459 this.fireEvent("focus", this);
9463 beforeBlur : Roo.emptyFn,
9467 onBlur : function(){
9469 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9470 //this.el.removeClass(this.focusClass);
9472 this.hasFocus = false;
9473 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9476 var v = this.getValue();
9477 if(String(v) !== String(this.startValue)){
9478 this.fireEvent('change', this, v, this.startValue);
9480 this.fireEvent("blur", this);
9483 onChange : function(e)
9485 var v = this.getValue();
9486 if(String(v) !== String(this.startValue)){
9487 this.fireEvent('change', this, v, this.startValue);
9493 * Resets the current field value to the originally loaded value and clears any validation messages
9496 this.setValue(this.originalValue);
9500 * Returns the name of the field
9501 * @return {Mixed} name The name field
9503 getName: function(){
9507 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9508 * @return {Mixed} value The field value
9510 getValue : function(){
9512 var v = this.inputEl().getValue();
9517 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9518 * @return {Mixed} value The field value
9520 getRawValue : function(){
9521 var v = this.inputEl().getValue();
9527 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9528 * @param {Mixed} value The value to set
9530 setRawValue : function(v){
9531 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9534 selectText : function(start, end){
9535 var v = this.getRawValue();
9537 start = start === undefined ? 0 : start;
9538 end = end === undefined ? v.length : end;
9539 var d = this.inputEl().dom;
9540 if(d.setSelectionRange){
9541 d.setSelectionRange(start, end);
9542 }else if(d.createTextRange){
9543 var range = d.createTextRange();
9544 range.moveStart("character", start);
9545 range.moveEnd("character", v.length-end);
9552 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9553 * @param {Mixed} value The value to set
9555 setValue : function(v){
9558 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9564 processValue : function(value){
9565 if(this.stripCharsRe){
9566 var newValue = value.replace(this.stripCharsRe, '');
9567 if(newValue !== value){
9568 this.setRawValue(newValue);
9575 preFocus : function(){
9577 if(this.selectOnFocus){
9578 this.inputEl().dom.select();
9581 filterKeys : function(e){
9583 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9586 var c = e.getCharCode(), cc = String.fromCharCode(c);
9587 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9590 if(!this.maskRe.test(cc)){
9595 * Clear any invalid styles/messages for this field
9597 clearInvalid : function(){
9599 if(!this.el || this.preventMark){ // not rendered
9604 this.el.removeClass(this.invalidClass);
9606 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9608 var feedback = this.el.select('.form-control-feedback', true).first();
9611 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9617 this.indicator.removeClass('visible');
9618 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9621 this.fireEvent('valid', this);
9625 * Mark this field as valid
9627 markValid : function()
9629 if(!this.el || this.preventMark){ // not rendered...
9633 this.el.removeClass([this.invalidClass, this.validClass]);
9635 var feedback = this.el.select('.form-control-feedback', true).first();
9638 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9642 this.indicator.removeClass('visible');
9643 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9650 if(this.allowBlank && !this.getRawValue().length){
9654 this.el.addClass(this.validClass);
9656 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9658 var feedback = this.el.select('.form-control-feedback', true).first();
9661 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9662 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9667 this.fireEvent('valid', this);
9671 * Mark this field as invalid
9672 * @param {String} msg The validation message
9674 markInvalid : function(msg)
9676 if(!this.el || this.preventMark){ // not rendered
9680 this.el.removeClass([this.invalidClass, this.validClass]);
9682 var feedback = this.el.select('.form-control-feedback', true).first();
9685 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9692 if(this.allowBlank && !this.getRawValue().length){
9697 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9698 this.indicator.addClass('visible');
9701 this.el.addClass(this.invalidClass);
9703 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9705 var feedback = this.el.select('.form-control-feedback', true).first();
9708 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9710 if(this.getValue().length || this.forceFeedback){
9711 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9718 this.fireEvent('invalid', this, msg);
9721 SafariOnKeyDown : function(event)
9723 // this is a workaround for a password hang bug on chrome/ webkit.
9724 if (this.inputEl().dom.type != 'password') {
9728 var isSelectAll = false;
9730 if(this.inputEl().dom.selectionEnd > 0){
9731 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9733 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9734 event.preventDefault();
9739 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9741 event.preventDefault();
9742 // this is very hacky as keydown always get's upper case.
9744 var cc = String.fromCharCode(event.getCharCode());
9745 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9749 adjustWidth : function(tag, w){
9750 tag = tag.toLowerCase();
9751 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9752 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9756 if(tag == 'textarea'){
9759 }else if(Roo.isOpera){
9763 if(tag == 'textarea'){
9771 setFieldLabel : function(v)
9778 var ar = this.el.select('label > span',true);
9780 if (ar.elements.length) {
9781 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9782 this.fieldLabel = v;
9786 var br = this.el.select('label',true);
9788 if(br.elements.length) {
9789 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9790 this.fieldLabel = v;
9794 Roo.log('Cannot Found any of label > span || label in input');
9798 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9799 this.fieldLabel = v;
9814 * @class Roo.bootstrap.TextArea
9815 * @extends Roo.bootstrap.Input
9816 * Bootstrap TextArea class
9817 * @cfg {Number} cols Specifies the visible width of a text area
9818 * @cfg {Number} rows Specifies the visible number of lines in a text area
9819 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9820 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9821 * @cfg {string} html text
9824 * Create a new TextArea
9825 * @param {Object} config The config object
9828 Roo.bootstrap.TextArea = function(config){
9829 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9833 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9843 getAutoCreate : function(){
9845 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9851 if(this.inputType != 'hidden'){
9852 cfg.cls = 'form-group' //input-group
9860 value : this.value || '',
9861 html: this.html || '',
9862 cls : 'form-control',
9863 placeholder : this.placeholder || ''
9867 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9868 input.maxLength = this.maxLength;
9872 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9876 input.cols = this.cols;
9879 if (this.readOnly) {
9880 input.readonly = true;
9884 input.name = this.name;
9888 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9892 ['xs','sm','md','lg'].map(function(size){
9893 if (settings[size]) {
9894 cfg.cls += ' col-' + size + '-' + settings[size];
9898 var inputblock = input;
9900 if(this.hasFeedback && !this.allowBlank){
9904 cls: 'glyphicon form-control-feedback'
9908 cls : 'has-feedback',
9917 if (this.before || this.after) {
9920 cls : 'input-group',
9924 inputblock.cn.push({
9926 cls : 'input-group-addon',
9931 inputblock.cn.push(input);
9933 if(this.hasFeedback && !this.allowBlank){
9934 inputblock.cls += ' has-feedback';
9935 inputblock.cn.push(feedback);
9939 inputblock.cn.push({
9941 cls : 'input-group-addon',
9948 if (align ==='left' && this.fieldLabel.length) {
9953 cls : 'control-label',
9954 html : this.fieldLabel
9965 if(this.labelWidth > 12){
9966 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9969 if(this.labelWidth < 13 && this.labelmd == 0){
9970 this.labelmd = this.labelWidth;
9973 if(this.labellg > 0){
9974 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9975 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9978 if(this.labelmd > 0){
9979 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9980 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9983 if(this.labelsm > 0){
9984 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9985 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9988 if(this.labelxs > 0){
9989 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9990 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9993 } else if ( this.fieldLabel.length) {
9998 //cls : 'input-group-addon',
9999 html : this.fieldLabel
10017 if (this.disabled) {
10018 input.disabled=true;
10025 * return the real textarea element.
10027 inputEl: function ()
10029 return this.el.select('textarea.form-control',true).first();
10033 * Clear any invalid styles/messages for this field
10035 clearInvalid : function()
10038 if(!this.el || this.preventMark){ // not rendered
10042 var label = this.el.select('label', true).first();
10043 var icon = this.el.select('i.fa-star', true).first();
10049 this.el.removeClass(this.invalidClass);
10051 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10053 var feedback = this.el.select('.form-control-feedback', true).first();
10056 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10061 this.fireEvent('valid', this);
10065 * Mark this field as valid
10067 markValid : function()
10069 if(!this.el || this.preventMark){ // not rendered
10073 this.el.removeClass([this.invalidClass, this.validClass]);
10075 var feedback = this.el.select('.form-control-feedback', true).first();
10078 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10081 if(this.disabled || this.allowBlank){
10085 var label = this.el.select('label', true).first();
10086 var icon = this.el.select('i.fa-star', true).first();
10092 this.el.addClass(this.validClass);
10094 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10096 var feedback = this.el.select('.form-control-feedback', true).first();
10099 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10100 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10105 this.fireEvent('valid', this);
10109 * Mark this field as invalid
10110 * @param {String} msg The validation message
10112 markInvalid : function(msg)
10114 if(!this.el || this.preventMark){ // not rendered
10118 this.el.removeClass([this.invalidClass, this.validClass]);
10120 var feedback = this.el.select('.form-control-feedback', true).first();
10123 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10126 if(this.disabled || this.allowBlank){
10130 var label = this.el.select('label', true).first();
10131 var icon = this.el.select('i.fa-star', true).first();
10133 if(!this.getValue().length && label && !icon){
10134 this.el.createChild({
10136 cls : 'text-danger fa fa-lg fa-star',
10137 tooltip : 'This field is required',
10138 style : 'margin-right:5px;'
10142 this.el.addClass(this.invalidClass);
10144 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10146 var feedback = this.el.select('.form-control-feedback', true).first();
10149 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10151 if(this.getValue().length || this.forceFeedback){
10152 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10159 this.fireEvent('invalid', this, msg);
10167 * trigger field - base class for combo..
10172 * @class Roo.bootstrap.TriggerField
10173 * @extends Roo.bootstrap.Input
10174 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10175 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10176 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10177 * for which you can provide a custom implementation. For example:
10179 var trigger = new Roo.bootstrap.TriggerField();
10180 trigger.onTriggerClick = myTriggerFn;
10181 trigger.applyTo('my-field');
10184 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10185 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10186 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10187 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10188 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10191 * Create a new TriggerField.
10192 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10193 * to the base TextField)
10195 Roo.bootstrap.TriggerField = function(config){
10196 this.mimicing = false;
10197 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10200 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10202 * @cfg {String} triggerClass A CSS class to apply to the trigger
10205 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10210 * @cfg {Boolean} removable (true|false) special filter default false
10214 /** @cfg {Boolean} grow @hide */
10215 /** @cfg {Number} growMin @hide */
10216 /** @cfg {Number} growMax @hide */
10222 autoSize: Roo.emptyFn,
10226 deferHeight : true,
10229 actionMode : 'wrap',
10234 getAutoCreate : function(){
10236 var align = this.labelAlign || this.parentLabelAlign();
10241 cls: 'form-group' //input-group
10248 type : this.inputType,
10249 cls : 'form-control',
10250 autocomplete: 'new-password',
10251 placeholder : this.placeholder || ''
10255 input.name = this.name;
10258 input.cls += ' input-' + this.size;
10261 if (this.disabled) {
10262 input.disabled=true;
10265 var inputblock = input;
10267 if(this.hasFeedback && !this.allowBlank){
10271 cls: 'glyphicon form-control-feedback'
10274 if(this.removable && !this.editable && !this.tickable){
10276 cls : 'has-feedback',
10282 cls : 'roo-combo-removable-btn close'
10289 cls : 'has-feedback',
10298 if(this.removable && !this.editable && !this.tickable){
10300 cls : 'roo-removable',
10306 cls : 'roo-combo-removable-btn close'
10313 if (this.before || this.after) {
10316 cls : 'input-group',
10320 inputblock.cn.push({
10322 cls : 'input-group-addon',
10327 inputblock.cn.push(input);
10329 if(this.hasFeedback && !this.allowBlank){
10330 inputblock.cls += ' has-feedback';
10331 inputblock.cn.push(feedback);
10335 inputblock.cn.push({
10337 cls : 'input-group-addon',
10350 cls: 'form-hidden-field'
10364 cls: 'form-hidden-field'
10368 cls: 'roo-select2-choices',
10372 cls: 'roo-select2-search-field',
10385 cls: 'roo-select2-container input-group',
10390 // cls: 'typeahead typeahead-long dropdown-menu',
10391 // style: 'display:none'
10396 if(!this.multiple && this.showToggleBtn){
10402 if (this.caret != false) {
10405 cls: 'fa fa-' + this.caret
10412 cls : 'input-group-addon btn dropdown-toggle',
10417 cls: 'combobox-clear',
10431 combobox.cls += ' roo-select2-container-multi';
10434 if (align ==='left' && this.fieldLabel.length) {
10436 cfg.cls += ' roo-form-group-label-left';
10441 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10442 tooltip : 'This field is required'
10447 cls : 'control-label',
10448 html : this.fieldLabel
10460 var labelCfg = cfg.cn[1];
10461 var contentCfg = cfg.cn[2];
10463 if(this.indicatorpos == 'right'){
10468 cls : 'control-label',
10472 html : this.fieldLabel
10476 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10477 tooltip : 'This field is required'
10490 labelCfg = cfg.cn[0];
10491 contentCfg = cfg.cn[1];
10494 if(this.labelWidth > 12){
10495 labelCfg.style = "width: " + this.labelWidth + 'px';
10498 if(this.labelWidth < 13 && this.labelmd == 0){
10499 this.labelmd = this.labelWidth;
10502 if(this.labellg > 0){
10503 labelCfg.cls += ' col-lg-' + this.labellg;
10504 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10507 if(this.labelmd > 0){
10508 labelCfg.cls += ' col-md-' + this.labelmd;
10509 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10512 if(this.labelsm > 0){
10513 labelCfg.cls += ' col-sm-' + this.labelsm;
10514 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10517 if(this.labelxs > 0){
10518 labelCfg.cls += ' col-xs-' + this.labelxs;
10519 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10522 } else if ( this.fieldLabel.length) {
10523 // Roo.log(" label");
10527 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10528 tooltip : 'This field is required'
10532 //cls : 'input-group-addon',
10533 html : this.fieldLabel
10541 if(this.indicatorpos == 'right'){
10549 html : this.fieldLabel
10553 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10554 tooltip : 'This field is required'
10567 // Roo.log(" no label && no align");
10574 ['xs','sm','md','lg'].map(function(size){
10575 if (settings[size]) {
10576 cfg.cls += ' col-' + size + '-' + settings[size];
10587 onResize : function(w, h){
10588 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10589 // if(typeof w == 'number'){
10590 // var x = w - this.trigger.getWidth();
10591 // this.inputEl().setWidth(this.adjustWidth('input', x));
10592 // this.trigger.setStyle('left', x+'px');
10597 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10600 getResizeEl : function(){
10601 return this.inputEl();
10605 getPositionEl : function(){
10606 return this.inputEl();
10610 alignErrorIcon : function(){
10611 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10615 initEvents : function(){
10619 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10620 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10621 if(!this.multiple && this.showToggleBtn){
10622 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10623 if(this.hideTrigger){
10624 this.trigger.setDisplayed(false);
10626 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10630 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10633 if(this.removable && !this.editable && !this.tickable){
10634 var close = this.closeTriggerEl();
10637 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10638 close.on('click', this.removeBtnClick, this, close);
10642 //this.trigger.addClassOnOver('x-form-trigger-over');
10643 //this.trigger.addClassOnClick('x-form-trigger-click');
10646 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10650 closeTriggerEl : function()
10652 var close = this.el.select('.roo-combo-removable-btn', true).first();
10653 return close ? close : false;
10656 removeBtnClick : function(e, h, el)
10658 e.preventDefault();
10660 if(this.fireEvent("remove", this) !== false){
10662 this.fireEvent("afterremove", this)
10666 createList : function()
10668 this.list = Roo.get(document.body).createChild({
10670 cls: 'typeahead typeahead-long dropdown-menu',
10671 style: 'display:none'
10674 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10679 initTrigger : function(){
10684 onDestroy : function(){
10686 this.trigger.removeAllListeners();
10687 // this.trigger.remove();
10690 // this.wrap.remove();
10692 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10696 onFocus : function(){
10697 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10699 if(!this.mimicing){
10700 this.wrap.addClass('x-trigger-wrap-focus');
10701 this.mimicing = true;
10702 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10703 if(this.monitorTab){
10704 this.el.on("keydown", this.checkTab, this);
10711 checkTab : function(e){
10712 if(e.getKey() == e.TAB){
10713 this.triggerBlur();
10718 onBlur : function(){
10723 mimicBlur : function(e, t){
10725 if(!this.wrap.contains(t) && this.validateBlur()){
10726 this.triggerBlur();
10732 triggerBlur : function(){
10733 this.mimicing = false;
10734 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10735 if(this.monitorTab){
10736 this.el.un("keydown", this.checkTab, this);
10738 //this.wrap.removeClass('x-trigger-wrap-focus');
10739 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10743 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10744 validateBlur : function(e, t){
10749 onDisable : function(){
10750 this.inputEl().dom.disabled = true;
10751 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10753 // this.wrap.addClass('x-item-disabled');
10758 onEnable : function(){
10759 this.inputEl().dom.disabled = false;
10760 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10762 // this.el.removeClass('x-item-disabled');
10767 onShow : function(){
10768 var ae = this.getActionEl();
10771 ae.dom.style.display = '';
10772 ae.dom.style.visibility = 'visible';
10778 onHide : function(){
10779 var ae = this.getActionEl();
10780 ae.dom.style.display = 'none';
10784 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10785 * by an implementing function.
10787 * @param {EventObject} e
10789 onTriggerClick : Roo.emptyFn
10793 * Ext JS Library 1.1.1
10794 * Copyright(c) 2006-2007, Ext JS, LLC.
10796 * Originally Released Under LGPL - original licence link has changed is not relivant.
10799 * <script type="text/javascript">
10804 * @class Roo.data.SortTypes
10806 * Defines the default sorting (casting?) comparison functions used when sorting data.
10808 Roo.data.SortTypes = {
10810 * Default sort that does nothing
10811 * @param {Mixed} s The value being converted
10812 * @return {Mixed} The comparison value
10814 none : function(s){
10819 * The regular expression used to strip tags
10823 stripTagsRE : /<\/?[^>]+>/gi,
10826 * Strips all HTML tags to sort on text only
10827 * @param {Mixed} s The value being converted
10828 * @return {String} The comparison value
10830 asText : function(s){
10831 return String(s).replace(this.stripTagsRE, "");
10835 * Strips all HTML tags to sort on text only - Case insensitive
10836 * @param {Mixed} s The value being converted
10837 * @return {String} The comparison value
10839 asUCText : function(s){
10840 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10844 * Case insensitive string
10845 * @param {Mixed} s The value being converted
10846 * @return {String} The comparison value
10848 asUCString : function(s) {
10849 return String(s).toUpperCase();
10854 * @param {Mixed} s The value being converted
10855 * @return {Number} The comparison value
10857 asDate : function(s) {
10861 if(s instanceof Date){
10862 return s.getTime();
10864 return Date.parse(String(s));
10869 * @param {Mixed} s The value being converted
10870 * @return {Float} The comparison value
10872 asFloat : function(s) {
10873 var val = parseFloat(String(s).replace(/,/g, ""));
10882 * @param {Mixed} s The value being converted
10883 * @return {Number} The comparison value
10885 asInt : function(s) {
10886 var val = parseInt(String(s).replace(/,/g, ""));
10894 * Ext JS Library 1.1.1
10895 * Copyright(c) 2006-2007, Ext JS, LLC.
10897 * Originally Released Under LGPL - original licence link has changed is not relivant.
10900 * <script type="text/javascript">
10904 * @class Roo.data.Record
10905 * Instances of this class encapsulate both record <em>definition</em> information, and record
10906 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10907 * to access Records cached in an {@link Roo.data.Store} object.<br>
10909 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10910 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10913 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10915 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10916 * {@link #create}. The parameters are the same.
10917 * @param {Array} data An associative Array of data values keyed by the field name.
10918 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10919 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10920 * not specified an integer id is generated.
10922 Roo.data.Record = function(data, id){
10923 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10928 * Generate a constructor for a specific record layout.
10929 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10930 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10931 * Each field definition object may contain the following properties: <ul>
10932 * <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,
10933 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10934 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10935 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10936 * is being used, then this is a string containing the javascript expression to reference the data relative to
10937 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10938 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10939 * this may be omitted.</p></li>
10940 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10941 * <ul><li>auto (Default, implies no conversion)</li>
10946 * <li>date</li></ul></p></li>
10947 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10948 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10949 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10950 * by the Reader into an object that will be stored in the Record. It is passed the
10951 * following parameters:<ul>
10952 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10954 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10956 * <br>usage:<br><pre><code>
10957 var TopicRecord = Roo.data.Record.create(
10958 {name: 'title', mapping: 'topic_title'},
10959 {name: 'author', mapping: 'username'},
10960 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10961 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10962 {name: 'lastPoster', mapping: 'user2'},
10963 {name: 'excerpt', mapping: 'post_text'}
10966 var myNewRecord = new TopicRecord({
10967 title: 'Do my job please',
10970 lastPost: new Date(),
10971 lastPoster: 'Animal',
10972 excerpt: 'No way dude!'
10974 myStore.add(myNewRecord);
10979 Roo.data.Record.create = function(o){
10980 var f = function(){
10981 f.superclass.constructor.apply(this, arguments);
10983 Roo.extend(f, Roo.data.Record);
10984 var p = f.prototype;
10985 p.fields = new Roo.util.MixedCollection(false, function(field){
10988 for(var i = 0, len = o.length; i < len; i++){
10989 p.fields.add(new Roo.data.Field(o[i]));
10991 f.getField = function(name){
10992 return p.fields.get(name);
10997 Roo.data.Record.AUTO_ID = 1000;
10998 Roo.data.Record.EDIT = 'edit';
10999 Roo.data.Record.REJECT = 'reject';
11000 Roo.data.Record.COMMIT = 'commit';
11002 Roo.data.Record.prototype = {
11004 * Readonly flag - true if this record has been modified.
11013 join : function(store){
11014 this.store = store;
11018 * Set the named field to the specified value.
11019 * @param {String} name The name of the field to set.
11020 * @param {Object} value The value to set the field to.
11022 set : function(name, value){
11023 if(this.data[name] == value){
11027 if(!this.modified){
11028 this.modified = {};
11030 if(typeof this.modified[name] == 'undefined'){
11031 this.modified[name] = this.data[name];
11033 this.data[name] = value;
11034 if(!this.editing && this.store){
11035 this.store.afterEdit(this);
11040 * Get the value of the named field.
11041 * @param {String} name The name of the field to get the value of.
11042 * @return {Object} The value of the field.
11044 get : function(name){
11045 return this.data[name];
11049 beginEdit : function(){
11050 this.editing = true;
11051 this.modified = {};
11055 cancelEdit : function(){
11056 this.editing = false;
11057 delete this.modified;
11061 endEdit : function(){
11062 this.editing = false;
11063 if(this.dirty && this.store){
11064 this.store.afterEdit(this);
11069 * Usually called by the {@link Roo.data.Store} which owns the Record.
11070 * Rejects all changes made to the Record since either creation, or the last commit operation.
11071 * Modified fields are reverted to their original values.
11073 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11074 * of reject operations.
11076 reject : function(){
11077 var m = this.modified;
11079 if(typeof m[n] != "function"){
11080 this.data[n] = m[n];
11083 this.dirty = false;
11084 delete this.modified;
11085 this.editing = false;
11087 this.store.afterReject(this);
11092 * Usually called by the {@link Roo.data.Store} which owns the Record.
11093 * Commits all changes made to the Record since either creation, or the last commit operation.
11095 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11096 * of commit operations.
11098 commit : function(){
11099 this.dirty = false;
11100 delete this.modified;
11101 this.editing = false;
11103 this.store.afterCommit(this);
11108 hasError : function(){
11109 return this.error != null;
11113 clearError : function(){
11118 * Creates a copy of this record.
11119 * @param {String} id (optional) A new record id if you don't want to use this record's id
11122 copy : function(newId) {
11123 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11127 * Ext JS Library 1.1.1
11128 * Copyright(c) 2006-2007, Ext JS, LLC.
11130 * Originally Released Under LGPL - original licence link has changed is not relivant.
11133 * <script type="text/javascript">
11139 * @class Roo.data.Store
11140 * @extends Roo.util.Observable
11141 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11142 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11144 * 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
11145 * has no knowledge of the format of the data returned by the Proxy.<br>
11147 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11148 * instances from the data object. These records are cached and made available through accessor functions.
11150 * Creates a new Store.
11151 * @param {Object} config A config object containing the objects needed for the Store to access data,
11152 * and read the data into Records.
11154 Roo.data.Store = function(config){
11155 this.data = new Roo.util.MixedCollection(false);
11156 this.data.getKey = function(o){
11159 this.baseParams = {};
11161 this.paramNames = {
11166 "multisort" : "_multisort"
11169 if(config && config.data){
11170 this.inlineData = config.data;
11171 delete config.data;
11174 Roo.apply(this, config);
11176 if(this.reader){ // reader passed
11177 this.reader = Roo.factory(this.reader, Roo.data);
11178 this.reader.xmodule = this.xmodule || false;
11179 if(!this.recordType){
11180 this.recordType = this.reader.recordType;
11182 if(this.reader.onMetaChange){
11183 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11187 if(this.recordType){
11188 this.fields = this.recordType.prototype.fields;
11190 this.modified = [];
11194 * @event datachanged
11195 * Fires when the data cache has changed, and a widget which is using this Store
11196 * as a Record cache should refresh its view.
11197 * @param {Store} this
11199 datachanged : true,
11201 * @event metachange
11202 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11203 * @param {Store} this
11204 * @param {Object} meta The JSON metadata
11209 * Fires when Records have been added to the Store
11210 * @param {Store} this
11211 * @param {Roo.data.Record[]} records The array of Records added
11212 * @param {Number} index The index at which the record(s) were added
11217 * Fires when a Record has been removed from the Store
11218 * @param {Store} this
11219 * @param {Roo.data.Record} record The Record that was removed
11220 * @param {Number} index The index at which the record was removed
11225 * Fires when a Record has been updated
11226 * @param {Store} this
11227 * @param {Roo.data.Record} record The Record that was updated
11228 * @param {String} operation The update operation being performed. Value may be one of:
11230 Roo.data.Record.EDIT
11231 Roo.data.Record.REJECT
11232 Roo.data.Record.COMMIT
11238 * Fires when the data cache has been cleared.
11239 * @param {Store} this
11243 * @event beforeload
11244 * Fires before a request is made for a new data object. If the beforeload handler returns false
11245 * the load action will be canceled.
11246 * @param {Store} this
11247 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11251 * @event beforeloadadd
11252 * Fires after a new set of Records has been loaded.
11253 * @param {Store} this
11254 * @param {Roo.data.Record[]} records The Records that were loaded
11255 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11257 beforeloadadd : true,
11260 * Fires after a new set of Records has been loaded, before they are added to the store.
11261 * @param {Store} this
11262 * @param {Roo.data.Record[]} records The Records that were loaded
11263 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11264 * @params {Object} return from reader
11268 * @event loadexception
11269 * Fires if an exception occurs in the Proxy during loading.
11270 * Called with the signature of the Proxy's "loadexception" event.
11271 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11274 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11275 * @param {Object} load options
11276 * @param {Object} jsonData from your request (normally this contains the Exception)
11278 loadexception : true
11282 this.proxy = Roo.factory(this.proxy, Roo.data);
11283 this.proxy.xmodule = this.xmodule || false;
11284 this.relayEvents(this.proxy, ["loadexception"]);
11286 this.sortToggle = {};
11287 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11289 Roo.data.Store.superclass.constructor.call(this);
11291 if(this.inlineData){
11292 this.loadData(this.inlineData);
11293 delete this.inlineData;
11297 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11299 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11300 * without a remote query - used by combo/forms at present.
11304 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11307 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11310 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11311 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11314 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11315 * on any HTTP request
11318 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11321 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11325 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11326 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11328 remoteSort : false,
11331 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11332 * loaded or when a record is removed. (defaults to false).
11334 pruneModifiedRecords : false,
11337 lastOptions : null,
11340 * Add Records to the Store and fires the add event.
11341 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11343 add : function(records){
11344 records = [].concat(records);
11345 for(var i = 0, len = records.length; i < len; i++){
11346 records[i].join(this);
11348 var index = this.data.length;
11349 this.data.addAll(records);
11350 this.fireEvent("add", this, records, index);
11354 * Remove a Record from the Store and fires the remove event.
11355 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11357 remove : function(record){
11358 var index = this.data.indexOf(record);
11359 this.data.removeAt(index);
11361 if(this.pruneModifiedRecords){
11362 this.modified.remove(record);
11364 this.fireEvent("remove", this, record, index);
11368 * Remove all Records from the Store and fires the clear event.
11370 removeAll : function(){
11372 if(this.pruneModifiedRecords){
11373 this.modified = [];
11375 this.fireEvent("clear", this);
11379 * Inserts Records to the Store at the given index and fires the add event.
11380 * @param {Number} index The start index at which to insert the passed Records.
11381 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11383 insert : function(index, records){
11384 records = [].concat(records);
11385 for(var i = 0, len = records.length; i < len; i++){
11386 this.data.insert(index, records[i]);
11387 records[i].join(this);
11389 this.fireEvent("add", this, records, index);
11393 * Get the index within the cache of the passed Record.
11394 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11395 * @return {Number} The index of the passed Record. Returns -1 if not found.
11397 indexOf : function(record){
11398 return this.data.indexOf(record);
11402 * Get the index within the cache of the Record with the passed id.
11403 * @param {String} id The id of the Record to find.
11404 * @return {Number} The index of the Record. Returns -1 if not found.
11406 indexOfId : function(id){
11407 return this.data.indexOfKey(id);
11411 * Get the Record with the specified id.
11412 * @param {String} id The id of the Record to find.
11413 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11415 getById : function(id){
11416 return this.data.key(id);
11420 * Get the Record at the specified index.
11421 * @param {Number} index The index of the Record to find.
11422 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11424 getAt : function(index){
11425 return this.data.itemAt(index);
11429 * Returns a range of Records between specified indices.
11430 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11431 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11432 * @return {Roo.data.Record[]} An array of Records
11434 getRange : function(start, end){
11435 return this.data.getRange(start, end);
11439 storeOptions : function(o){
11440 o = Roo.apply({}, o);
11443 this.lastOptions = o;
11447 * Loads the Record cache from the configured Proxy using the configured Reader.
11449 * If using remote paging, then the first load call must specify the <em>start</em>
11450 * and <em>limit</em> properties in the options.params property to establish the initial
11451 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11453 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11454 * and this call will return before the new data has been loaded. Perform any post-processing
11455 * in a callback function, or in a "load" event handler.</strong>
11457 * @param {Object} options An object containing properties which control loading options:<ul>
11458 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11459 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11460 * passed the following arguments:<ul>
11461 * <li>r : Roo.data.Record[]</li>
11462 * <li>options: Options object from the load call</li>
11463 * <li>success: Boolean success indicator</li></ul></li>
11464 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11465 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11468 load : function(options){
11469 options = options || {};
11470 if(this.fireEvent("beforeload", this, options) !== false){
11471 this.storeOptions(options);
11472 var p = Roo.apply(options.params || {}, this.baseParams);
11473 // if meta was not loaded from remote source.. try requesting it.
11474 if (!this.reader.metaFromRemote) {
11475 p._requestMeta = 1;
11477 if(this.sortInfo && this.remoteSort){
11478 var pn = this.paramNames;
11479 p[pn["sort"]] = this.sortInfo.field;
11480 p[pn["dir"]] = this.sortInfo.direction;
11482 if (this.multiSort) {
11483 var pn = this.paramNames;
11484 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11487 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11492 * Reloads the Record cache from the configured Proxy using the configured Reader and
11493 * the options from the last load operation performed.
11494 * @param {Object} options (optional) An object containing properties which may override the options
11495 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11496 * the most recently used options are reused).
11498 reload : function(options){
11499 this.load(Roo.applyIf(options||{}, this.lastOptions));
11503 // Called as a callback by the Reader during a load operation.
11504 loadRecords : function(o, options, success){
11505 if(!o || success === false){
11506 if(success !== false){
11507 this.fireEvent("load", this, [], options, o);
11509 if(options.callback){
11510 options.callback.call(options.scope || this, [], options, false);
11514 // if data returned failure - throw an exception.
11515 if (o.success === false) {
11516 // show a message if no listener is registered.
11517 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11518 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11520 // loadmask wil be hooked into this..
11521 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11524 var r = o.records, t = o.totalRecords || r.length;
11526 this.fireEvent("beforeloadadd", this, r, options, o);
11528 if(!options || options.add !== true){
11529 if(this.pruneModifiedRecords){
11530 this.modified = [];
11532 for(var i = 0, len = r.length; i < len; i++){
11536 this.data = this.snapshot;
11537 delete this.snapshot;
11540 this.data.addAll(r);
11541 this.totalLength = t;
11543 this.fireEvent("datachanged", this);
11545 this.totalLength = Math.max(t, this.data.length+r.length);
11549 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11551 var e = new Roo.data.Record({});
11553 e.set(this.parent.displayField, this.parent.emptyTitle);
11554 e.set(this.parent.valueField, '');
11559 this.fireEvent("load", this, r, options, o);
11560 if(options.callback){
11561 options.callback.call(options.scope || this, r, options, true);
11567 * Loads data from a passed data block. A Reader which understands the format of the data
11568 * must have been configured in the constructor.
11569 * @param {Object} data The data block from which to read the Records. The format of the data expected
11570 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11571 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11573 loadData : function(o, append){
11574 var r = this.reader.readRecords(o);
11575 this.loadRecords(r, {add: append}, true);
11579 * Gets the number of cached records.
11581 * <em>If using paging, this may not be the total size of the dataset. If the data object
11582 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11583 * the data set size</em>
11585 getCount : function(){
11586 return this.data.length || 0;
11590 * Gets the total number of records in the dataset as returned by the server.
11592 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11593 * the dataset size</em>
11595 getTotalCount : function(){
11596 return this.totalLength || 0;
11600 * Returns the sort state of the Store as an object with two properties:
11602 field {String} The name of the field by which the Records are sorted
11603 direction {String} The sort order, "ASC" or "DESC"
11606 getSortState : function(){
11607 return this.sortInfo;
11611 applySort : function(){
11612 if(this.sortInfo && !this.remoteSort){
11613 var s = this.sortInfo, f = s.field;
11614 var st = this.fields.get(f).sortType;
11615 var fn = function(r1, r2){
11616 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11617 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11619 this.data.sort(s.direction, fn);
11620 if(this.snapshot && this.snapshot != this.data){
11621 this.snapshot.sort(s.direction, fn);
11627 * Sets the default sort column and order to be used by the next load operation.
11628 * @param {String} fieldName The name of the field to sort by.
11629 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11631 setDefaultSort : function(field, dir){
11632 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11636 * Sort the Records.
11637 * If remote sorting is used, the sort is performed on the server, and the cache is
11638 * reloaded. If local sorting is used, the cache is sorted internally.
11639 * @param {String} fieldName The name of the field to sort by.
11640 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11642 sort : function(fieldName, dir){
11643 var f = this.fields.get(fieldName);
11645 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11647 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11648 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11653 this.sortToggle[f.name] = dir;
11654 this.sortInfo = {field: f.name, direction: dir};
11655 if(!this.remoteSort){
11657 this.fireEvent("datachanged", this);
11659 this.load(this.lastOptions);
11664 * Calls the specified function for each of the Records in the cache.
11665 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11666 * Returning <em>false</em> aborts and exits the iteration.
11667 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11669 each : function(fn, scope){
11670 this.data.each(fn, scope);
11674 * Gets all records modified since the last commit. Modified records are persisted across load operations
11675 * (e.g., during paging).
11676 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11678 getModifiedRecords : function(){
11679 return this.modified;
11683 createFilterFn : function(property, value, anyMatch){
11684 if(!value.exec){ // not a regex
11685 value = String(value);
11686 if(value.length == 0){
11689 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11691 return function(r){
11692 return value.test(r.data[property]);
11697 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11698 * @param {String} property A field on your records
11699 * @param {Number} start The record index to start at (defaults to 0)
11700 * @param {Number} end The last record index to include (defaults to length - 1)
11701 * @return {Number} The sum
11703 sum : function(property, start, end){
11704 var rs = this.data.items, v = 0;
11705 start = start || 0;
11706 end = (end || end === 0) ? end : rs.length-1;
11708 for(var i = start; i <= end; i++){
11709 v += (rs[i].data[property] || 0);
11715 * Filter the records by a specified property.
11716 * @param {String} field A field on your records
11717 * @param {String/RegExp} value Either a string that the field
11718 * should start with or a RegExp to test against the field
11719 * @param {Boolean} anyMatch True to match any part not just the beginning
11721 filter : function(property, value, anyMatch){
11722 var fn = this.createFilterFn(property, value, anyMatch);
11723 return fn ? this.filterBy(fn) : this.clearFilter();
11727 * Filter by a function. The specified function will be called with each
11728 * record in this data source. If the function returns true the record is included,
11729 * otherwise it is filtered.
11730 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11731 * @param {Object} scope (optional) The scope of the function (defaults to this)
11733 filterBy : function(fn, scope){
11734 this.snapshot = this.snapshot || this.data;
11735 this.data = this.queryBy(fn, scope||this);
11736 this.fireEvent("datachanged", this);
11740 * Query the records by a specified property.
11741 * @param {String} field A field on your records
11742 * @param {String/RegExp} value Either a string that the field
11743 * should start with or a RegExp to test against the field
11744 * @param {Boolean} anyMatch True to match any part not just the beginning
11745 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11747 query : function(property, value, anyMatch){
11748 var fn = this.createFilterFn(property, value, anyMatch);
11749 return fn ? this.queryBy(fn) : this.data.clone();
11753 * Query by a function. The specified function will be called with each
11754 * record in this data source. If the function returns true the record is included
11756 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11757 * @param {Object} scope (optional) The scope of the function (defaults to this)
11758 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11760 queryBy : function(fn, scope){
11761 var data = this.snapshot || this.data;
11762 return data.filterBy(fn, scope||this);
11766 * Collects unique values for a particular dataIndex from this store.
11767 * @param {String} dataIndex The property to collect
11768 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11769 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11770 * @return {Array} An array of the unique values
11772 collect : function(dataIndex, allowNull, bypassFilter){
11773 var d = (bypassFilter === true && this.snapshot) ?
11774 this.snapshot.items : this.data.items;
11775 var v, sv, r = [], l = {};
11776 for(var i = 0, len = d.length; i < len; i++){
11777 v = d[i].data[dataIndex];
11779 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11788 * Revert to a view of the Record cache with no filtering applied.
11789 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11791 clearFilter : function(suppressEvent){
11792 if(this.snapshot && this.snapshot != this.data){
11793 this.data = this.snapshot;
11794 delete this.snapshot;
11795 if(suppressEvent !== true){
11796 this.fireEvent("datachanged", this);
11802 afterEdit : function(record){
11803 if(this.modified.indexOf(record) == -1){
11804 this.modified.push(record);
11806 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11810 afterReject : function(record){
11811 this.modified.remove(record);
11812 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11816 afterCommit : function(record){
11817 this.modified.remove(record);
11818 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11822 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11823 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11825 commitChanges : function(){
11826 var m = this.modified.slice(0);
11827 this.modified = [];
11828 for(var i = 0, len = m.length; i < len; i++){
11834 * Cancel outstanding changes on all changed records.
11836 rejectChanges : function(){
11837 var m = this.modified.slice(0);
11838 this.modified = [];
11839 for(var i = 0, len = m.length; i < len; i++){
11844 onMetaChange : function(meta, rtype, o){
11845 this.recordType = rtype;
11846 this.fields = rtype.prototype.fields;
11847 delete this.snapshot;
11848 this.sortInfo = meta.sortInfo || this.sortInfo;
11849 this.modified = [];
11850 this.fireEvent('metachange', this, this.reader.meta);
11853 moveIndex : function(data, type)
11855 var index = this.indexOf(data);
11857 var newIndex = index + type;
11861 this.insert(newIndex, data);
11866 * Ext JS Library 1.1.1
11867 * Copyright(c) 2006-2007, Ext JS, LLC.
11869 * Originally Released Under LGPL - original licence link has changed is not relivant.
11872 * <script type="text/javascript">
11876 * @class Roo.data.SimpleStore
11877 * @extends Roo.data.Store
11878 * Small helper class to make creating Stores from Array data easier.
11879 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11880 * @cfg {Array} fields An array of field definition objects, or field name strings.
11881 * @cfg {Array} data The multi-dimensional array of data
11883 * @param {Object} config
11885 Roo.data.SimpleStore = function(config){
11886 Roo.data.SimpleStore.superclass.constructor.call(this, {
11888 reader: new Roo.data.ArrayReader({
11891 Roo.data.Record.create(config.fields)
11893 proxy : new Roo.data.MemoryProxy(config.data)
11897 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11899 * Ext JS Library 1.1.1
11900 * Copyright(c) 2006-2007, Ext JS, LLC.
11902 * Originally Released Under LGPL - original licence link has changed is not relivant.
11905 * <script type="text/javascript">
11910 * @extends Roo.data.Store
11911 * @class Roo.data.JsonStore
11912 * Small helper class to make creating Stores for JSON data easier. <br/>
11914 var store = new Roo.data.JsonStore({
11915 url: 'get-images.php',
11917 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11920 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11921 * JsonReader and HttpProxy (unless inline data is provided).</b>
11922 * @cfg {Array} fields An array of field definition objects, or field name strings.
11924 * @param {Object} config
11926 Roo.data.JsonStore = function(c){
11927 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11928 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11929 reader: new Roo.data.JsonReader(c, c.fields)
11932 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11934 * Ext JS Library 1.1.1
11935 * Copyright(c) 2006-2007, Ext JS, LLC.
11937 * Originally Released Under LGPL - original licence link has changed is not relivant.
11940 * <script type="text/javascript">
11944 Roo.data.Field = function(config){
11945 if(typeof config == "string"){
11946 config = {name: config};
11948 Roo.apply(this, config);
11951 this.type = "auto";
11954 var st = Roo.data.SortTypes;
11955 // named sortTypes are supported, here we look them up
11956 if(typeof this.sortType == "string"){
11957 this.sortType = st[this.sortType];
11960 // set default sortType for strings and dates
11961 if(!this.sortType){
11964 this.sortType = st.asUCString;
11967 this.sortType = st.asDate;
11970 this.sortType = st.none;
11975 var stripRe = /[\$,%]/g;
11977 // prebuilt conversion function for this field, instead of
11978 // switching every time we're reading a value
11980 var cv, dateFormat = this.dateFormat;
11985 cv = function(v){ return v; };
11988 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11992 return v !== undefined && v !== null && v !== '' ?
11993 parseInt(String(v).replace(stripRe, ""), 10) : '';
11998 return v !== undefined && v !== null && v !== '' ?
11999 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12004 cv = function(v){ return v === true || v === "true" || v == 1; };
12011 if(v instanceof Date){
12015 if(dateFormat == "timestamp"){
12016 return new Date(v*1000);
12018 return Date.parseDate(v, dateFormat);
12020 var parsed = Date.parse(v);
12021 return parsed ? new Date(parsed) : null;
12030 Roo.data.Field.prototype = {
12038 * Ext JS Library 1.1.1
12039 * Copyright(c) 2006-2007, Ext JS, LLC.
12041 * Originally Released Under LGPL - original licence link has changed is not relivant.
12044 * <script type="text/javascript">
12047 // Base class for reading structured data from a data source. This class is intended to be
12048 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12051 * @class Roo.data.DataReader
12052 * Base class for reading structured data from a data source. This class is intended to be
12053 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12056 Roo.data.DataReader = function(meta, recordType){
12060 this.recordType = recordType instanceof Array ?
12061 Roo.data.Record.create(recordType) : recordType;
12064 Roo.data.DataReader.prototype = {
12066 * Create an empty record
12067 * @param {Object} data (optional) - overlay some values
12068 * @return {Roo.data.Record} record created.
12070 newRow : function(d) {
12072 this.recordType.prototype.fields.each(function(c) {
12074 case 'int' : da[c.name] = 0; break;
12075 case 'date' : da[c.name] = new Date(); break;
12076 case 'float' : da[c.name] = 0.0; break;
12077 case 'boolean' : da[c.name] = false; break;
12078 default : da[c.name] = ""; break;
12082 return new this.recordType(Roo.apply(da, d));
12087 * Ext JS Library 1.1.1
12088 * Copyright(c) 2006-2007, Ext JS, LLC.
12090 * Originally Released Under LGPL - original licence link has changed is not relivant.
12093 * <script type="text/javascript">
12097 * @class Roo.data.DataProxy
12098 * @extends Roo.data.Observable
12099 * This class is an abstract base class for implementations which provide retrieval of
12100 * unformatted data objects.<br>
12102 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12103 * (of the appropriate type which knows how to parse the data object) to provide a block of
12104 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12106 * Custom implementations must implement the load method as described in
12107 * {@link Roo.data.HttpProxy#load}.
12109 Roo.data.DataProxy = function(){
12112 * @event beforeload
12113 * Fires before a network request is made to retrieve a data object.
12114 * @param {Object} This DataProxy object.
12115 * @param {Object} params The params parameter to the load function.
12120 * Fires before the load method's callback is called.
12121 * @param {Object} This DataProxy object.
12122 * @param {Object} o The data object.
12123 * @param {Object} arg The callback argument object passed to the load function.
12127 * @event loadexception
12128 * Fires if an Exception occurs during data retrieval.
12129 * @param {Object} This DataProxy object.
12130 * @param {Object} o The data object.
12131 * @param {Object} arg The callback argument object passed to the load function.
12132 * @param {Object} e The Exception.
12134 loadexception : true
12136 Roo.data.DataProxy.superclass.constructor.call(this);
12139 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12142 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12146 * Ext JS Library 1.1.1
12147 * Copyright(c) 2006-2007, Ext JS, LLC.
12149 * Originally Released Under LGPL - original licence link has changed is not relivant.
12152 * <script type="text/javascript">
12155 * @class Roo.data.MemoryProxy
12156 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12157 * to the Reader when its load method is called.
12159 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12161 Roo.data.MemoryProxy = function(data){
12165 Roo.data.MemoryProxy.superclass.constructor.call(this);
12169 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12172 * Load data from the requested source (in this case an in-memory
12173 * data object passed to the constructor), read the data object into
12174 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12175 * process that block using the passed callback.
12176 * @param {Object} params This parameter is not used by the MemoryProxy class.
12177 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12178 * object into a block of Roo.data.Records.
12179 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12180 * The function must be passed <ul>
12181 * <li>The Record block object</li>
12182 * <li>The "arg" argument from the load function</li>
12183 * <li>A boolean success indicator</li>
12185 * @param {Object} scope The scope in which to call the callback
12186 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12188 load : function(params, reader, callback, scope, arg){
12189 params = params || {};
12192 result = reader.readRecords(this.data);
12194 this.fireEvent("loadexception", this, arg, null, e);
12195 callback.call(scope, null, arg, false);
12198 callback.call(scope, result, arg, true);
12202 update : function(params, records){
12207 * Ext JS Library 1.1.1
12208 * Copyright(c) 2006-2007, Ext JS, LLC.
12210 * Originally Released Under LGPL - original licence link has changed is not relivant.
12213 * <script type="text/javascript">
12216 * @class Roo.data.HttpProxy
12217 * @extends Roo.data.DataProxy
12218 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12219 * configured to reference a certain URL.<br><br>
12221 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12222 * from which the running page was served.<br><br>
12224 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12226 * Be aware that to enable the browser to parse an XML document, the server must set
12227 * the Content-Type header in the HTTP response to "text/xml".
12229 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12230 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12231 * will be used to make the request.
12233 Roo.data.HttpProxy = function(conn){
12234 Roo.data.HttpProxy.superclass.constructor.call(this);
12235 // is conn a conn config or a real conn?
12237 this.useAjax = !conn || !conn.events;
12241 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12242 // thse are take from connection...
12245 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12248 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12249 * extra parameters to each request made by this object. (defaults to undefined)
12252 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12253 * to each request made by this object. (defaults to undefined)
12256 * @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)
12259 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12262 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12268 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12272 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12273 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12274 * a finer-grained basis than the DataProxy events.
12276 getConnection : function(){
12277 return this.useAjax ? Roo.Ajax : this.conn;
12281 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12282 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12283 * process that block using the passed callback.
12284 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12285 * for the request to the remote server.
12286 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12287 * object into a block of Roo.data.Records.
12288 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12289 * The function must be passed <ul>
12290 * <li>The Record block object</li>
12291 * <li>The "arg" argument from the load function</li>
12292 * <li>A boolean success indicator</li>
12294 * @param {Object} scope The scope in which to call the callback
12295 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12297 load : function(params, reader, callback, scope, arg){
12298 if(this.fireEvent("beforeload", this, params) !== false){
12300 params : params || {},
12302 callback : callback,
12307 callback : this.loadResponse,
12311 Roo.applyIf(o, this.conn);
12312 if(this.activeRequest){
12313 Roo.Ajax.abort(this.activeRequest);
12315 this.activeRequest = Roo.Ajax.request(o);
12317 this.conn.request(o);
12320 callback.call(scope||this, null, arg, false);
12325 loadResponse : function(o, success, response){
12326 delete this.activeRequest;
12328 this.fireEvent("loadexception", this, o, response);
12329 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12334 result = o.reader.read(response);
12336 this.fireEvent("loadexception", this, o, response, e);
12337 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12341 this.fireEvent("load", this, o, o.request.arg);
12342 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12346 update : function(dataSet){
12351 updateResponse : function(dataSet){
12356 * Ext JS Library 1.1.1
12357 * Copyright(c) 2006-2007, Ext JS, LLC.
12359 * Originally Released Under LGPL - original licence link has changed is not relivant.
12362 * <script type="text/javascript">
12366 * @class Roo.data.ScriptTagProxy
12367 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12368 * other than the originating domain of the running page.<br><br>
12370 * <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
12371 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12373 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12374 * source code that is used as the source inside a <script> tag.<br><br>
12376 * In order for the browser to process the returned data, the server must wrap the data object
12377 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12378 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12379 * depending on whether the callback name was passed:
12382 boolean scriptTag = false;
12383 String cb = request.getParameter("callback");
12386 response.setContentType("text/javascript");
12388 response.setContentType("application/x-json");
12390 Writer out = response.getWriter();
12392 out.write(cb + "(");
12394 out.print(dataBlock.toJsonString());
12401 * @param {Object} config A configuration object.
12403 Roo.data.ScriptTagProxy = function(config){
12404 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12405 Roo.apply(this, config);
12406 this.head = document.getElementsByTagName("head")[0];
12409 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12411 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12413 * @cfg {String} url The URL from which to request the data object.
12416 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12420 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12421 * the server the name of the callback function set up by the load call to process the returned data object.
12422 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12423 * javascript output which calls this named function passing the data object as its only parameter.
12425 callbackParam : "callback",
12427 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12428 * name to the request.
12433 * Load data from the configured URL, read the data object into
12434 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12435 * process that block using the passed callback.
12436 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12437 * for the request to the remote server.
12438 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12439 * object into a block of Roo.data.Records.
12440 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12441 * The function must be passed <ul>
12442 * <li>The Record block object</li>
12443 * <li>The "arg" argument from the load function</li>
12444 * <li>A boolean success indicator</li>
12446 * @param {Object} scope The scope in which to call the callback
12447 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12449 load : function(params, reader, callback, scope, arg){
12450 if(this.fireEvent("beforeload", this, params) !== false){
12452 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12454 var url = this.url;
12455 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12457 url += "&_dc=" + (new Date().getTime());
12459 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12462 cb : "stcCallback"+transId,
12463 scriptId : "stcScript"+transId,
12467 callback : callback,
12473 window[trans.cb] = function(o){
12474 conn.handleResponse(o, trans);
12477 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12479 if(this.autoAbort !== false){
12483 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12485 var script = document.createElement("script");
12486 script.setAttribute("src", url);
12487 script.setAttribute("type", "text/javascript");
12488 script.setAttribute("id", trans.scriptId);
12489 this.head.appendChild(script);
12491 this.trans = trans;
12493 callback.call(scope||this, null, arg, false);
12498 isLoading : function(){
12499 return this.trans ? true : false;
12503 * Abort the current server request.
12505 abort : function(){
12506 if(this.isLoading()){
12507 this.destroyTrans(this.trans);
12512 destroyTrans : function(trans, isLoaded){
12513 this.head.removeChild(document.getElementById(trans.scriptId));
12514 clearTimeout(trans.timeoutId);
12516 window[trans.cb] = undefined;
12518 delete window[trans.cb];
12521 // if hasn't been loaded, wait for load to remove it to prevent script error
12522 window[trans.cb] = function(){
12523 window[trans.cb] = undefined;
12525 delete window[trans.cb];
12532 handleResponse : function(o, trans){
12533 this.trans = false;
12534 this.destroyTrans(trans, true);
12537 result = trans.reader.readRecords(o);
12539 this.fireEvent("loadexception", this, o, trans.arg, e);
12540 trans.callback.call(trans.scope||window, null, trans.arg, false);
12543 this.fireEvent("load", this, o, trans.arg);
12544 trans.callback.call(trans.scope||window, result, trans.arg, true);
12548 handleFailure : function(trans){
12549 this.trans = false;
12550 this.destroyTrans(trans, false);
12551 this.fireEvent("loadexception", this, null, trans.arg);
12552 trans.callback.call(trans.scope||window, null, trans.arg, false);
12556 * Ext JS Library 1.1.1
12557 * Copyright(c) 2006-2007, Ext JS, LLC.
12559 * Originally Released Under LGPL - original licence link has changed is not relivant.
12562 * <script type="text/javascript">
12566 * @class Roo.data.JsonReader
12567 * @extends Roo.data.DataReader
12568 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12569 * based on mappings in a provided Roo.data.Record constructor.
12571 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12572 * in the reply previously.
12577 var RecordDef = Roo.data.Record.create([
12578 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12579 {name: 'occupation'} // This field will use "occupation" as the mapping.
12581 var myReader = new Roo.data.JsonReader({
12582 totalProperty: "results", // The property which contains the total dataset size (optional)
12583 root: "rows", // The property which contains an Array of row objects
12584 id: "id" // The property within each row object that provides an ID for the record (optional)
12588 * This would consume a JSON file like this:
12590 { 'results': 2, 'rows': [
12591 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12592 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12595 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12596 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12597 * paged from the remote server.
12598 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12599 * @cfg {String} root name of the property which contains the Array of row objects.
12600 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12601 * @cfg {Array} fields Array of field definition objects
12603 * Create a new JsonReader
12604 * @param {Object} meta Metadata configuration options
12605 * @param {Object} recordType Either an Array of field definition objects,
12606 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12608 Roo.data.JsonReader = function(meta, recordType){
12611 // set some defaults:
12612 Roo.applyIf(meta, {
12613 totalProperty: 'total',
12614 successProperty : 'success',
12619 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12621 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12624 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12625 * Used by Store query builder to append _requestMeta to params.
12628 metaFromRemote : false,
12630 * This method is only used by a DataProxy which has retrieved data from a remote server.
12631 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12632 * @return {Object} data A data block which is used by an Roo.data.Store object as
12633 * a cache of Roo.data.Records.
12635 read : function(response){
12636 var json = response.responseText;
12638 var o = /* eval:var:o */ eval("("+json+")");
12640 throw {message: "JsonReader.read: Json object not found"};
12646 this.metaFromRemote = true;
12647 this.meta = o.metaData;
12648 this.recordType = Roo.data.Record.create(o.metaData.fields);
12649 this.onMetaChange(this.meta, this.recordType, o);
12651 return this.readRecords(o);
12654 // private function a store will implement
12655 onMetaChange : function(meta, recordType, o){
12662 simpleAccess: function(obj, subsc) {
12669 getJsonAccessor: function(){
12671 return function(expr) {
12673 return(re.test(expr))
12674 ? new Function("obj", "return obj." + expr)
12679 return Roo.emptyFn;
12684 * Create a data block containing Roo.data.Records from an XML document.
12685 * @param {Object} o An object which contains an Array of row objects in the property specified
12686 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12687 * which contains the total size of the dataset.
12688 * @return {Object} data A data block which is used by an Roo.data.Store object as
12689 * a cache of Roo.data.Records.
12691 readRecords : function(o){
12693 * After any data loads, the raw JSON data is available for further custom processing.
12697 var s = this.meta, Record = this.recordType,
12698 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12700 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12702 if(s.totalProperty) {
12703 this.getTotal = this.getJsonAccessor(s.totalProperty);
12705 if(s.successProperty) {
12706 this.getSuccess = this.getJsonAccessor(s.successProperty);
12708 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12710 var g = this.getJsonAccessor(s.id);
12711 this.getId = function(rec) {
12713 return (r === undefined || r === "") ? null : r;
12716 this.getId = function(){return null;};
12719 for(var jj = 0; jj < fl; jj++){
12721 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12722 this.ef[jj] = this.getJsonAccessor(map);
12726 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12727 if(s.totalProperty){
12728 var vt = parseInt(this.getTotal(o), 10);
12733 if(s.successProperty){
12734 var vs = this.getSuccess(o);
12735 if(vs === false || vs === 'false'){
12740 for(var i = 0; i < c; i++){
12743 var id = this.getId(n);
12744 for(var j = 0; j < fl; j++){
12746 var v = this.ef[j](n);
12748 Roo.log('missing convert for ' + f.name);
12752 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12754 var record = new Record(values, id);
12756 records[i] = record;
12762 totalRecords : totalRecords
12767 * Ext JS Library 1.1.1
12768 * Copyright(c) 2006-2007, Ext JS, LLC.
12770 * Originally Released Under LGPL - original licence link has changed is not relivant.
12773 * <script type="text/javascript">
12777 * @class Roo.data.ArrayReader
12778 * @extends Roo.data.DataReader
12779 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12780 * Each element of that Array represents a row of data fields. The
12781 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12782 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12786 var RecordDef = Roo.data.Record.create([
12787 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12788 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12790 var myReader = new Roo.data.ArrayReader({
12791 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12795 * This would consume an Array like this:
12797 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12799 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12801 * Create a new JsonReader
12802 * @param {Object} meta Metadata configuration options.
12803 * @param {Object} recordType Either an Array of field definition objects
12804 * as specified to {@link Roo.data.Record#create},
12805 * or an {@link Roo.data.Record} object
12806 * created using {@link Roo.data.Record#create}.
12808 Roo.data.ArrayReader = function(meta, recordType){
12809 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12812 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12814 * Create a data block containing Roo.data.Records from an XML document.
12815 * @param {Object} o An Array of row objects which represents the dataset.
12816 * @return {Object} data A data block which is used by an Roo.data.Store object as
12817 * a cache of Roo.data.Records.
12819 readRecords : function(o){
12820 var sid = this.meta ? this.meta.id : null;
12821 var recordType = this.recordType, fields = recordType.prototype.fields;
12824 for(var i = 0; i < root.length; i++){
12827 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12828 for(var j = 0, jlen = fields.length; j < jlen; j++){
12829 var f = fields.items[j];
12830 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12831 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12833 values[f.name] = v;
12835 var record = new recordType(values, id);
12837 records[records.length] = record;
12841 totalRecords : records.length
12850 * @class Roo.bootstrap.ComboBox
12851 * @extends Roo.bootstrap.TriggerField
12852 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12853 * @cfg {Boolean} append (true|false) default false
12854 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12855 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12856 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12857 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12858 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12859 * @cfg {Boolean} animate default true
12860 * @cfg {Boolean} emptyResultText only for touch device
12861 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12862 * @cfg {String} emptyTitle default ''
12864 * Create a new ComboBox.
12865 * @param {Object} config Configuration options
12867 Roo.bootstrap.ComboBox = function(config){
12868 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12872 * Fires when the dropdown list is expanded
12873 * @param {Roo.bootstrap.ComboBox} combo This combo box
12878 * Fires when the dropdown list is collapsed
12879 * @param {Roo.bootstrap.ComboBox} combo This combo box
12883 * @event beforeselect
12884 * Fires before a list item is selected. Return false to cancel the selection.
12885 * @param {Roo.bootstrap.ComboBox} combo This combo box
12886 * @param {Roo.data.Record} record The data record returned from the underlying store
12887 * @param {Number} index The index of the selected item in the dropdown list
12889 'beforeselect' : true,
12892 * Fires when a list item is selected
12893 * @param {Roo.bootstrap.ComboBox} combo This combo box
12894 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12895 * @param {Number} index The index of the selected item in the dropdown list
12899 * @event beforequery
12900 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12901 * The event object passed has these properties:
12902 * @param {Roo.bootstrap.ComboBox} combo This combo box
12903 * @param {String} query The query
12904 * @param {Boolean} forceAll true to force "all" query
12905 * @param {Boolean} cancel true to cancel the query
12906 * @param {Object} e The query event object
12908 'beforequery': true,
12911 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12912 * @param {Roo.bootstrap.ComboBox} combo This combo box
12917 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12918 * @param {Roo.bootstrap.ComboBox} combo This combo box
12919 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12924 * Fires when the remove value from the combobox array
12925 * @param {Roo.bootstrap.ComboBox} combo This combo box
12929 * @event afterremove
12930 * Fires when the remove value from the combobox array
12931 * @param {Roo.bootstrap.ComboBox} combo This combo box
12933 'afterremove' : true,
12935 * @event specialfilter
12936 * Fires when specialfilter
12937 * @param {Roo.bootstrap.ComboBox} combo This combo box
12939 'specialfilter' : true,
12942 * Fires when tick the element
12943 * @param {Roo.bootstrap.ComboBox} combo This combo box
12947 * @event touchviewdisplay
12948 * Fires when touch view require special display (default is using displayField)
12949 * @param {Roo.bootstrap.ComboBox} combo This combo box
12950 * @param {Object} cfg set html .
12952 'touchviewdisplay' : true
12957 this.tickItems = [];
12959 this.selectedIndex = -1;
12960 if(this.mode == 'local'){
12961 if(config.queryDelay === undefined){
12962 this.queryDelay = 10;
12964 if(config.minChars === undefined){
12970 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12973 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12974 * rendering into an Roo.Editor, defaults to false)
12977 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12978 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12981 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12984 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12985 * the dropdown list (defaults to undefined, with no header element)
12989 * @cfg {String/Roo.Template} tpl The template to use to render the output
12993 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12995 listWidth: undefined,
12997 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12998 * mode = 'remote' or 'text' if mode = 'local')
13000 displayField: undefined,
13003 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13004 * mode = 'remote' or 'value' if mode = 'local').
13005 * Note: use of a valueField requires the user make a selection
13006 * in order for a value to be mapped.
13008 valueField: undefined,
13010 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13015 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13016 * field's data value (defaults to the underlying DOM element's name)
13018 hiddenName: undefined,
13020 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13024 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13026 selectedClass: 'active',
13029 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13033 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13034 * anchor positions (defaults to 'tl-bl')
13036 listAlign: 'tl-bl?',
13038 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13042 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13043 * query specified by the allQuery config option (defaults to 'query')
13045 triggerAction: 'query',
13047 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13048 * (defaults to 4, does not apply if editable = false)
13052 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13053 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13057 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13058 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13062 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13063 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13067 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13068 * when editable = true (defaults to false)
13070 selectOnFocus:false,
13072 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13074 queryParam: 'query',
13076 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13077 * when mode = 'remote' (defaults to 'Loading...')
13079 loadingText: 'Loading...',
13081 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13085 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13089 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13090 * traditional select (defaults to true)
13094 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13098 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13102 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13103 * listWidth has a higher value)
13107 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13108 * allow the user to set arbitrary text into the field (defaults to false)
13110 forceSelection:false,
13112 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13113 * if typeAhead = true (defaults to 250)
13115 typeAheadDelay : 250,
13117 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13118 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13120 valueNotFoundText : undefined,
13122 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13124 blockFocus : false,
13127 * @cfg {Boolean} disableClear Disable showing of clear button.
13129 disableClear : false,
13131 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13133 alwaysQuery : false,
13136 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13141 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13143 invalidClass : "has-warning",
13146 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13148 validClass : "has-success",
13151 * @cfg {Boolean} specialFilter (true|false) special filter default false
13153 specialFilter : false,
13156 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13158 mobileTouchView : true,
13161 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13163 useNativeIOS : false,
13166 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13168 mobile_restrict_height : false,
13170 ios_options : false,
13182 btnPosition : 'right',
13183 triggerList : true,
13184 showToggleBtn : true,
13186 emptyResultText: 'Empty',
13187 triggerText : 'Select',
13190 // element that contains real text value.. (when hidden is used..)
13192 getAutoCreate : function()
13197 * Render classic select for iso
13200 if(Roo.isIOS && this.useNativeIOS){
13201 cfg = this.getAutoCreateNativeIOS();
13209 if(Roo.isTouch && this.mobileTouchView){
13210 cfg = this.getAutoCreateTouchView();
13217 if(!this.tickable){
13218 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13223 * ComboBox with tickable selections
13226 var align = this.labelAlign || this.parentLabelAlign();
13229 cls : 'form-group roo-combobox-tickable' //input-group
13232 var btn_text_select = '';
13233 var btn_text_done = '';
13234 var btn_text_cancel = '';
13236 if (this.btn_text_show) {
13237 btn_text_select = 'Select';
13238 btn_text_done = 'Done';
13239 btn_text_cancel = 'Cancel';
13244 cls : 'tickable-buttons',
13249 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13250 //html : this.triggerText
13251 html: btn_text_select
13257 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13259 html: btn_text_done
13265 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13267 html: btn_text_cancel
13273 buttons.cn.unshift({
13275 cls: 'roo-select2-search-field-input'
13281 Roo.each(buttons.cn, function(c){
13283 c.cls += ' btn-' + _this.size;
13286 if (_this.disabled) {
13297 cls: 'form-hidden-field'
13301 cls: 'roo-select2-choices',
13305 cls: 'roo-select2-search-field',
13316 cls: 'roo-select2-container input-group roo-select2-container-multi',
13321 // cls: 'typeahead typeahead-long dropdown-menu',
13322 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13327 if(this.hasFeedback && !this.allowBlank){
13331 cls: 'glyphicon form-control-feedback'
13334 combobox.cn.push(feedback);
13338 if (align ==='left' && this.fieldLabel.length) {
13340 cfg.cls += ' roo-form-group-label-left';
13345 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13346 tooltip : 'This field is required'
13351 cls : 'control-label',
13352 html : this.fieldLabel
13364 var labelCfg = cfg.cn[1];
13365 var contentCfg = cfg.cn[2];
13368 if(this.indicatorpos == 'right'){
13374 cls : 'control-label',
13378 html : this.fieldLabel
13382 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13383 tooltip : 'This field is required'
13398 labelCfg = cfg.cn[0];
13399 contentCfg = cfg.cn[1];
13403 if(this.labelWidth > 12){
13404 labelCfg.style = "width: " + this.labelWidth + 'px';
13407 if(this.labelWidth < 13 && this.labelmd == 0){
13408 this.labelmd = this.labelWidth;
13411 if(this.labellg > 0){
13412 labelCfg.cls += ' col-lg-' + this.labellg;
13413 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13416 if(this.labelmd > 0){
13417 labelCfg.cls += ' col-md-' + this.labelmd;
13418 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13421 if(this.labelsm > 0){
13422 labelCfg.cls += ' col-sm-' + this.labelsm;
13423 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13426 if(this.labelxs > 0){
13427 labelCfg.cls += ' col-xs-' + this.labelxs;
13428 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13432 } else if ( this.fieldLabel.length) {
13433 // Roo.log(" label");
13437 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13438 tooltip : 'This field is required'
13442 //cls : 'input-group-addon',
13443 html : this.fieldLabel
13448 if(this.indicatorpos == 'right'){
13452 //cls : 'input-group-addon',
13453 html : this.fieldLabel
13457 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13458 tooltip : 'This field is required'
13467 // Roo.log(" no label && no align");
13474 ['xs','sm','md','lg'].map(function(size){
13475 if (settings[size]) {
13476 cfg.cls += ' col-' + size + '-' + settings[size];
13484 _initEventsCalled : false,
13487 initEvents: function()
13489 if (this._initEventsCalled) { // as we call render... prevent looping...
13492 this._initEventsCalled = true;
13495 throw "can not find store for combo";
13498 this.indicator = this.indicatorEl();
13500 this.store = Roo.factory(this.store, Roo.data);
13501 this.store.parent = this;
13503 // if we are building from html. then this element is so complex, that we can not really
13504 // use the rendered HTML.
13505 // so we have to trash and replace the previous code.
13506 if (Roo.XComponent.build_from_html) {
13507 // remove this element....
13508 var e = this.el.dom, k=0;
13509 while (e ) { e = e.previousSibling; ++k;}
13514 this.rendered = false;
13516 this.render(this.parent().getChildContainer(true), k);
13519 if(Roo.isIOS && this.useNativeIOS){
13520 this.initIOSView();
13528 if(Roo.isTouch && this.mobileTouchView){
13529 this.initTouchView();
13534 this.initTickableEvents();
13538 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13540 if(this.hiddenName){
13542 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13544 this.hiddenField.dom.value =
13545 this.hiddenValue !== undefined ? this.hiddenValue :
13546 this.value !== undefined ? this.value : '';
13548 // prevent input submission
13549 this.el.dom.removeAttribute('name');
13550 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13555 // this.el.dom.setAttribute('autocomplete', 'off');
13558 var cls = 'x-combo-list';
13560 //this.list = new Roo.Layer({
13561 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13567 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13568 _this.list.setWidth(lw);
13571 this.list.on('mouseover', this.onViewOver, this);
13572 this.list.on('mousemove', this.onViewMove, this);
13573 this.list.on('scroll', this.onViewScroll, this);
13576 this.list.swallowEvent('mousewheel');
13577 this.assetHeight = 0;
13580 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13581 this.assetHeight += this.header.getHeight();
13584 this.innerList = this.list.createChild({cls:cls+'-inner'});
13585 this.innerList.on('mouseover', this.onViewOver, this);
13586 this.innerList.on('mousemove', this.onViewMove, this);
13587 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13589 if(this.allowBlank && !this.pageSize && !this.disableClear){
13590 this.footer = this.list.createChild({cls:cls+'-ft'});
13591 this.pageTb = new Roo.Toolbar(this.footer);
13595 this.footer = this.list.createChild({cls:cls+'-ft'});
13596 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13597 {pageSize: this.pageSize});
13601 if (this.pageTb && this.allowBlank && !this.disableClear) {
13603 this.pageTb.add(new Roo.Toolbar.Fill(), {
13604 cls: 'x-btn-icon x-btn-clear',
13606 handler: function()
13609 _this.clearValue();
13610 _this.onSelect(false, -1);
13615 this.assetHeight += this.footer.getHeight();
13620 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13623 this.view = new Roo.View(this.list, this.tpl, {
13624 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13626 //this.view.wrapEl.setDisplayed(false);
13627 this.view.on('click', this.onViewClick, this);
13630 this.store.on('beforeload', this.onBeforeLoad, this);
13631 this.store.on('load', this.onLoad, this);
13632 this.store.on('loadexception', this.onLoadException, this);
13634 if(this.resizable){
13635 this.resizer = new Roo.Resizable(this.list, {
13636 pinned:true, handles:'se'
13638 this.resizer.on('resize', function(r, w, h){
13639 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13640 this.listWidth = w;
13641 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13642 this.restrictHeight();
13644 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13647 if(!this.editable){
13648 this.editable = true;
13649 this.setEditable(false);
13654 if (typeof(this.events.add.listeners) != 'undefined') {
13656 this.addicon = this.wrap.createChild(
13657 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13659 this.addicon.on('click', function(e) {
13660 this.fireEvent('add', this);
13663 if (typeof(this.events.edit.listeners) != 'undefined') {
13665 this.editicon = this.wrap.createChild(
13666 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13667 if (this.addicon) {
13668 this.editicon.setStyle('margin-left', '40px');
13670 this.editicon.on('click', function(e) {
13672 // we fire even if inothing is selected..
13673 this.fireEvent('edit', this, this.lastData );
13679 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13680 "up" : function(e){
13681 this.inKeyMode = true;
13685 "down" : function(e){
13686 if(!this.isExpanded()){
13687 this.onTriggerClick();
13689 this.inKeyMode = true;
13694 "enter" : function(e){
13695 // this.onViewClick();
13699 if(this.fireEvent("specialkey", this, e)){
13700 this.onViewClick(false);
13706 "esc" : function(e){
13710 "tab" : function(e){
13713 if(this.fireEvent("specialkey", this, e)){
13714 this.onViewClick(false);
13722 doRelay : function(foo, bar, hname){
13723 if(hname == 'down' || this.scope.isExpanded()){
13724 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13733 this.queryDelay = Math.max(this.queryDelay || 10,
13734 this.mode == 'local' ? 10 : 250);
13737 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13739 if(this.typeAhead){
13740 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13742 if(this.editable !== false){
13743 this.inputEl().on("keyup", this.onKeyUp, this);
13745 if(this.forceSelection){
13746 this.inputEl().on('blur', this.doForce, this);
13750 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13751 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13755 initTickableEvents: function()
13759 if(this.hiddenName){
13761 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13763 this.hiddenField.dom.value =
13764 this.hiddenValue !== undefined ? this.hiddenValue :
13765 this.value !== undefined ? this.value : '';
13767 // prevent input submission
13768 this.el.dom.removeAttribute('name');
13769 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13774 // this.list = this.el.select('ul.dropdown-menu',true).first();
13776 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13777 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13778 if(this.triggerList){
13779 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13782 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13783 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13785 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13786 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13788 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13789 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13791 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13792 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13793 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13796 this.cancelBtn.hide();
13801 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13802 _this.list.setWidth(lw);
13805 this.list.on('mouseover', this.onViewOver, this);
13806 this.list.on('mousemove', this.onViewMove, this);
13808 this.list.on('scroll', this.onViewScroll, this);
13811 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13812 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13815 this.view = new Roo.View(this.list, this.tpl, {
13820 selectedClass: this.selectedClass
13823 //this.view.wrapEl.setDisplayed(false);
13824 this.view.on('click', this.onViewClick, this);
13828 this.store.on('beforeload', this.onBeforeLoad, this);
13829 this.store.on('load', this.onLoad, this);
13830 this.store.on('loadexception', this.onLoadException, this);
13833 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13834 "up" : function(e){
13835 this.inKeyMode = true;
13839 "down" : function(e){
13840 this.inKeyMode = true;
13844 "enter" : function(e){
13845 if(this.fireEvent("specialkey", this, e)){
13846 this.onViewClick(false);
13852 "esc" : function(e){
13853 this.onTickableFooterButtonClick(e, false, false);
13856 "tab" : function(e){
13857 this.fireEvent("specialkey", this, e);
13859 this.onTickableFooterButtonClick(e, false, false);
13866 doRelay : function(e, fn, key){
13867 if(this.scope.isExpanded()){
13868 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13877 this.queryDelay = Math.max(this.queryDelay || 10,
13878 this.mode == 'local' ? 10 : 250);
13881 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13883 if(this.typeAhead){
13884 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13887 if(this.editable !== false){
13888 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13891 this.indicator = this.indicatorEl();
13893 if(this.indicator){
13894 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13895 this.indicator.hide();
13900 onDestroy : function(){
13902 this.view.setStore(null);
13903 this.view.el.removeAllListeners();
13904 this.view.el.remove();
13905 this.view.purgeListeners();
13908 this.list.dom.innerHTML = '';
13912 this.store.un('beforeload', this.onBeforeLoad, this);
13913 this.store.un('load', this.onLoad, this);
13914 this.store.un('loadexception', this.onLoadException, this);
13916 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13920 fireKey : function(e){
13921 if(e.isNavKeyPress() && !this.list.isVisible()){
13922 this.fireEvent("specialkey", this, e);
13927 onResize: function(w, h){
13928 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13930 // if(typeof w != 'number'){
13931 // // we do not handle it!?!?
13934 // var tw = this.trigger.getWidth();
13935 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13936 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13938 // this.inputEl().setWidth( this.adjustWidth('input', x));
13940 // //this.trigger.setStyle('left', x+'px');
13942 // if(this.list && this.listWidth === undefined){
13943 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13944 // this.list.setWidth(lw);
13945 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13953 * Allow or prevent the user from directly editing the field text. If false is passed,
13954 * the user will only be able to select from the items defined in the dropdown list. This method
13955 * is the runtime equivalent of setting the 'editable' config option at config time.
13956 * @param {Boolean} value True to allow the user to directly edit the field text
13958 setEditable : function(value){
13959 if(value == this.editable){
13962 this.editable = value;
13964 this.inputEl().dom.setAttribute('readOnly', true);
13965 this.inputEl().on('mousedown', this.onTriggerClick, this);
13966 this.inputEl().addClass('x-combo-noedit');
13968 this.inputEl().dom.setAttribute('readOnly', false);
13969 this.inputEl().un('mousedown', this.onTriggerClick, this);
13970 this.inputEl().removeClass('x-combo-noedit');
13976 onBeforeLoad : function(combo,opts){
13977 if(!this.hasFocus){
13981 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13983 this.restrictHeight();
13984 this.selectedIndex = -1;
13988 onLoad : function(){
13990 this.hasQuery = false;
13992 if(!this.hasFocus){
13996 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13997 this.loading.hide();
14000 if(this.store.getCount() > 0){
14003 this.restrictHeight();
14004 if(this.lastQuery == this.allQuery){
14005 if(this.editable && !this.tickable){
14006 this.inputEl().dom.select();
14010 !this.selectByValue(this.value, true) &&
14013 !this.store.lastOptions ||
14014 typeof(this.store.lastOptions.add) == 'undefined' ||
14015 this.store.lastOptions.add != true
14018 this.select(0, true);
14021 if(this.autoFocus){
14024 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14025 this.taTask.delay(this.typeAheadDelay);
14029 this.onEmptyResults();
14035 onLoadException : function()
14037 this.hasQuery = false;
14039 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14040 this.loading.hide();
14043 if(this.tickable && this.editable){
14048 // only causes errors at present
14049 //Roo.log(this.store.reader.jsonData);
14050 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14052 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14058 onTypeAhead : function(){
14059 if(this.store.getCount() > 0){
14060 var r = this.store.getAt(0);
14061 var newValue = r.data[this.displayField];
14062 var len = newValue.length;
14063 var selStart = this.getRawValue().length;
14065 if(selStart != len){
14066 this.setRawValue(newValue);
14067 this.selectText(selStart, newValue.length);
14073 onSelect : function(record, index){
14075 if(this.fireEvent('beforeselect', this, record, index) !== false){
14077 this.setFromData(index > -1 ? record.data : false);
14080 this.fireEvent('select', this, record, index);
14085 * Returns the currently selected field value or empty string if no value is set.
14086 * @return {String} value The selected value
14088 getValue : function()
14090 if(Roo.isIOS && this.useNativeIOS){
14091 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14095 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14098 if(this.valueField){
14099 return typeof this.value != 'undefined' ? this.value : '';
14101 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14105 getRawValue : function()
14107 if(Roo.isIOS && this.useNativeIOS){
14108 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14111 var v = this.inputEl().getValue();
14117 * Clears any text/value currently set in the field
14119 clearValue : function(){
14121 if(this.hiddenField){
14122 this.hiddenField.dom.value = '';
14125 this.setRawValue('');
14126 this.lastSelectionText = '';
14127 this.lastData = false;
14129 var close = this.closeTriggerEl();
14140 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14141 * will be displayed in the field. If the value does not match the data value of an existing item,
14142 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14143 * Otherwise the field will be blank (although the value will still be set).
14144 * @param {String} value The value to match
14146 setValue : function(v)
14148 if(Roo.isIOS && this.useNativeIOS){
14149 this.setIOSValue(v);
14159 if(this.valueField){
14160 var r = this.findRecord(this.valueField, v);
14162 text = r.data[this.displayField];
14163 }else if(this.valueNotFoundText !== undefined){
14164 text = this.valueNotFoundText;
14167 this.lastSelectionText = text;
14168 if(this.hiddenField){
14169 this.hiddenField.dom.value = v;
14171 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14174 var close = this.closeTriggerEl();
14177 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14183 * @property {Object} the last set data for the element
14188 * Sets the value of the field based on a object which is related to the record format for the store.
14189 * @param {Object} value the value to set as. or false on reset?
14191 setFromData : function(o){
14198 var dv = ''; // display value
14199 var vv = ''; // value value..
14201 if (this.displayField) {
14202 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14204 // this is an error condition!!!
14205 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14208 if(this.valueField){
14209 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14212 var close = this.closeTriggerEl();
14215 if(dv.length || vv * 1 > 0){
14217 this.blockFocus=true;
14223 if(this.hiddenField){
14224 this.hiddenField.dom.value = vv;
14226 this.lastSelectionText = dv;
14227 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14231 // no hidden field.. - we store the value in 'value', but still display
14232 // display field!!!!
14233 this.lastSelectionText = dv;
14234 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14241 reset : function(){
14242 // overridden so that last data is reset..
14249 this.setValue(this.originalValue);
14250 //this.clearInvalid();
14251 this.lastData = false;
14253 this.view.clearSelections();
14259 findRecord : function(prop, value){
14261 if(this.store.getCount() > 0){
14262 this.store.each(function(r){
14263 if(r.data[prop] == value){
14273 getName: function()
14275 // returns hidden if it's set..
14276 if (!this.rendered) {return ''};
14277 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14281 onViewMove : function(e, t){
14282 this.inKeyMode = false;
14286 onViewOver : function(e, t){
14287 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14290 var item = this.view.findItemFromChild(t);
14293 var index = this.view.indexOf(item);
14294 this.select(index, false);
14299 onViewClick : function(view, doFocus, el, e)
14301 var index = this.view.getSelectedIndexes()[0];
14303 var r = this.store.getAt(index);
14307 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14314 Roo.each(this.tickItems, function(v,k){
14316 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14318 _this.tickItems.splice(k, 1);
14320 if(typeof(e) == 'undefined' && view == false){
14321 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14333 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14334 this.tickItems.push(r.data);
14337 if(typeof(e) == 'undefined' && view == false){
14338 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14345 this.onSelect(r, index);
14347 if(doFocus !== false && !this.blockFocus){
14348 this.inputEl().focus();
14353 restrictHeight : function(){
14354 //this.innerList.dom.style.height = '';
14355 //var inner = this.innerList.dom;
14356 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14357 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14358 //this.list.beginUpdate();
14359 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14360 this.list.alignTo(this.inputEl(), this.listAlign);
14361 this.list.alignTo(this.inputEl(), this.listAlign);
14362 //this.list.endUpdate();
14366 onEmptyResults : function(){
14368 if(this.tickable && this.editable){
14369 this.hasFocus = false;
14370 this.restrictHeight();
14378 * Returns true if the dropdown list is expanded, else false.
14380 isExpanded : function(){
14381 return this.list.isVisible();
14385 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14386 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14387 * @param {String} value The data value of the item to select
14388 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14389 * selected item if it is not currently in view (defaults to true)
14390 * @return {Boolean} True if the value matched an item in the list, else false
14392 selectByValue : function(v, scrollIntoView){
14393 if(v !== undefined && v !== null){
14394 var r = this.findRecord(this.valueField || this.displayField, v);
14396 this.select(this.store.indexOf(r), scrollIntoView);
14404 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14405 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14406 * @param {Number} index The zero-based index of the list item to select
14407 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14408 * selected item if it is not currently in view (defaults to true)
14410 select : function(index, scrollIntoView){
14411 this.selectedIndex = index;
14412 this.view.select(index);
14413 if(scrollIntoView !== false){
14414 var el = this.view.getNode(index);
14416 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14419 this.list.scrollChildIntoView(el, false);
14425 selectNext : function(){
14426 var ct = this.store.getCount();
14428 if(this.selectedIndex == -1){
14430 }else if(this.selectedIndex < ct-1){
14431 this.select(this.selectedIndex+1);
14437 selectPrev : function(){
14438 var ct = this.store.getCount();
14440 if(this.selectedIndex == -1){
14442 }else if(this.selectedIndex != 0){
14443 this.select(this.selectedIndex-1);
14449 onKeyUp : function(e){
14450 if(this.editable !== false && !e.isSpecialKey()){
14451 this.lastKey = e.getKey();
14452 this.dqTask.delay(this.queryDelay);
14457 validateBlur : function(){
14458 return !this.list || !this.list.isVisible();
14462 initQuery : function(){
14464 var v = this.getRawValue();
14466 if(this.tickable && this.editable){
14467 v = this.tickableInputEl().getValue();
14474 doForce : function(){
14475 if(this.inputEl().dom.value.length > 0){
14476 this.inputEl().dom.value =
14477 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14483 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14484 * query allowing the query action to be canceled if needed.
14485 * @param {String} query The SQL query to execute
14486 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14487 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14488 * saved in the current store (defaults to false)
14490 doQuery : function(q, forceAll){
14492 if(q === undefined || q === null){
14497 forceAll: forceAll,
14501 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14506 forceAll = qe.forceAll;
14507 if(forceAll === true || (q.length >= this.minChars)){
14509 this.hasQuery = true;
14511 if(this.lastQuery != q || this.alwaysQuery){
14512 this.lastQuery = q;
14513 if(this.mode == 'local'){
14514 this.selectedIndex = -1;
14516 this.store.clearFilter();
14519 if(this.specialFilter){
14520 this.fireEvent('specialfilter', this);
14525 this.store.filter(this.displayField, q);
14528 this.store.fireEvent("datachanged", this.store);
14535 this.store.baseParams[this.queryParam] = q;
14537 var options = {params : this.getParams(q)};
14540 options.add = true;
14541 options.params.start = this.page * this.pageSize;
14544 this.store.load(options);
14547 * this code will make the page width larger, at the beginning, the list not align correctly,
14548 * we should expand the list on onLoad
14549 * so command out it
14554 this.selectedIndex = -1;
14559 this.loadNext = false;
14563 getParams : function(q){
14565 //p[this.queryParam] = q;
14569 p.limit = this.pageSize;
14575 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14577 collapse : function(){
14578 if(!this.isExpanded()){
14584 this.hasFocus = false;
14588 this.cancelBtn.hide();
14589 this.trigger.show();
14592 this.tickableInputEl().dom.value = '';
14593 this.tickableInputEl().blur();
14598 Roo.get(document).un('mousedown', this.collapseIf, this);
14599 Roo.get(document).un('mousewheel', this.collapseIf, this);
14600 if (!this.editable) {
14601 Roo.get(document).un('keydown', this.listKeyPress, this);
14603 this.fireEvent('collapse', this);
14609 collapseIf : function(e){
14610 var in_combo = e.within(this.el);
14611 var in_list = e.within(this.list);
14612 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14614 if (in_combo || in_list || is_list) {
14615 //e.stopPropagation();
14620 this.onTickableFooterButtonClick(e, false, false);
14628 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14630 expand : function(){
14632 if(this.isExpanded() || !this.hasFocus){
14636 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14637 this.list.setWidth(lw);
14643 this.restrictHeight();
14647 this.tickItems = Roo.apply([], this.item);
14650 this.cancelBtn.show();
14651 this.trigger.hide();
14654 this.tickableInputEl().focus();
14659 Roo.get(document).on('mousedown', this.collapseIf, this);
14660 Roo.get(document).on('mousewheel', this.collapseIf, this);
14661 if (!this.editable) {
14662 Roo.get(document).on('keydown', this.listKeyPress, this);
14665 this.fireEvent('expand', this);
14669 // Implements the default empty TriggerField.onTriggerClick function
14670 onTriggerClick : function(e)
14672 Roo.log('trigger click');
14674 if(this.disabled || !this.triggerList){
14679 this.loadNext = false;
14681 if(this.isExpanded()){
14683 if (!this.blockFocus) {
14684 this.inputEl().focus();
14688 this.hasFocus = true;
14689 if(this.triggerAction == 'all') {
14690 this.doQuery(this.allQuery, true);
14692 this.doQuery(this.getRawValue());
14694 if (!this.blockFocus) {
14695 this.inputEl().focus();
14700 onTickableTriggerClick : function(e)
14707 this.loadNext = false;
14708 this.hasFocus = true;
14710 if(this.triggerAction == 'all') {
14711 this.doQuery(this.allQuery, true);
14713 this.doQuery(this.getRawValue());
14717 onSearchFieldClick : function(e)
14719 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14720 this.onTickableFooterButtonClick(e, false, false);
14724 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14729 this.loadNext = false;
14730 this.hasFocus = true;
14732 if(this.triggerAction == 'all') {
14733 this.doQuery(this.allQuery, true);
14735 this.doQuery(this.getRawValue());
14739 listKeyPress : function(e)
14741 //Roo.log('listkeypress');
14742 // scroll to first matching element based on key pres..
14743 if (e.isSpecialKey()) {
14746 var k = String.fromCharCode(e.getKey()).toUpperCase();
14749 var csel = this.view.getSelectedNodes();
14750 var cselitem = false;
14752 var ix = this.view.indexOf(csel[0]);
14753 cselitem = this.store.getAt(ix);
14754 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14760 this.store.each(function(v) {
14762 // start at existing selection.
14763 if (cselitem.id == v.id) {
14769 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14770 match = this.store.indexOf(v);
14776 if (match === false) {
14777 return true; // no more action?
14780 this.view.select(match);
14781 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14782 sn.scrollIntoView(sn.dom.parentNode, false);
14785 onViewScroll : function(e, t){
14787 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){
14791 this.hasQuery = true;
14793 this.loading = this.list.select('.loading', true).first();
14795 if(this.loading === null){
14796 this.list.createChild({
14798 cls: 'loading roo-select2-more-results roo-select2-active',
14799 html: 'Loading more results...'
14802 this.loading = this.list.select('.loading', true).first();
14804 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14806 this.loading.hide();
14809 this.loading.show();
14814 this.loadNext = true;
14816 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14821 addItem : function(o)
14823 var dv = ''; // display value
14825 if (this.displayField) {
14826 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14828 // this is an error condition!!!
14829 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14836 var choice = this.choices.createChild({
14838 cls: 'roo-select2-search-choice',
14847 cls: 'roo-select2-search-choice-close fa fa-times',
14852 }, this.searchField);
14854 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14856 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14864 this.inputEl().dom.value = '';
14869 onRemoveItem : function(e, _self, o)
14871 e.preventDefault();
14873 this.lastItem = Roo.apply([], this.item);
14875 var index = this.item.indexOf(o.data) * 1;
14878 Roo.log('not this item?!');
14882 this.item.splice(index, 1);
14887 this.fireEvent('remove', this, e);
14893 syncValue : function()
14895 if(!this.item.length){
14902 Roo.each(this.item, function(i){
14903 if(_this.valueField){
14904 value.push(i[_this.valueField]);
14911 this.value = value.join(',');
14913 if(this.hiddenField){
14914 this.hiddenField.dom.value = this.value;
14917 this.store.fireEvent("datachanged", this.store);
14922 clearItem : function()
14924 if(!this.multiple){
14930 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14938 if(this.tickable && !Roo.isTouch){
14939 this.view.refresh();
14943 inputEl: function ()
14945 if(Roo.isIOS && this.useNativeIOS){
14946 return this.el.select('select.roo-ios-select', true).first();
14949 if(Roo.isTouch && this.mobileTouchView){
14950 return this.el.select('input.form-control',true).first();
14954 return this.searchField;
14957 return this.el.select('input.form-control',true).first();
14960 onTickableFooterButtonClick : function(e, btn, el)
14962 e.preventDefault();
14964 this.lastItem = Roo.apply([], this.item);
14966 if(btn && btn.name == 'cancel'){
14967 this.tickItems = Roo.apply([], this.item);
14976 Roo.each(this.tickItems, function(o){
14984 validate : function()
14986 if(this.getVisibilityEl().hasClass('hidden')){
14990 var v = this.getRawValue();
14993 v = this.getValue();
14996 if(this.disabled || this.allowBlank || v.length){
15001 this.markInvalid();
15005 tickableInputEl : function()
15007 if(!this.tickable || !this.editable){
15008 return this.inputEl();
15011 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15015 getAutoCreateTouchView : function()
15020 cls: 'form-group' //input-group
15026 type : this.inputType,
15027 cls : 'form-control x-combo-noedit',
15028 autocomplete: 'new-password',
15029 placeholder : this.placeholder || '',
15034 input.name = this.name;
15038 input.cls += ' input-' + this.size;
15041 if (this.disabled) {
15042 input.disabled = true;
15053 inputblock.cls += ' input-group';
15055 inputblock.cn.unshift({
15057 cls : 'input-group-addon',
15062 if(this.removable && !this.multiple){
15063 inputblock.cls += ' roo-removable';
15065 inputblock.cn.push({
15068 cls : 'roo-combo-removable-btn close'
15072 if(this.hasFeedback && !this.allowBlank){
15074 inputblock.cls += ' has-feedback';
15076 inputblock.cn.push({
15078 cls: 'glyphicon form-control-feedback'
15085 inputblock.cls += (this.before) ? '' : ' input-group';
15087 inputblock.cn.push({
15089 cls : 'input-group-addon',
15100 cls: 'form-hidden-field'
15114 cls: 'form-hidden-field'
15118 cls: 'roo-select2-choices',
15122 cls: 'roo-select2-search-field',
15135 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15141 if(!this.multiple && this.showToggleBtn){
15148 if (this.caret != false) {
15151 cls: 'fa fa-' + this.caret
15158 cls : 'input-group-addon btn dropdown-toggle',
15163 cls: 'combobox-clear',
15177 combobox.cls += ' roo-select2-container-multi';
15180 var align = this.labelAlign || this.parentLabelAlign();
15182 if (align ==='left' && this.fieldLabel.length) {
15187 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15188 tooltip : 'This field is required'
15192 cls : 'control-label',
15193 html : this.fieldLabel
15204 var labelCfg = cfg.cn[1];
15205 var contentCfg = cfg.cn[2];
15208 if(this.indicatorpos == 'right'){
15213 cls : 'control-label',
15217 html : this.fieldLabel
15221 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15222 tooltip : 'This field is required'
15235 labelCfg = cfg.cn[0];
15236 contentCfg = cfg.cn[1];
15241 if(this.labelWidth > 12){
15242 labelCfg.style = "width: " + this.labelWidth + 'px';
15245 if(this.labelWidth < 13 && this.labelmd == 0){
15246 this.labelmd = this.labelWidth;
15249 if(this.labellg > 0){
15250 labelCfg.cls += ' col-lg-' + this.labellg;
15251 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15254 if(this.labelmd > 0){
15255 labelCfg.cls += ' col-md-' + this.labelmd;
15256 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15259 if(this.labelsm > 0){
15260 labelCfg.cls += ' col-sm-' + this.labelsm;
15261 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15264 if(this.labelxs > 0){
15265 labelCfg.cls += ' col-xs-' + this.labelxs;
15266 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15270 } else if ( this.fieldLabel.length) {
15274 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15275 tooltip : 'This field is required'
15279 cls : 'control-label',
15280 html : this.fieldLabel
15291 if(this.indicatorpos == 'right'){
15295 cls : 'control-label',
15296 html : this.fieldLabel,
15300 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15301 tooltip : 'This field is required'
15318 var settings = this;
15320 ['xs','sm','md','lg'].map(function(size){
15321 if (settings[size]) {
15322 cfg.cls += ' col-' + size + '-' + settings[size];
15329 initTouchView : function()
15331 this.renderTouchView();
15333 this.touchViewEl.on('scroll', function(){
15334 this.el.dom.scrollTop = 0;
15337 this.originalValue = this.getValue();
15339 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15341 this.inputEl().on("click", this.showTouchView, this);
15342 if (this.triggerEl) {
15343 this.triggerEl.on("click", this.showTouchView, this);
15347 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15348 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15350 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15352 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15353 this.store.on('load', this.onTouchViewLoad, this);
15354 this.store.on('loadexception', this.onTouchViewLoadException, this);
15356 if(this.hiddenName){
15358 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15360 this.hiddenField.dom.value =
15361 this.hiddenValue !== undefined ? this.hiddenValue :
15362 this.value !== undefined ? this.value : '';
15364 this.el.dom.removeAttribute('name');
15365 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15369 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15370 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15373 if(this.removable && !this.multiple){
15374 var close = this.closeTriggerEl();
15376 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15377 close.on('click', this.removeBtnClick, this, close);
15381 * fix the bug in Safari iOS8
15383 this.inputEl().on("focus", function(e){
15384 document.activeElement.blur();
15387 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15394 renderTouchView : function()
15396 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15397 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15399 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15400 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15402 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15403 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15404 this.touchViewBodyEl.setStyle('overflow', 'auto');
15406 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15407 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15409 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15410 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15414 showTouchView : function()
15420 this.touchViewHeaderEl.hide();
15422 if(this.modalTitle.length){
15423 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15424 this.touchViewHeaderEl.show();
15427 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15428 this.touchViewEl.show();
15430 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15432 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15433 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15435 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15437 if(this.modalTitle.length){
15438 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15441 this.touchViewBodyEl.setHeight(bodyHeight);
15445 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15447 this.touchViewEl.addClass('in');
15450 if(this._touchViewMask){
15451 Roo.get(document.body).addClass("x-body-masked");
15452 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15453 this._touchViewMask.setStyle('z-index', 10000);
15454 this._touchViewMask.addClass('show');
15457 this.doTouchViewQuery();
15461 hideTouchView : function()
15463 this.touchViewEl.removeClass('in');
15467 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15469 this.touchViewEl.setStyle('display', 'none');
15472 if(this._touchViewMask){
15473 this._touchViewMask.removeClass('show');
15474 Roo.get(document.body).removeClass("x-body-masked");
15478 setTouchViewValue : function()
15485 Roo.each(this.tickItems, function(o){
15490 this.hideTouchView();
15493 doTouchViewQuery : function()
15502 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15506 if(!this.alwaysQuery || this.mode == 'local'){
15507 this.onTouchViewLoad();
15514 onTouchViewBeforeLoad : function(combo,opts)
15520 onTouchViewLoad : function()
15522 if(this.store.getCount() < 1){
15523 this.onTouchViewEmptyResults();
15527 this.clearTouchView();
15529 var rawValue = this.getRawValue();
15531 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15533 this.tickItems = [];
15535 this.store.data.each(function(d, rowIndex){
15536 var row = this.touchViewListGroup.createChild(template);
15538 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15539 row.addClass(d.data.cls);
15542 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15545 html : d.data[this.displayField]
15548 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15549 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15552 row.removeClass('selected');
15553 if(!this.multiple && this.valueField &&
15554 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15557 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15558 row.addClass('selected');
15561 if(this.multiple && this.valueField &&
15562 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15566 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15567 this.tickItems.push(d.data);
15570 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15574 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15576 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15578 if(this.modalTitle.length){
15579 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15582 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15584 if(this.mobile_restrict_height && listHeight < bodyHeight){
15585 this.touchViewBodyEl.setHeight(listHeight);
15590 if(firstChecked && listHeight > bodyHeight){
15591 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15596 onTouchViewLoadException : function()
15598 this.hideTouchView();
15601 onTouchViewEmptyResults : function()
15603 this.clearTouchView();
15605 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15607 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15611 clearTouchView : function()
15613 this.touchViewListGroup.dom.innerHTML = '';
15616 onTouchViewClick : function(e, el, o)
15618 e.preventDefault();
15621 var rowIndex = o.rowIndex;
15623 var r = this.store.getAt(rowIndex);
15625 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15627 if(!this.multiple){
15628 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15629 c.dom.removeAttribute('checked');
15632 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15634 this.setFromData(r.data);
15636 var close = this.closeTriggerEl();
15642 this.hideTouchView();
15644 this.fireEvent('select', this, r, rowIndex);
15649 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15650 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15651 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15655 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15656 this.addItem(r.data);
15657 this.tickItems.push(r.data);
15661 getAutoCreateNativeIOS : function()
15664 cls: 'form-group' //input-group,
15669 cls : 'roo-ios-select'
15673 combobox.name = this.name;
15676 if (this.disabled) {
15677 combobox.disabled = true;
15680 var settings = this;
15682 ['xs','sm','md','lg'].map(function(size){
15683 if (settings[size]) {
15684 cfg.cls += ' col-' + size + '-' + settings[size];
15694 initIOSView : function()
15696 this.store.on('load', this.onIOSViewLoad, this);
15701 onIOSViewLoad : function()
15703 if(this.store.getCount() < 1){
15707 this.clearIOSView();
15709 if(this.allowBlank) {
15711 var default_text = '-- SELECT --';
15713 if(this.placeholder.length){
15714 default_text = this.placeholder;
15717 if(this.emptyTitle.length){
15718 default_text += ' - ' + this.emptyTitle + ' -';
15721 var opt = this.inputEl().createChild({
15724 html : default_text
15728 o[this.valueField] = 0;
15729 o[this.displayField] = default_text;
15731 this.ios_options.push({
15738 this.store.data.each(function(d, rowIndex){
15742 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15743 html = d.data[this.displayField];
15748 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15749 value = d.data[this.valueField];
15758 if(this.value == d.data[this.valueField]){
15759 option['selected'] = true;
15762 var opt = this.inputEl().createChild(option);
15764 this.ios_options.push({
15771 this.inputEl().on('change', function(){
15772 this.fireEvent('select', this);
15777 clearIOSView: function()
15779 this.inputEl().dom.innerHTML = '';
15781 this.ios_options = [];
15784 setIOSValue: function(v)
15788 if(!this.ios_options){
15792 Roo.each(this.ios_options, function(opts){
15794 opts.el.dom.removeAttribute('selected');
15796 if(opts.data[this.valueField] != v){
15800 opts.el.dom.setAttribute('selected', true);
15806 * @cfg {Boolean} grow
15810 * @cfg {Number} growMin
15814 * @cfg {Number} growMax
15823 Roo.apply(Roo.bootstrap.ComboBox, {
15827 cls: 'modal-header',
15849 cls: 'list-group-item',
15853 cls: 'roo-combobox-list-group-item-value'
15857 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15871 listItemCheckbox : {
15873 cls: 'list-group-item',
15877 cls: 'roo-combobox-list-group-item-value'
15881 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15897 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15902 cls: 'modal-footer',
15910 cls: 'col-xs-6 text-left',
15913 cls: 'btn btn-danger roo-touch-view-cancel',
15919 cls: 'col-xs-6 text-right',
15922 cls: 'btn btn-success roo-touch-view-ok',
15933 Roo.apply(Roo.bootstrap.ComboBox, {
15935 touchViewTemplate : {
15937 cls: 'modal fade roo-combobox-touch-view',
15941 cls: 'modal-dialog',
15942 style : 'position:fixed', // we have to fix position....
15946 cls: 'modal-content',
15948 Roo.bootstrap.ComboBox.header,
15949 Roo.bootstrap.ComboBox.body,
15950 Roo.bootstrap.ComboBox.footer
15959 * Ext JS Library 1.1.1
15960 * Copyright(c) 2006-2007, Ext JS, LLC.
15962 * Originally Released Under LGPL - original licence link has changed is not relivant.
15965 * <script type="text/javascript">
15970 * @extends Roo.util.Observable
15971 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15972 * This class also supports single and multi selection modes. <br>
15973 * Create a data model bound view:
15975 var store = new Roo.data.Store(...);
15977 var view = new Roo.View({
15979 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15981 singleSelect: true,
15982 selectedClass: "ydataview-selected",
15986 // listen for node click?
15987 view.on("click", function(vw, index, node, e){
15988 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15992 dataModel.load("foobar.xml");
15994 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15996 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15997 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15999 * Note: old style constructor is still suported (container, template, config)
16002 * Create a new View
16003 * @param {Object} config The config object
16006 Roo.View = function(config, depreciated_tpl, depreciated_config){
16008 this.parent = false;
16010 if (typeof(depreciated_tpl) == 'undefined') {
16011 // new way.. - universal constructor.
16012 Roo.apply(this, config);
16013 this.el = Roo.get(this.el);
16016 this.el = Roo.get(config);
16017 this.tpl = depreciated_tpl;
16018 Roo.apply(this, depreciated_config);
16020 this.wrapEl = this.el.wrap().wrap();
16021 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16024 if(typeof(this.tpl) == "string"){
16025 this.tpl = new Roo.Template(this.tpl);
16027 // support xtype ctors..
16028 this.tpl = new Roo.factory(this.tpl, Roo);
16032 this.tpl.compile();
16037 * @event beforeclick
16038 * Fires before a click is processed. Returns false to cancel the default action.
16039 * @param {Roo.View} this
16040 * @param {Number} index The index of the target node
16041 * @param {HTMLElement} node The target node
16042 * @param {Roo.EventObject} e The raw event object
16044 "beforeclick" : true,
16047 * Fires when a template node is clicked.
16048 * @param {Roo.View} this
16049 * @param {Number} index The index of the target node
16050 * @param {HTMLElement} node The target node
16051 * @param {Roo.EventObject} e The raw event object
16056 * Fires when a template node is double clicked.
16057 * @param {Roo.View} this
16058 * @param {Number} index The index of the target node
16059 * @param {HTMLElement} node The target node
16060 * @param {Roo.EventObject} e The raw event object
16064 * @event contextmenu
16065 * Fires when a template node is right clicked.
16066 * @param {Roo.View} this
16067 * @param {Number} index The index of the target node
16068 * @param {HTMLElement} node The target node
16069 * @param {Roo.EventObject} e The raw event object
16071 "contextmenu" : true,
16073 * @event selectionchange
16074 * Fires when the selected nodes change.
16075 * @param {Roo.View} this
16076 * @param {Array} selections Array of the selected nodes
16078 "selectionchange" : true,
16081 * @event beforeselect
16082 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16083 * @param {Roo.View} this
16084 * @param {HTMLElement} node The node to be selected
16085 * @param {Array} selections Array of currently selected nodes
16087 "beforeselect" : true,
16089 * @event preparedata
16090 * Fires on every row to render, to allow you to change the data.
16091 * @param {Roo.View} this
16092 * @param {Object} data to be rendered (change this)
16094 "preparedata" : true
16102 "click": this.onClick,
16103 "dblclick": this.onDblClick,
16104 "contextmenu": this.onContextMenu,
16108 this.selections = [];
16110 this.cmp = new Roo.CompositeElementLite([]);
16112 this.store = Roo.factory(this.store, Roo.data);
16113 this.setStore(this.store, true);
16116 if ( this.footer && this.footer.xtype) {
16118 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16120 this.footer.dataSource = this.store;
16121 this.footer.container = fctr;
16122 this.footer = Roo.factory(this.footer, Roo);
16123 fctr.insertFirst(this.el);
16125 // this is a bit insane - as the paging toolbar seems to detach the el..
16126 // dom.parentNode.parentNode.parentNode
16127 // they get detached?
16131 Roo.View.superclass.constructor.call(this);
16136 Roo.extend(Roo.View, Roo.util.Observable, {
16139 * @cfg {Roo.data.Store} store Data store to load data from.
16144 * @cfg {String|Roo.Element} el The container element.
16149 * @cfg {String|Roo.Template} tpl The template used by this View
16153 * @cfg {String} dataName the named area of the template to use as the data area
16154 * Works with domtemplates roo-name="name"
16158 * @cfg {String} selectedClass The css class to add to selected nodes
16160 selectedClass : "x-view-selected",
16162 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16167 * @cfg {String} text to display on mask (default Loading)
16171 * @cfg {Boolean} multiSelect Allow multiple selection
16173 multiSelect : false,
16175 * @cfg {Boolean} singleSelect Allow single selection
16177 singleSelect: false,
16180 * @cfg {Boolean} toggleSelect - selecting
16182 toggleSelect : false,
16185 * @cfg {Boolean} tickable - selecting
16190 * Returns the element this view is bound to.
16191 * @return {Roo.Element}
16193 getEl : function(){
16194 return this.wrapEl;
16200 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16202 refresh : function(){
16203 //Roo.log('refresh');
16206 // if we are using something like 'domtemplate', then
16207 // the what gets used is:
16208 // t.applySubtemplate(NAME, data, wrapping data..)
16209 // the outer template then get' applied with
16210 // the store 'extra data'
16211 // and the body get's added to the
16212 // roo-name="data" node?
16213 // <span class='roo-tpl-{name}'></span> ?????
16217 this.clearSelections();
16218 this.el.update("");
16220 var records = this.store.getRange();
16221 if(records.length < 1) {
16223 // is this valid?? = should it render a template??
16225 this.el.update(this.emptyText);
16229 if (this.dataName) {
16230 this.el.update(t.apply(this.store.meta)); //????
16231 el = this.el.child('.roo-tpl-' + this.dataName);
16234 for(var i = 0, len = records.length; i < len; i++){
16235 var data = this.prepareData(records[i].data, i, records[i]);
16236 this.fireEvent("preparedata", this, data, i, records[i]);
16238 var d = Roo.apply({}, data);
16241 Roo.apply(d, {'roo-id' : Roo.id()});
16245 Roo.each(this.parent.item, function(item){
16246 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16249 Roo.apply(d, {'roo-data-checked' : 'checked'});
16253 html[html.length] = Roo.util.Format.trim(
16255 t.applySubtemplate(this.dataName, d, this.store.meta) :
16262 el.update(html.join(""));
16263 this.nodes = el.dom.childNodes;
16264 this.updateIndexes(0);
16269 * Function to override to reformat the data that is sent to
16270 * the template for each node.
16271 * DEPRICATED - use the preparedata event handler.
16272 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16273 * a JSON object for an UpdateManager bound view).
16275 prepareData : function(data, index, record)
16277 this.fireEvent("preparedata", this, data, index, record);
16281 onUpdate : function(ds, record){
16282 // Roo.log('on update');
16283 this.clearSelections();
16284 var index = this.store.indexOf(record);
16285 var n = this.nodes[index];
16286 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16287 n.parentNode.removeChild(n);
16288 this.updateIndexes(index, index);
16294 onAdd : function(ds, records, index)
16296 //Roo.log(['on Add', ds, records, index] );
16297 this.clearSelections();
16298 if(this.nodes.length == 0){
16302 var n = this.nodes[index];
16303 for(var i = 0, len = records.length; i < len; i++){
16304 var d = this.prepareData(records[i].data, i, records[i]);
16306 this.tpl.insertBefore(n, d);
16309 this.tpl.append(this.el, d);
16312 this.updateIndexes(index);
16315 onRemove : function(ds, record, index){
16316 // Roo.log('onRemove');
16317 this.clearSelections();
16318 var el = this.dataName ?
16319 this.el.child('.roo-tpl-' + this.dataName) :
16322 el.dom.removeChild(this.nodes[index]);
16323 this.updateIndexes(index);
16327 * Refresh an individual node.
16328 * @param {Number} index
16330 refreshNode : function(index){
16331 this.onUpdate(this.store, this.store.getAt(index));
16334 updateIndexes : function(startIndex, endIndex){
16335 var ns = this.nodes;
16336 startIndex = startIndex || 0;
16337 endIndex = endIndex || ns.length - 1;
16338 for(var i = startIndex; i <= endIndex; i++){
16339 ns[i].nodeIndex = i;
16344 * Changes the data store this view uses and refresh the view.
16345 * @param {Store} store
16347 setStore : function(store, initial){
16348 if(!initial && this.store){
16349 this.store.un("datachanged", this.refresh);
16350 this.store.un("add", this.onAdd);
16351 this.store.un("remove", this.onRemove);
16352 this.store.un("update", this.onUpdate);
16353 this.store.un("clear", this.refresh);
16354 this.store.un("beforeload", this.onBeforeLoad);
16355 this.store.un("load", this.onLoad);
16356 this.store.un("loadexception", this.onLoad);
16360 store.on("datachanged", this.refresh, this);
16361 store.on("add", this.onAdd, this);
16362 store.on("remove", this.onRemove, this);
16363 store.on("update", this.onUpdate, this);
16364 store.on("clear", this.refresh, this);
16365 store.on("beforeload", this.onBeforeLoad, this);
16366 store.on("load", this.onLoad, this);
16367 store.on("loadexception", this.onLoad, this);
16375 * onbeforeLoad - masks the loading area.
16378 onBeforeLoad : function(store,opts)
16380 //Roo.log('onBeforeLoad');
16382 this.el.update("");
16384 this.el.mask(this.mask ? this.mask : "Loading" );
16386 onLoad : function ()
16393 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16394 * @param {HTMLElement} node
16395 * @return {HTMLElement} The template node
16397 findItemFromChild : function(node){
16398 var el = this.dataName ?
16399 this.el.child('.roo-tpl-' + this.dataName,true) :
16402 if(!node || node.parentNode == el){
16405 var p = node.parentNode;
16406 while(p && p != el){
16407 if(p.parentNode == el){
16416 onClick : function(e){
16417 var item = this.findItemFromChild(e.getTarget());
16419 var index = this.indexOf(item);
16420 if(this.onItemClick(item, index, e) !== false){
16421 this.fireEvent("click", this, index, item, e);
16424 this.clearSelections();
16429 onContextMenu : function(e){
16430 var item = this.findItemFromChild(e.getTarget());
16432 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16437 onDblClick : function(e){
16438 var item = this.findItemFromChild(e.getTarget());
16440 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16444 onItemClick : function(item, index, e)
16446 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16449 if (this.toggleSelect) {
16450 var m = this.isSelected(item) ? 'unselect' : 'select';
16453 _t[m](item, true, false);
16456 if(this.multiSelect || this.singleSelect){
16457 if(this.multiSelect && e.shiftKey && this.lastSelection){
16458 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16460 this.select(item, this.multiSelect && e.ctrlKey);
16461 this.lastSelection = item;
16464 if(!this.tickable){
16465 e.preventDefault();
16473 * Get the number of selected nodes.
16476 getSelectionCount : function(){
16477 return this.selections.length;
16481 * Get the currently selected nodes.
16482 * @return {Array} An array of HTMLElements
16484 getSelectedNodes : function(){
16485 return this.selections;
16489 * Get the indexes of the selected nodes.
16492 getSelectedIndexes : function(){
16493 var indexes = [], s = this.selections;
16494 for(var i = 0, len = s.length; i < len; i++){
16495 indexes.push(s[i].nodeIndex);
16501 * Clear all selections
16502 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16504 clearSelections : function(suppressEvent){
16505 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16506 this.cmp.elements = this.selections;
16507 this.cmp.removeClass(this.selectedClass);
16508 this.selections = [];
16509 if(!suppressEvent){
16510 this.fireEvent("selectionchange", this, this.selections);
16516 * Returns true if the passed node is selected
16517 * @param {HTMLElement/Number} node The node or node index
16518 * @return {Boolean}
16520 isSelected : function(node){
16521 var s = this.selections;
16525 node = this.getNode(node);
16526 return s.indexOf(node) !== -1;
16531 * @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
16532 * @param {Boolean} keepExisting (optional) true to keep existing selections
16533 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16535 select : function(nodeInfo, keepExisting, suppressEvent){
16536 if(nodeInfo instanceof Array){
16538 this.clearSelections(true);
16540 for(var i = 0, len = nodeInfo.length; i < len; i++){
16541 this.select(nodeInfo[i], true, true);
16545 var node = this.getNode(nodeInfo);
16546 if(!node || this.isSelected(node)){
16547 return; // already selected.
16550 this.clearSelections(true);
16553 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16554 Roo.fly(node).addClass(this.selectedClass);
16555 this.selections.push(node);
16556 if(!suppressEvent){
16557 this.fireEvent("selectionchange", this, this.selections);
16565 * @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
16566 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16567 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16569 unselect : function(nodeInfo, keepExisting, suppressEvent)
16571 if(nodeInfo instanceof Array){
16572 Roo.each(this.selections, function(s) {
16573 this.unselect(s, nodeInfo);
16577 var node = this.getNode(nodeInfo);
16578 if(!node || !this.isSelected(node)){
16579 //Roo.log("not selected");
16580 return; // not selected.
16584 Roo.each(this.selections, function(s) {
16586 Roo.fly(node).removeClass(this.selectedClass);
16593 this.selections= ns;
16594 this.fireEvent("selectionchange", this, this.selections);
16598 * Gets a template node.
16599 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16600 * @return {HTMLElement} The node or null if it wasn't found
16602 getNode : function(nodeInfo){
16603 if(typeof nodeInfo == "string"){
16604 return document.getElementById(nodeInfo);
16605 }else if(typeof nodeInfo == "number"){
16606 return this.nodes[nodeInfo];
16612 * Gets a range template nodes.
16613 * @param {Number} startIndex
16614 * @param {Number} endIndex
16615 * @return {Array} An array of nodes
16617 getNodes : function(start, end){
16618 var ns = this.nodes;
16619 start = start || 0;
16620 end = typeof end == "undefined" ? ns.length - 1 : end;
16623 for(var i = start; i <= end; i++){
16627 for(var i = start; i >= end; i--){
16635 * Finds the index of the passed node
16636 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16637 * @return {Number} The index of the node or -1
16639 indexOf : function(node){
16640 node = this.getNode(node);
16641 if(typeof node.nodeIndex == "number"){
16642 return node.nodeIndex;
16644 var ns = this.nodes;
16645 for(var i = 0, len = ns.length; i < len; i++){
16656 * based on jquery fullcalendar
16660 Roo.bootstrap = Roo.bootstrap || {};
16662 * @class Roo.bootstrap.Calendar
16663 * @extends Roo.bootstrap.Component
16664 * Bootstrap Calendar class
16665 * @cfg {Boolean} loadMask (true|false) default false
16666 * @cfg {Object} header generate the user specific header of the calendar, default false
16669 * Create a new Container
16670 * @param {Object} config The config object
16675 Roo.bootstrap.Calendar = function(config){
16676 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16680 * Fires when a date is selected
16681 * @param {DatePicker} this
16682 * @param {Date} date The selected date
16686 * @event monthchange
16687 * Fires when the displayed month changes
16688 * @param {DatePicker} this
16689 * @param {Date} date The selected month
16691 'monthchange': true,
16693 * @event evententer
16694 * Fires when mouse over an event
16695 * @param {Calendar} this
16696 * @param {event} Event
16698 'evententer': true,
16700 * @event eventleave
16701 * Fires when the mouse leaves an
16702 * @param {Calendar} this
16705 'eventleave': true,
16707 * @event eventclick
16708 * Fires when the mouse click an
16709 * @param {Calendar} this
16718 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16721 * @cfg {Number} startDay
16722 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16730 getAutoCreate : function(){
16733 var fc_button = function(name, corner, style, content ) {
16734 return Roo.apply({},{
16736 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16738 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16741 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16752 style : 'width:100%',
16759 cls : 'fc-header-left',
16761 fc_button('prev', 'left', 'arrow', '‹' ),
16762 fc_button('next', 'right', 'arrow', '›' ),
16763 { tag: 'span', cls: 'fc-header-space' },
16764 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16772 cls : 'fc-header-center',
16776 cls: 'fc-header-title',
16779 html : 'month / year'
16787 cls : 'fc-header-right',
16789 /* fc_button('month', 'left', '', 'month' ),
16790 fc_button('week', '', '', 'week' ),
16791 fc_button('day', 'right', '', 'day' )
16803 header = this.header;
16806 var cal_heads = function() {
16808 // fixme - handle this.
16810 for (var i =0; i < Date.dayNames.length; i++) {
16811 var d = Date.dayNames[i];
16814 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16815 html : d.substring(0,3)
16819 ret[0].cls += ' fc-first';
16820 ret[6].cls += ' fc-last';
16823 var cal_cell = function(n) {
16826 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16831 cls: 'fc-day-number',
16835 cls: 'fc-day-content',
16839 style: 'position: relative;' // height: 17px;
16851 var cal_rows = function() {
16854 for (var r = 0; r < 6; r++) {
16861 for (var i =0; i < Date.dayNames.length; i++) {
16862 var d = Date.dayNames[i];
16863 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16866 row.cn[0].cls+=' fc-first';
16867 row.cn[0].cn[0].style = 'min-height:90px';
16868 row.cn[6].cls+=' fc-last';
16872 ret[0].cls += ' fc-first';
16873 ret[4].cls += ' fc-prev-last';
16874 ret[5].cls += ' fc-last';
16881 cls: 'fc-border-separate',
16882 style : 'width:100%',
16890 cls : 'fc-first fc-last',
16908 cls : 'fc-content',
16909 style : "position: relative;",
16912 cls : 'fc-view fc-view-month fc-grid',
16913 style : 'position: relative',
16914 unselectable : 'on',
16917 cls : 'fc-event-container',
16918 style : 'position:absolute;z-index:8;top:0;left:0;'
16936 initEvents : function()
16939 throw "can not find store for calendar";
16945 style: "text-align:center",
16949 style: "background-color:white;width:50%;margin:250 auto",
16953 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16964 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16966 var size = this.el.select('.fc-content', true).first().getSize();
16967 this.maskEl.setSize(size.width, size.height);
16968 this.maskEl.enableDisplayMode("block");
16969 if(!this.loadMask){
16970 this.maskEl.hide();
16973 this.store = Roo.factory(this.store, Roo.data);
16974 this.store.on('load', this.onLoad, this);
16975 this.store.on('beforeload', this.onBeforeLoad, this);
16979 this.cells = this.el.select('.fc-day',true);
16980 //Roo.log(this.cells);
16981 this.textNodes = this.el.query('.fc-day-number');
16982 this.cells.addClassOnOver('fc-state-hover');
16984 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16985 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16986 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16987 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16989 this.on('monthchange', this.onMonthChange, this);
16991 this.update(new Date().clearTime());
16994 resize : function() {
16995 var sz = this.el.getSize();
16997 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16998 this.el.select('.fc-day-content div',true).setHeight(34);
17003 showPrevMonth : function(e){
17004 this.update(this.activeDate.add("mo", -1));
17006 showToday : function(e){
17007 this.update(new Date().clearTime());
17010 showNextMonth : function(e){
17011 this.update(this.activeDate.add("mo", 1));
17015 showPrevYear : function(){
17016 this.update(this.activeDate.add("y", -1));
17020 showNextYear : function(){
17021 this.update(this.activeDate.add("y", 1));
17026 update : function(date)
17028 var vd = this.activeDate;
17029 this.activeDate = date;
17030 // if(vd && this.el){
17031 // var t = date.getTime();
17032 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17033 // Roo.log('using add remove');
17035 // this.fireEvent('monthchange', this, date);
17037 // this.cells.removeClass("fc-state-highlight");
17038 // this.cells.each(function(c){
17039 // if(c.dateValue == t){
17040 // c.addClass("fc-state-highlight");
17041 // setTimeout(function(){
17042 // try{c.dom.firstChild.focus();}catch(e){}
17052 var days = date.getDaysInMonth();
17054 var firstOfMonth = date.getFirstDateOfMonth();
17055 var startingPos = firstOfMonth.getDay()-this.startDay;
17057 if(startingPos < this.startDay){
17061 var pm = date.add(Date.MONTH, -1);
17062 var prevStart = pm.getDaysInMonth()-startingPos;
17064 this.cells = this.el.select('.fc-day',true);
17065 this.textNodes = this.el.query('.fc-day-number');
17066 this.cells.addClassOnOver('fc-state-hover');
17068 var cells = this.cells.elements;
17069 var textEls = this.textNodes;
17071 Roo.each(cells, function(cell){
17072 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17075 days += startingPos;
17077 // convert everything to numbers so it's fast
17078 var day = 86400000;
17079 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17082 //Roo.log(prevStart);
17084 var today = new Date().clearTime().getTime();
17085 var sel = date.clearTime().getTime();
17086 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17087 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17088 var ddMatch = this.disabledDatesRE;
17089 var ddText = this.disabledDatesText;
17090 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17091 var ddaysText = this.disabledDaysText;
17092 var format = this.format;
17094 var setCellClass = function(cal, cell){
17098 //Roo.log('set Cell Class');
17100 var t = d.getTime();
17104 cell.dateValue = t;
17106 cell.className += " fc-today";
17107 cell.className += " fc-state-highlight";
17108 cell.title = cal.todayText;
17111 // disable highlight in other month..
17112 //cell.className += " fc-state-highlight";
17117 cell.className = " fc-state-disabled";
17118 cell.title = cal.minText;
17122 cell.className = " fc-state-disabled";
17123 cell.title = cal.maxText;
17127 if(ddays.indexOf(d.getDay()) != -1){
17128 cell.title = ddaysText;
17129 cell.className = " fc-state-disabled";
17132 if(ddMatch && format){
17133 var fvalue = d.dateFormat(format);
17134 if(ddMatch.test(fvalue)){
17135 cell.title = ddText.replace("%0", fvalue);
17136 cell.className = " fc-state-disabled";
17140 if (!cell.initialClassName) {
17141 cell.initialClassName = cell.dom.className;
17144 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17149 for(; i < startingPos; i++) {
17150 textEls[i].innerHTML = (++prevStart);
17151 d.setDate(d.getDate()+1);
17153 cells[i].className = "fc-past fc-other-month";
17154 setCellClass(this, cells[i]);
17159 for(; i < days; i++){
17160 intDay = i - startingPos + 1;
17161 textEls[i].innerHTML = (intDay);
17162 d.setDate(d.getDate()+1);
17164 cells[i].className = ''; // "x-date-active";
17165 setCellClass(this, cells[i]);
17169 for(; i < 42; i++) {
17170 textEls[i].innerHTML = (++extraDays);
17171 d.setDate(d.getDate()+1);
17173 cells[i].className = "fc-future fc-other-month";
17174 setCellClass(this, cells[i]);
17177 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17179 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17181 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17182 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17184 if(totalRows != 6){
17185 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17186 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17189 this.fireEvent('monthchange', this, date);
17193 if(!this.internalRender){
17194 var main = this.el.dom.firstChild;
17195 var w = main.offsetWidth;
17196 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17197 Roo.fly(main).setWidth(w);
17198 this.internalRender = true;
17199 // opera does not respect the auto grow header center column
17200 // then, after it gets a width opera refuses to recalculate
17201 // without a second pass
17202 if(Roo.isOpera && !this.secondPass){
17203 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17204 this.secondPass = true;
17205 this.update.defer(10, this, [date]);
17212 findCell : function(dt) {
17213 dt = dt.clearTime().getTime();
17215 this.cells.each(function(c){
17216 //Roo.log("check " +c.dateValue + '?=' + dt);
17217 if(c.dateValue == dt){
17227 findCells : function(ev) {
17228 var s = ev.start.clone().clearTime().getTime();
17230 var e= ev.end.clone().clearTime().getTime();
17233 this.cells.each(function(c){
17234 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17236 if(c.dateValue > e){
17239 if(c.dateValue < s){
17248 // findBestRow: function(cells)
17252 // for (var i =0 ; i < cells.length;i++) {
17253 // ret = Math.max(cells[i].rows || 0,ret);
17260 addItem : function(ev)
17262 // look for vertical location slot in
17263 var cells = this.findCells(ev);
17265 // ev.row = this.findBestRow(cells);
17267 // work out the location.
17271 for(var i =0; i < cells.length; i++) {
17273 cells[i].row = cells[0].row;
17276 cells[i].row = cells[i].row + 1;
17286 if (crow.start.getY() == cells[i].getY()) {
17288 crow.end = cells[i];
17305 cells[0].events.push(ev);
17307 this.calevents.push(ev);
17310 clearEvents: function() {
17312 if(!this.calevents){
17316 Roo.each(this.cells.elements, function(c){
17322 Roo.each(this.calevents, function(e) {
17323 Roo.each(e.els, function(el) {
17324 el.un('mouseenter' ,this.onEventEnter, this);
17325 el.un('mouseleave' ,this.onEventLeave, this);
17330 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17336 renderEvents: function()
17340 this.cells.each(function(c) {
17349 if(c.row != c.events.length){
17350 r = 4 - (4 - (c.row - c.events.length));
17353 c.events = ev.slice(0, r);
17354 c.more = ev.slice(r);
17356 if(c.more.length && c.more.length == 1){
17357 c.events.push(c.more.pop());
17360 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17364 this.cells.each(function(c) {
17366 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17369 for (var e = 0; e < c.events.length; e++){
17370 var ev = c.events[e];
17371 var rows = ev.rows;
17373 for(var i = 0; i < rows.length; i++) {
17375 // how many rows should it span..
17378 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17379 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17381 unselectable : "on",
17384 cls: 'fc-event-inner',
17388 // cls: 'fc-event-time',
17389 // html : cells.length > 1 ? '' : ev.time
17393 cls: 'fc-event-title',
17394 html : String.format('{0}', ev.title)
17401 cls: 'ui-resizable-handle ui-resizable-e',
17402 html : '  '
17409 cfg.cls += ' fc-event-start';
17411 if ((i+1) == rows.length) {
17412 cfg.cls += ' fc-event-end';
17415 var ctr = _this.el.select('.fc-event-container',true).first();
17416 var cg = ctr.createChild(cfg);
17418 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17419 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17421 var r = (c.more.length) ? 1 : 0;
17422 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17423 cg.setWidth(ebox.right - sbox.x -2);
17425 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17426 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17427 cg.on('click', _this.onEventClick, _this, ev);
17438 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17439 style : 'position: absolute',
17440 unselectable : "on",
17443 cls: 'fc-event-inner',
17447 cls: 'fc-event-title',
17455 cls: 'ui-resizable-handle ui-resizable-e',
17456 html : '  '
17462 var ctr = _this.el.select('.fc-event-container',true).first();
17463 var cg = ctr.createChild(cfg);
17465 var sbox = c.select('.fc-day-content',true).first().getBox();
17466 var ebox = c.select('.fc-day-content',true).first().getBox();
17468 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17469 cg.setWidth(ebox.right - sbox.x -2);
17471 cg.on('click', _this.onMoreEventClick, _this, c.more);
17481 onEventEnter: function (e, el,event,d) {
17482 this.fireEvent('evententer', this, el, event);
17485 onEventLeave: function (e, el,event,d) {
17486 this.fireEvent('eventleave', this, el, event);
17489 onEventClick: function (e, el,event,d) {
17490 this.fireEvent('eventclick', this, el, event);
17493 onMonthChange: function () {
17497 onMoreEventClick: function(e, el, more)
17501 this.calpopover.placement = 'right';
17502 this.calpopover.setTitle('More');
17504 this.calpopover.setContent('');
17506 var ctr = this.calpopover.el.select('.popover-content', true).first();
17508 Roo.each(more, function(m){
17510 cls : 'fc-event-hori fc-event-draggable',
17513 var cg = ctr.createChild(cfg);
17515 cg.on('click', _this.onEventClick, _this, m);
17518 this.calpopover.show(el);
17523 onLoad: function ()
17525 this.calevents = [];
17528 if(this.store.getCount() > 0){
17529 this.store.data.each(function(d){
17532 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17533 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17534 time : d.data.start_time,
17535 title : d.data.title,
17536 description : d.data.description,
17537 venue : d.data.venue
17542 this.renderEvents();
17544 if(this.calevents.length && this.loadMask){
17545 this.maskEl.hide();
17549 onBeforeLoad: function()
17551 this.clearEvents();
17553 this.maskEl.show();
17567 * @class Roo.bootstrap.Popover
17568 * @extends Roo.bootstrap.Component
17569 * Bootstrap Popover class
17570 * @cfg {String} html contents of the popover (or false to use children..)
17571 * @cfg {String} title of popover (or false to hide)
17572 * @cfg {String} placement how it is placed
17573 * @cfg {String} trigger click || hover (or false to trigger manually)
17574 * @cfg {String} over what (parent or false to trigger manually.)
17575 * @cfg {Number} delay - delay before showing
17578 * Create a new Popover
17579 * @param {Object} config The config object
17582 Roo.bootstrap.Popover = function(config){
17583 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17589 * After the popover show
17591 * @param {Roo.bootstrap.Popover} this
17596 * After the popover hide
17598 * @param {Roo.bootstrap.Popover} this
17604 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17606 title: 'Fill in a title',
17609 placement : 'right',
17610 trigger : 'hover', // hover
17616 can_build_overlaid : false,
17618 getChildContainer : function()
17620 return this.el.select('.popover-content',true).first();
17623 getAutoCreate : function(){
17626 cls : 'popover roo-dynamic',
17627 style: 'display:block',
17633 cls : 'popover-inner',
17637 cls: 'popover-title',
17641 cls : 'popover-content',
17652 setTitle: function(str)
17655 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17657 setContent: function(str)
17660 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17662 // as it get's added to the bottom of the page.
17663 onRender : function(ct, position)
17665 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17667 var cfg = Roo.apply({}, this.getAutoCreate());
17671 cfg.cls += ' ' + this.cls;
17674 cfg.style = this.style;
17676 //Roo.log("adding to ");
17677 this.el = Roo.get(document.body).createChild(cfg, position);
17678 // Roo.log(this.el);
17683 initEvents : function()
17685 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17686 this.el.enableDisplayMode('block');
17688 if (this.over === false) {
17691 if (this.triggers === false) {
17694 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17695 var triggers = this.trigger ? this.trigger.split(' ') : [];
17696 Roo.each(triggers, function(trigger) {
17698 if (trigger == 'click') {
17699 on_el.on('click', this.toggle, this);
17700 } else if (trigger != 'manual') {
17701 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17702 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17704 on_el.on(eventIn ,this.enter, this);
17705 on_el.on(eventOut, this.leave, this);
17716 toggle : function () {
17717 this.hoverState == 'in' ? this.leave() : this.enter();
17720 enter : function () {
17722 clearTimeout(this.timeout);
17724 this.hoverState = 'in';
17726 if (!this.delay || !this.delay.show) {
17731 this.timeout = setTimeout(function () {
17732 if (_t.hoverState == 'in') {
17735 }, this.delay.show)
17738 leave : function() {
17739 clearTimeout(this.timeout);
17741 this.hoverState = 'out';
17743 if (!this.delay || !this.delay.hide) {
17748 this.timeout = setTimeout(function () {
17749 if (_t.hoverState == 'out') {
17752 }, this.delay.hide)
17755 show : function (on_el)
17758 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17762 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17763 if (this.html !== false) {
17764 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17766 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17767 if (!this.title.length) {
17768 this.el.select('.popover-title',true).hide();
17771 var placement = typeof this.placement == 'function' ?
17772 this.placement.call(this, this.el, on_el) :
17775 var autoToken = /\s?auto?\s?/i;
17776 var autoPlace = autoToken.test(placement);
17778 placement = placement.replace(autoToken, '') || 'top';
17782 //this.el.setXY([0,0]);
17784 this.el.dom.style.display='block';
17785 this.el.addClass(placement);
17787 //this.el.appendTo(on_el);
17789 var p = this.getPosition();
17790 var box = this.el.getBox();
17795 var align = Roo.bootstrap.Popover.alignment[placement];
17798 this.el.alignTo(on_el, align[0],align[1]);
17799 //var arrow = this.el.select('.arrow',true).first();
17800 //arrow.set(align[2],
17802 this.el.addClass('in');
17805 if (this.el.hasClass('fade')) {
17809 this.hoverState = 'in';
17811 this.fireEvent('show', this);
17816 this.el.setXY([0,0]);
17817 this.el.removeClass('in');
17819 this.hoverState = null;
17821 this.fireEvent('hide', this);
17826 Roo.bootstrap.Popover.alignment = {
17827 'left' : ['r-l', [-10,0], 'right'],
17828 'right' : ['l-r', [10,0], 'left'],
17829 'bottom' : ['t-b', [0,10], 'top'],
17830 'top' : [ 'b-t', [0,-10], 'bottom']
17841 * @class Roo.bootstrap.Progress
17842 * @extends Roo.bootstrap.Component
17843 * Bootstrap Progress class
17844 * @cfg {Boolean} striped striped of the progress bar
17845 * @cfg {Boolean} active animated of the progress bar
17849 * Create a new Progress
17850 * @param {Object} config The config object
17853 Roo.bootstrap.Progress = function(config){
17854 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17857 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17862 getAutoCreate : function(){
17870 cfg.cls += ' progress-striped';
17874 cfg.cls += ' active';
17893 * @class Roo.bootstrap.ProgressBar
17894 * @extends Roo.bootstrap.Component
17895 * Bootstrap ProgressBar class
17896 * @cfg {Number} aria_valuenow aria-value now
17897 * @cfg {Number} aria_valuemin aria-value min
17898 * @cfg {Number} aria_valuemax aria-value max
17899 * @cfg {String} label label for the progress bar
17900 * @cfg {String} panel (success | info | warning | danger )
17901 * @cfg {String} role role of the progress bar
17902 * @cfg {String} sr_only text
17906 * Create a new ProgressBar
17907 * @param {Object} config The config object
17910 Roo.bootstrap.ProgressBar = function(config){
17911 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17914 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17918 aria_valuemax : 100,
17924 getAutoCreate : function()
17929 cls: 'progress-bar',
17930 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17942 cfg.role = this.role;
17945 if(this.aria_valuenow){
17946 cfg['aria-valuenow'] = this.aria_valuenow;
17949 if(this.aria_valuemin){
17950 cfg['aria-valuemin'] = this.aria_valuemin;
17953 if(this.aria_valuemax){
17954 cfg['aria-valuemax'] = this.aria_valuemax;
17957 if(this.label && !this.sr_only){
17958 cfg.html = this.label;
17962 cfg.cls += ' progress-bar-' + this.panel;
17968 update : function(aria_valuenow)
17970 this.aria_valuenow = aria_valuenow;
17972 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17987 * @class Roo.bootstrap.TabGroup
17988 * @extends Roo.bootstrap.Column
17989 * Bootstrap Column class
17990 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17991 * @cfg {Boolean} carousel true to make the group behave like a carousel
17992 * @cfg {Boolean} bullets show bullets for the panels
17993 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17994 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17995 * @cfg {Boolean} showarrow (true|false) show arrow default true
17998 * Create a new TabGroup
17999 * @param {Object} config The config object
18002 Roo.bootstrap.TabGroup = function(config){
18003 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18005 this.navId = Roo.id();
18008 Roo.bootstrap.TabGroup.register(this);
18012 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18015 transition : false,
18020 slideOnTouch : false,
18023 getAutoCreate : function()
18025 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18027 cfg.cls += ' tab-content';
18029 if (this.carousel) {
18030 cfg.cls += ' carousel slide';
18033 cls : 'carousel-inner',
18037 if(this.bullets && !Roo.isTouch){
18040 cls : 'carousel-bullets',
18044 if(this.bullets_cls){
18045 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18052 cfg.cn[0].cn.push(bullets);
18055 if(this.showarrow){
18056 cfg.cn[0].cn.push({
18058 class : 'carousel-arrow',
18062 class : 'carousel-prev',
18066 class : 'fa fa-chevron-left'
18072 class : 'carousel-next',
18076 class : 'fa fa-chevron-right'
18089 initEvents: function()
18091 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18092 // this.el.on("touchstart", this.onTouchStart, this);
18095 if(this.autoslide){
18098 this.slideFn = window.setInterval(function() {
18099 _this.showPanelNext();
18103 if(this.showarrow){
18104 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18105 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18111 // onTouchStart : function(e, el, o)
18113 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18117 // this.showPanelNext();
18121 getChildContainer : function()
18123 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18127 * register a Navigation item
18128 * @param {Roo.bootstrap.NavItem} the navitem to add
18130 register : function(item)
18132 this.tabs.push( item);
18133 item.navId = this.navId; // not really needed..
18138 getActivePanel : function()
18141 Roo.each(this.tabs, function(t) {
18151 getPanelByName : function(n)
18154 Roo.each(this.tabs, function(t) {
18155 if (t.tabId == n) {
18163 indexOfPanel : function(p)
18166 Roo.each(this.tabs, function(t,i) {
18167 if (t.tabId == p.tabId) {
18176 * show a specific panel
18177 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18178 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18180 showPanel : function (pan)
18182 if(this.transition || typeof(pan) == 'undefined'){
18183 Roo.log("waiting for the transitionend");
18187 if (typeof(pan) == 'number') {
18188 pan = this.tabs[pan];
18191 if (typeof(pan) == 'string') {
18192 pan = this.getPanelByName(pan);
18195 var cur = this.getActivePanel();
18198 Roo.log('pan or acitve pan is undefined');
18202 if (pan.tabId == this.getActivePanel().tabId) {
18206 if (false === cur.fireEvent('beforedeactivate')) {
18210 if(this.bullets > 0 && !Roo.isTouch){
18211 this.setActiveBullet(this.indexOfPanel(pan));
18214 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18216 this.transition = true;
18217 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18218 var lr = dir == 'next' ? 'left' : 'right';
18219 pan.el.addClass(dir); // or prev
18220 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18221 cur.el.addClass(lr); // or right
18222 pan.el.addClass(lr);
18225 cur.el.on('transitionend', function() {
18226 Roo.log("trans end?");
18228 pan.el.removeClass([lr,dir]);
18229 pan.setActive(true);
18231 cur.el.removeClass([lr]);
18232 cur.setActive(false);
18234 _this.transition = false;
18236 }, this, { single: true } );
18241 cur.setActive(false);
18242 pan.setActive(true);
18247 showPanelNext : function()
18249 var i = this.indexOfPanel(this.getActivePanel());
18251 if (i >= this.tabs.length - 1 && !this.autoslide) {
18255 if (i >= this.tabs.length - 1 && this.autoslide) {
18259 this.showPanel(this.tabs[i+1]);
18262 showPanelPrev : function()
18264 var i = this.indexOfPanel(this.getActivePanel());
18266 if (i < 1 && !this.autoslide) {
18270 if (i < 1 && this.autoslide) {
18271 i = this.tabs.length;
18274 this.showPanel(this.tabs[i-1]);
18278 addBullet: function()
18280 if(!this.bullets || Roo.isTouch){
18283 var ctr = this.el.select('.carousel-bullets',true).first();
18284 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18285 var bullet = ctr.createChild({
18286 cls : 'bullet bullet-' + i
18287 },ctr.dom.lastChild);
18292 bullet.on('click', (function(e, el, o, ii, t){
18294 e.preventDefault();
18296 this.showPanel(ii);
18298 if(this.autoslide && this.slideFn){
18299 clearInterval(this.slideFn);
18300 this.slideFn = window.setInterval(function() {
18301 _this.showPanelNext();
18305 }).createDelegate(this, [i, bullet], true));
18310 setActiveBullet : function(i)
18316 Roo.each(this.el.select('.bullet', true).elements, function(el){
18317 el.removeClass('selected');
18320 var bullet = this.el.select('.bullet-' + i, true).first();
18326 bullet.addClass('selected');
18337 Roo.apply(Roo.bootstrap.TabGroup, {
18341 * register a Navigation Group
18342 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18344 register : function(navgrp)
18346 this.groups[navgrp.navId] = navgrp;
18350 * fetch a Navigation Group based on the navigation ID
18351 * if one does not exist , it will get created.
18352 * @param {string} the navgroup to add
18353 * @returns {Roo.bootstrap.NavGroup} the navgroup
18355 get: function(navId) {
18356 if (typeof(this.groups[navId]) == 'undefined') {
18357 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18359 return this.groups[navId] ;
18374 * @class Roo.bootstrap.TabPanel
18375 * @extends Roo.bootstrap.Component
18376 * Bootstrap TabPanel class
18377 * @cfg {Boolean} active panel active
18378 * @cfg {String} html panel content
18379 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18380 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18381 * @cfg {String} href click to link..
18385 * Create a new TabPanel
18386 * @param {Object} config The config object
18389 Roo.bootstrap.TabPanel = function(config){
18390 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18394 * Fires when the active status changes
18395 * @param {Roo.bootstrap.TabPanel} this
18396 * @param {Boolean} state the new state
18401 * @event beforedeactivate
18402 * Fires before a tab is de-activated - can be used to do validation on a form.
18403 * @param {Roo.bootstrap.TabPanel} this
18404 * @return {Boolean} false if there is an error
18407 'beforedeactivate': true
18410 this.tabId = this.tabId || Roo.id();
18414 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18422 getAutoCreate : function(){
18425 // item is needed for carousel - not sure if it has any effect otherwise
18426 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18427 html: this.html || ''
18431 cfg.cls += ' active';
18435 cfg.tabId = this.tabId;
18442 initEvents: function()
18444 var p = this.parent();
18446 this.navId = this.navId || p.navId;
18448 if (typeof(this.navId) != 'undefined') {
18449 // not really needed.. but just in case.. parent should be a NavGroup.
18450 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18454 var i = tg.tabs.length - 1;
18456 if(this.active && tg.bullets > 0 && i < tg.bullets){
18457 tg.setActiveBullet(i);
18461 this.el.on('click', this.onClick, this);
18464 this.el.on("touchstart", this.onTouchStart, this);
18465 this.el.on("touchmove", this.onTouchMove, this);
18466 this.el.on("touchend", this.onTouchEnd, this);
18471 onRender : function(ct, position)
18473 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18476 setActive : function(state)
18478 Roo.log("panel - set active " + this.tabId + "=" + state);
18480 this.active = state;
18482 this.el.removeClass('active');
18484 } else if (!this.el.hasClass('active')) {
18485 this.el.addClass('active');
18488 this.fireEvent('changed', this, state);
18491 onClick : function(e)
18493 e.preventDefault();
18495 if(!this.href.length){
18499 window.location.href = this.href;
18508 onTouchStart : function(e)
18510 this.swiping = false;
18512 this.startX = e.browserEvent.touches[0].clientX;
18513 this.startY = e.browserEvent.touches[0].clientY;
18516 onTouchMove : function(e)
18518 this.swiping = true;
18520 this.endX = e.browserEvent.touches[0].clientX;
18521 this.endY = e.browserEvent.touches[0].clientY;
18524 onTouchEnd : function(e)
18531 var tabGroup = this.parent();
18533 if(this.endX > this.startX){ // swiping right
18534 tabGroup.showPanelPrev();
18538 if(this.startX > this.endX){ // swiping left
18539 tabGroup.showPanelNext();
18558 * @class Roo.bootstrap.DateField
18559 * @extends Roo.bootstrap.Input
18560 * Bootstrap DateField class
18561 * @cfg {Number} weekStart default 0
18562 * @cfg {String} viewMode default empty, (months|years)
18563 * @cfg {String} minViewMode default empty, (months|years)
18564 * @cfg {Number} startDate default -Infinity
18565 * @cfg {Number} endDate default Infinity
18566 * @cfg {Boolean} todayHighlight default false
18567 * @cfg {Boolean} todayBtn default false
18568 * @cfg {Boolean} calendarWeeks default false
18569 * @cfg {Object} daysOfWeekDisabled default empty
18570 * @cfg {Boolean} singleMode default false (true | false)
18572 * @cfg {Boolean} keyboardNavigation default true
18573 * @cfg {String} language default en
18576 * Create a new DateField
18577 * @param {Object} config The config object
18580 Roo.bootstrap.DateField = function(config){
18581 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18585 * Fires when this field show.
18586 * @param {Roo.bootstrap.DateField} this
18587 * @param {Mixed} date The date value
18592 * Fires when this field hide.
18593 * @param {Roo.bootstrap.DateField} this
18594 * @param {Mixed} date The date value
18599 * Fires when select a date.
18600 * @param {Roo.bootstrap.DateField} this
18601 * @param {Mixed} date The date value
18605 * @event beforeselect
18606 * Fires when before select a date.
18607 * @param {Roo.bootstrap.DateField} this
18608 * @param {Mixed} date The date value
18610 beforeselect : true
18614 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18617 * @cfg {String} format
18618 * The default date format string which can be overriden for localization support. The format must be
18619 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18623 * @cfg {String} altFormats
18624 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18625 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18627 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18635 todayHighlight : false,
18641 keyboardNavigation: true,
18643 calendarWeeks: false,
18645 startDate: -Infinity,
18649 daysOfWeekDisabled: [],
18653 singleMode : false,
18655 UTCDate: function()
18657 return new Date(Date.UTC.apply(Date, arguments));
18660 UTCToday: function()
18662 var today = new Date();
18663 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18666 getDate: function() {
18667 var d = this.getUTCDate();
18668 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18671 getUTCDate: function() {
18675 setDate: function(d) {
18676 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18679 setUTCDate: function(d) {
18681 this.setValue(this.formatDate(this.date));
18684 onRender: function(ct, position)
18687 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18689 this.language = this.language || 'en';
18690 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18691 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18693 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18694 this.format = this.format || 'm/d/y';
18695 this.isInline = false;
18696 this.isInput = true;
18697 this.component = this.el.select('.add-on', true).first() || false;
18698 this.component = (this.component && this.component.length === 0) ? false : this.component;
18699 this.hasInput = this.component && this.inputEl().length;
18701 if (typeof(this.minViewMode === 'string')) {
18702 switch (this.minViewMode) {
18704 this.minViewMode = 1;
18707 this.minViewMode = 2;
18710 this.minViewMode = 0;
18715 if (typeof(this.viewMode === 'string')) {
18716 switch (this.viewMode) {
18729 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18731 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18733 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18735 this.picker().on('mousedown', this.onMousedown, this);
18736 this.picker().on('click', this.onClick, this);
18738 this.picker().addClass('datepicker-dropdown');
18740 this.startViewMode = this.viewMode;
18742 if(this.singleMode){
18743 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18744 v.setVisibilityMode(Roo.Element.DISPLAY);
18748 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18749 v.setStyle('width', '189px');
18753 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18754 if(!this.calendarWeeks){
18759 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18760 v.attr('colspan', function(i, val){
18761 return parseInt(val) + 1;
18766 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18768 this.setStartDate(this.startDate);
18769 this.setEndDate(this.endDate);
18771 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18778 if(this.isInline) {
18783 picker : function()
18785 return this.pickerEl;
18786 // return this.el.select('.datepicker', true).first();
18789 fillDow: function()
18791 var dowCnt = this.weekStart;
18800 if(this.calendarWeeks){
18808 while (dowCnt < this.weekStart + 7) {
18812 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18816 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18819 fillMonths: function()
18822 var months = this.picker().select('>.datepicker-months td', true).first();
18824 months.dom.innerHTML = '';
18830 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18833 months.createChild(month);
18840 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;
18842 if (this.date < this.startDate) {
18843 this.viewDate = new Date(this.startDate);
18844 } else if (this.date > this.endDate) {
18845 this.viewDate = new Date(this.endDate);
18847 this.viewDate = new Date(this.date);
18855 var d = new Date(this.viewDate),
18856 year = d.getUTCFullYear(),
18857 month = d.getUTCMonth(),
18858 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18859 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18860 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18861 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18862 currentDate = this.date && this.date.valueOf(),
18863 today = this.UTCToday();
18865 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18867 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18869 // this.picker.select('>tfoot th.today').
18870 // .text(dates[this.language].today)
18871 // .toggle(this.todayBtn !== false);
18873 this.updateNavArrows();
18876 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18878 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18880 prevMonth.setUTCDate(day);
18882 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18884 var nextMonth = new Date(prevMonth);
18886 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18888 nextMonth = nextMonth.valueOf();
18890 var fillMonths = false;
18892 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18894 while(prevMonth.valueOf() <= nextMonth) {
18897 if (prevMonth.getUTCDay() === this.weekStart) {
18899 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18907 if(this.calendarWeeks){
18908 // ISO 8601: First week contains first thursday.
18909 // ISO also states week starts on Monday, but we can be more abstract here.
18911 // Start of current week: based on weekstart/current date
18912 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18913 // Thursday of this week
18914 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18915 // First Thursday of year, year from thursday
18916 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18917 // Calendar week: ms between thursdays, div ms per day, div 7 days
18918 calWeek = (th - yth) / 864e5 / 7 + 1;
18920 fillMonths.cn.push({
18928 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18930 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18933 if (this.todayHighlight &&
18934 prevMonth.getUTCFullYear() == today.getFullYear() &&
18935 prevMonth.getUTCMonth() == today.getMonth() &&
18936 prevMonth.getUTCDate() == today.getDate()) {
18937 clsName += ' today';
18940 if (currentDate && prevMonth.valueOf() === currentDate) {
18941 clsName += ' active';
18944 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18945 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18946 clsName += ' disabled';
18949 fillMonths.cn.push({
18951 cls: 'day ' + clsName,
18952 html: prevMonth.getDate()
18955 prevMonth.setDate(prevMonth.getDate()+1);
18958 var currentYear = this.date && this.date.getUTCFullYear();
18959 var currentMonth = this.date && this.date.getUTCMonth();
18961 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18963 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18964 v.removeClass('active');
18966 if(currentYear === year && k === currentMonth){
18967 v.addClass('active');
18970 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18971 v.addClass('disabled');
18977 year = parseInt(year/10, 10) * 10;
18979 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18981 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18984 for (var i = -1; i < 11; i++) {
18985 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18987 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18995 showMode: function(dir)
18998 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19001 Roo.each(this.picker().select('>div',true).elements, function(v){
19002 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19005 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19010 if(this.isInline) {
19014 this.picker().removeClass(['bottom', 'top']);
19016 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19018 * place to the top of element!
19022 this.picker().addClass('top');
19023 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19028 this.picker().addClass('bottom');
19030 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19033 parseDate : function(value)
19035 if(!value || value instanceof Date){
19038 var v = Date.parseDate(value, this.format);
19039 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19040 v = Date.parseDate(value, 'Y-m-d');
19042 if(!v && this.altFormats){
19043 if(!this.altFormatsArray){
19044 this.altFormatsArray = this.altFormats.split("|");
19046 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19047 v = Date.parseDate(value, this.altFormatsArray[i]);
19053 formatDate : function(date, fmt)
19055 return (!date || !(date instanceof Date)) ?
19056 date : date.dateFormat(fmt || this.format);
19059 onFocus : function()
19061 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19065 onBlur : function()
19067 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19069 var d = this.inputEl().getValue();
19076 showPopup : function()
19078 this.picker().show();
19082 this.fireEvent('showpopup', this, this.date);
19085 hidePopup : function()
19087 if(this.isInline) {
19090 this.picker().hide();
19091 this.viewMode = this.startViewMode;
19094 this.fireEvent('hidepopup', this, this.date);
19098 onMousedown: function(e)
19100 e.stopPropagation();
19101 e.preventDefault();
19106 Roo.bootstrap.DateField.superclass.keyup.call(this);
19110 setValue: function(v)
19112 if(this.fireEvent('beforeselect', this, v) !== false){
19113 var d = new Date(this.parseDate(v) ).clearTime();
19115 if(isNaN(d.getTime())){
19116 this.date = this.viewDate = '';
19117 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19121 v = this.formatDate(d);
19123 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19125 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19129 this.fireEvent('select', this, this.date);
19133 getValue: function()
19135 return this.formatDate(this.date);
19138 fireKey: function(e)
19140 if (!this.picker().isVisible()){
19141 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19147 var dateChanged = false,
19149 newDate, newViewDate;
19154 e.preventDefault();
19158 if (!this.keyboardNavigation) {
19161 dir = e.keyCode == 37 ? -1 : 1;
19164 newDate = this.moveYear(this.date, dir);
19165 newViewDate = this.moveYear(this.viewDate, dir);
19166 } else if (e.shiftKey){
19167 newDate = this.moveMonth(this.date, dir);
19168 newViewDate = this.moveMonth(this.viewDate, dir);
19170 newDate = new Date(this.date);
19171 newDate.setUTCDate(this.date.getUTCDate() + dir);
19172 newViewDate = new Date(this.viewDate);
19173 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19175 if (this.dateWithinRange(newDate)){
19176 this.date = newDate;
19177 this.viewDate = newViewDate;
19178 this.setValue(this.formatDate(this.date));
19180 e.preventDefault();
19181 dateChanged = true;
19186 if (!this.keyboardNavigation) {
19189 dir = e.keyCode == 38 ? -1 : 1;
19191 newDate = this.moveYear(this.date, dir);
19192 newViewDate = this.moveYear(this.viewDate, dir);
19193 } else if (e.shiftKey){
19194 newDate = this.moveMonth(this.date, dir);
19195 newViewDate = this.moveMonth(this.viewDate, dir);
19197 newDate = new Date(this.date);
19198 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19199 newViewDate = new Date(this.viewDate);
19200 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19202 if (this.dateWithinRange(newDate)){
19203 this.date = newDate;
19204 this.viewDate = newViewDate;
19205 this.setValue(this.formatDate(this.date));
19207 e.preventDefault();
19208 dateChanged = true;
19212 this.setValue(this.formatDate(this.date));
19214 e.preventDefault();
19217 this.setValue(this.formatDate(this.date));
19231 onClick: function(e)
19233 e.stopPropagation();
19234 e.preventDefault();
19236 var target = e.getTarget();
19238 if(target.nodeName.toLowerCase() === 'i'){
19239 target = Roo.get(target).dom.parentNode;
19242 var nodeName = target.nodeName;
19243 var className = target.className;
19244 var html = target.innerHTML;
19245 //Roo.log(nodeName);
19247 switch(nodeName.toLowerCase()) {
19249 switch(className) {
19255 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19256 switch(this.viewMode){
19258 this.viewDate = this.moveMonth(this.viewDate, dir);
19262 this.viewDate = this.moveYear(this.viewDate, dir);
19268 var date = new Date();
19269 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19271 this.setValue(this.formatDate(this.date));
19278 if (className.indexOf('disabled') < 0) {
19279 this.viewDate.setUTCDate(1);
19280 if (className.indexOf('month') > -1) {
19281 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19283 var year = parseInt(html, 10) || 0;
19284 this.viewDate.setUTCFullYear(year);
19288 if(this.singleMode){
19289 this.setValue(this.formatDate(this.viewDate));
19300 //Roo.log(className);
19301 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19302 var day = parseInt(html, 10) || 1;
19303 var year = this.viewDate.getUTCFullYear(),
19304 month = this.viewDate.getUTCMonth();
19306 if (className.indexOf('old') > -1) {
19313 } else if (className.indexOf('new') > -1) {
19321 //Roo.log([year,month,day]);
19322 this.date = this.UTCDate(year, month, day,0,0,0,0);
19323 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19325 //Roo.log(this.formatDate(this.date));
19326 this.setValue(this.formatDate(this.date));
19333 setStartDate: function(startDate)
19335 this.startDate = startDate || -Infinity;
19336 if (this.startDate !== -Infinity) {
19337 this.startDate = this.parseDate(this.startDate);
19340 this.updateNavArrows();
19343 setEndDate: function(endDate)
19345 this.endDate = endDate || Infinity;
19346 if (this.endDate !== Infinity) {
19347 this.endDate = this.parseDate(this.endDate);
19350 this.updateNavArrows();
19353 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19355 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19356 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19357 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19359 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19360 return parseInt(d, 10);
19363 this.updateNavArrows();
19366 updateNavArrows: function()
19368 if(this.singleMode){
19372 var d = new Date(this.viewDate),
19373 year = d.getUTCFullYear(),
19374 month = d.getUTCMonth();
19376 Roo.each(this.picker().select('.prev', true).elements, function(v){
19378 switch (this.viewMode) {
19381 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19387 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19394 Roo.each(this.picker().select('.next', true).elements, function(v){
19396 switch (this.viewMode) {
19399 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19405 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19413 moveMonth: function(date, dir)
19418 var new_date = new Date(date.valueOf()),
19419 day = new_date.getUTCDate(),
19420 month = new_date.getUTCMonth(),
19421 mag = Math.abs(dir),
19423 dir = dir > 0 ? 1 : -1;
19426 // If going back one month, make sure month is not current month
19427 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19429 return new_date.getUTCMonth() == month;
19431 // If going forward one month, make sure month is as expected
19432 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19434 return new_date.getUTCMonth() != new_month;
19436 new_month = month + dir;
19437 new_date.setUTCMonth(new_month);
19438 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19439 if (new_month < 0 || new_month > 11) {
19440 new_month = (new_month + 12) % 12;
19443 // For magnitudes >1, move one month at a time...
19444 for (var i=0; i<mag; i++) {
19445 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19446 new_date = this.moveMonth(new_date, dir);
19448 // ...then reset the day, keeping it in the new month
19449 new_month = new_date.getUTCMonth();
19450 new_date.setUTCDate(day);
19452 return new_month != new_date.getUTCMonth();
19455 // Common date-resetting loop -- if date is beyond end of month, make it
19458 new_date.setUTCDate(--day);
19459 new_date.setUTCMonth(new_month);
19464 moveYear: function(date, dir)
19466 return this.moveMonth(date, dir*12);
19469 dateWithinRange: function(date)
19471 return date >= this.startDate && date <= this.endDate;
19477 this.picker().remove();
19480 validateValue : function(value)
19482 if(this.getVisibilityEl().hasClass('hidden')){
19486 if(value.length < 1) {
19487 if(this.allowBlank){
19493 if(value.length < this.minLength){
19496 if(value.length > this.maxLength){
19500 var vt = Roo.form.VTypes;
19501 if(!vt[this.vtype](value, this)){
19505 if(typeof this.validator == "function"){
19506 var msg = this.validator(value);
19512 if(this.regex && !this.regex.test(value)){
19516 if(typeof(this.parseDate(value)) == 'undefined'){
19520 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19524 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19534 this.date = this.viewDate = '';
19536 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19541 Roo.apply(Roo.bootstrap.DateField, {
19552 html: '<i class="fa fa-arrow-left"/>'
19562 html: '<i class="fa fa-arrow-right"/>'
19604 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19605 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19606 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19607 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19608 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19621 navFnc: 'FullYear',
19626 navFnc: 'FullYear',
19631 Roo.apply(Roo.bootstrap.DateField, {
19635 cls: 'datepicker dropdown-menu roo-dynamic',
19639 cls: 'datepicker-days',
19643 cls: 'table-condensed',
19645 Roo.bootstrap.DateField.head,
19649 Roo.bootstrap.DateField.footer
19656 cls: 'datepicker-months',
19660 cls: 'table-condensed',
19662 Roo.bootstrap.DateField.head,
19663 Roo.bootstrap.DateField.content,
19664 Roo.bootstrap.DateField.footer
19671 cls: 'datepicker-years',
19675 cls: 'table-condensed',
19677 Roo.bootstrap.DateField.head,
19678 Roo.bootstrap.DateField.content,
19679 Roo.bootstrap.DateField.footer
19698 * @class Roo.bootstrap.TimeField
19699 * @extends Roo.bootstrap.Input
19700 * Bootstrap DateField class
19704 * Create a new TimeField
19705 * @param {Object} config The config object
19708 Roo.bootstrap.TimeField = function(config){
19709 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19713 * Fires when this field show.
19714 * @param {Roo.bootstrap.DateField} thisthis
19715 * @param {Mixed} date The date value
19720 * Fires when this field hide.
19721 * @param {Roo.bootstrap.DateField} this
19722 * @param {Mixed} date The date value
19727 * Fires when select a date.
19728 * @param {Roo.bootstrap.DateField} this
19729 * @param {Mixed} date The date value
19735 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19738 * @cfg {String} format
19739 * The default time format string which can be overriden for localization support. The format must be
19740 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19744 onRender: function(ct, position)
19747 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19749 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19751 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19753 this.pop = this.picker().select('>.datepicker-time',true).first();
19754 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19756 this.picker().on('mousedown', this.onMousedown, this);
19757 this.picker().on('click', this.onClick, this);
19759 this.picker().addClass('datepicker-dropdown');
19764 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19765 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19766 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19767 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19768 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19769 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19773 fireKey: function(e){
19774 if (!this.picker().isVisible()){
19775 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19781 e.preventDefault();
19789 this.onTogglePeriod();
19792 this.onIncrementMinutes();
19795 this.onDecrementMinutes();
19804 onClick: function(e) {
19805 e.stopPropagation();
19806 e.preventDefault();
19809 picker : function()
19811 return this.el.select('.datepicker', true).first();
19814 fillTime: function()
19816 var time = this.pop.select('tbody', true).first();
19818 time.dom.innerHTML = '';
19833 cls: 'hours-up glyphicon glyphicon-chevron-up'
19853 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19874 cls: 'timepicker-hour',
19889 cls: 'timepicker-minute',
19904 cls: 'btn btn-primary period',
19926 cls: 'hours-down glyphicon glyphicon-chevron-down'
19946 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19964 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19971 var hours = this.time.getHours();
19972 var minutes = this.time.getMinutes();
19985 hours = hours - 12;
19989 hours = '0' + hours;
19993 minutes = '0' + minutes;
19996 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19997 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19998 this.pop.select('button', true).first().dom.innerHTML = period;
20004 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20006 var cls = ['bottom'];
20008 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20015 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20020 this.picker().addClass(cls.join('-'));
20024 Roo.each(cls, function(c){
20026 _this.picker().setTop(_this.inputEl().getHeight());
20030 _this.picker().setTop(0 - _this.picker().getHeight());
20035 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20039 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20046 onFocus : function()
20048 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20052 onBlur : function()
20054 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20060 this.picker().show();
20065 this.fireEvent('show', this, this.date);
20070 this.picker().hide();
20073 this.fireEvent('hide', this, this.date);
20076 setTime : function()
20079 this.setValue(this.time.format(this.format));
20081 this.fireEvent('select', this, this.date);
20086 onMousedown: function(e){
20087 e.stopPropagation();
20088 e.preventDefault();
20091 onIncrementHours: function()
20093 Roo.log('onIncrementHours');
20094 this.time = this.time.add(Date.HOUR, 1);
20099 onDecrementHours: function()
20101 Roo.log('onDecrementHours');
20102 this.time = this.time.add(Date.HOUR, -1);
20106 onIncrementMinutes: function()
20108 Roo.log('onIncrementMinutes');
20109 this.time = this.time.add(Date.MINUTE, 1);
20113 onDecrementMinutes: function()
20115 Roo.log('onDecrementMinutes');
20116 this.time = this.time.add(Date.MINUTE, -1);
20120 onTogglePeriod: function()
20122 Roo.log('onTogglePeriod');
20123 this.time = this.time.add(Date.HOUR, 12);
20130 Roo.apply(Roo.bootstrap.TimeField, {
20160 cls: 'btn btn-info ok',
20172 Roo.apply(Roo.bootstrap.TimeField, {
20176 cls: 'datepicker dropdown-menu',
20180 cls: 'datepicker-time',
20184 cls: 'table-condensed',
20186 Roo.bootstrap.TimeField.content,
20187 Roo.bootstrap.TimeField.footer
20206 * @class Roo.bootstrap.MonthField
20207 * @extends Roo.bootstrap.Input
20208 * Bootstrap MonthField class
20210 * @cfg {String} language default en
20213 * Create a new MonthField
20214 * @param {Object} config The config object
20217 Roo.bootstrap.MonthField = function(config){
20218 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20223 * Fires when this field show.
20224 * @param {Roo.bootstrap.MonthField} this
20225 * @param {Mixed} date The date value
20230 * Fires when this field hide.
20231 * @param {Roo.bootstrap.MonthField} this
20232 * @param {Mixed} date The date value
20237 * Fires when select a date.
20238 * @param {Roo.bootstrap.MonthField} this
20239 * @param {String} oldvalue The old value
20240 * @param {String} newvalue The new value
20246 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20248 onRender: function(ct, position)
20251 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20253 this.language = this.language || 'en';
20254 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20255 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20257 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20258 this.isInline = false;
20259 this.isInput = true;
20260 this.component = this.el.select('.add-on', true).first() || false;
20261 this.component = (this.component && this.component.length === 0) ? false : this.component;
20262 this.hasInput = this.component && this.inputEL().length;
20264 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20266 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20268 this.picker().on('mousedown', this.onMousedown, this);
20269 this.picker().on('click', this.onClick, this);
20271 this.picker().addClass('datepicker-dropdown');
20273 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20274 v.setStyle('width', '189px');
20281 if(this.isInline) {
20287 setValue: function(v, suppressEvent)
20289 var o = this.getValue();
20291 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20295 if(suppressEvent !== true){
20296 this.fireEvent('select', this, o, v);
20301 getValue: function()
20306 onClick: function(e)
20308 e.stopPropagation();
20309 e.preventDefault();
20311 var target = e.getTarget();
20313 if(target.nodeName.toLowerCase() === 'i'){
20314 target = Roo.get(target).dom.parentNode;
20317 var nodeName = target.nodeName;
20318 var className = target.className;
20319 var html = target.innerHTML;
20321 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20325 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20327 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20333 picker : function()
20335 return this.pickerEl;
20338 fillMonths: function()
20341 var months = this.picker().select('>.datepicker-months td', true).first();
20343 months.dom.innerHTML = '';
20349 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20352 months.createChild(month);
20361 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20362 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20365 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20366 e.removeClass('active');
20368 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20369 e.addClass('active');
20376 if(this.isInline) {
20380 this.picker().removeClass(['bottom', 'top']);
20382 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20384 * place to the top of element!
20388 this.picker().addClass('top');
20389 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20394 this.picker().addClass('bottom');
20396 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20399 onFocus : function()
20401 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20405 onBlur : function()
20407 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20409 var d = this.inputEl().getValue();
20418 this.picker().show();
20419 this.picker().select('>.datepicker-months', true).first().show();
20423 this.fireEvent('show', this, this.date);
20428 if(this.isInline) {
20431 this.picker().hide();
20432 this.fireEvent('hide', this, this.date);
20436 onMousedown: function(e)
20438 e.stopPropagation();
20439 e.preventDefault();
20444 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20448 fireKey: function(e)
20450 if (!this.picker().isVisible()){
20451 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20462 e.preventDefault();
20466 dir = e.keyCode == 37 ? -1 : 1;
20468 this.vIndex = this.vIndex + dir;
20470 if(this.vIndex < 0){
20474 if(this.vIndex > 11){
20478 if(isNaN(this.vIndex)){
20482 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20488 dir = e.keyCode == 38 ? -1 : 1;
20490 this.vIndex = this.vIndex + dir * 4;
20492 if(this.vIndex < 0){
20496 if(this.vIndex > 11){
20500 if(isNaN(this.vIndex)){
20504 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20509 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20510 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20514 e.preventDefault();
20517 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20518 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20534 this.picker().remove();
20539 Roo.apply(Roo.bootstrap.MonthField, {
20558 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20559 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20564 Roo.apply(Roo.bootstrap.MonthField, {
20568 cls: 'datepicker dropdown-menu roo-dynamic',
20572 cls: 'datepicker-months',
20576 cls: 'table-condensed',
20578 Roo.bootstrap.DateField.content
20598 * @class Roo.bootstrap.CheckBox
20599 * @extends Roo.bootstrap.Input
20600 * Bootstrap CheckBox class
20602 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20603 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20604 * @cfg {String} boxLabel The text that appears beside the checkbox
20605 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20606 * @cfg {Boolean} checked initnal the element
20607 * @cfg {Boolean} inline inline the element (default false)
20608 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20609 * @cfg {String} tooltip label tooltip
20612 * Create a new CheckBox
20613 * @param {Object} config The config object
20616 Roo.bootstrap.CheckBox = function(config){
20617 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20622 * Fires when the element is checked or unchecked.
20623 * @param {Roo.bootstrap.CheckBox} this This input
20624 * @param {Boolean} checked The new checked value
20629 * Fires when the element is click.
20630 * @param {Roo.bootstrap.CheckBox} this This input
20637 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20639 inputType: 'checkbox',
20648 getAutoCreate : function()
20650 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20656 cfg.cls = 'form-group ' + this.inputType; //input-group
20659 cfg.cls += ' ' + this.inputType + '-inline';
20665 type : this.inputType,
20666 value : this.inputValue,
20667 cls : 'roo-' + this.inputType, //'form-box',
20668 placeholder : this.placeholder || ''
20672 if(this.inputType != 'radio'){
20676 cls : 'roo-hidden-value',
20677 value : this.checked ? this.inputValue : this.valueOff
20682 if (this.weight) { // Validity check?
20683 cfg.cls += " " + this.inputType + "-" + this.weight;
20686 if (this.disabled) {
20687 input.disabled=true;
20691 input.checked = this.checked;
20696 input.name = this.name;
20698 if(this.inputType != 'radio'){
20699 hidden.name = this.name;
20700 input.name = '_hidden_' + this.name;
20705 input.cls += ' input-' + this.size;
20710 ['xs','sm','md','lg'].map(function(size){
20711 if (settings[size]) {
20712 cfg.cls += ' col-' + size + '-' + settings[size];
20716 var inputblock = input;
20718 if (this.before || this.after) {
20721 cls : 'input-group',
20726 inputblock.cn.push({
20728 cls : 'input-group-addon',
20733 inputblock.cn.push(input);
20735 if(this.inputType != 'radio'){
20736 inputblock.cn.push(hidden);
20740 inputblock.cn.push({
20742 cls : 'input-group-addon',
20749 if (align ==='left' && this.fieldLabel.length) {
20750 // Roo.log("left and has label");
20755 cls : 'control-label',
20756 html : this.fieldLabel
20766 if(this.labelWidth > 12){
20767 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20770 if(this.labelWidth < 13 && this.labelmd == 0){
20771 this.labelmd = this.labelWidth;
20774 if(this.labellg > 0){
20775 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20776 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20779 if(this.labelmd > 0){
20780 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20781 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20784 if(this.labelsm > 0){
20785 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20786 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20789 if(this.labelxs > 0){
20790 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20791 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20794 } else if ( this.fieldLabel.length) {
20795 // Roo.log(" label");
20799 tag: this.boxLabel ? 'span' : 'label',
20801 cls: 'control-label box-input-label',
20802 //cls : 'input-group-addon',
20803 html : this.fieldLabel
20812 // Roo.log(" no label && no align");
20813 cfg.cn = [ inputblock ] ;
20819 var boxLabelCfg = {
20821 //'for': id, // box label is handled by onclick - so no for...
20823 html: this.boxLabel
20827 boxLabelCfg.tooltip = this.tooltip;
20830 cfg.cn.push(boxLabelCfg);
20833 if(this.inputType != 'radio'){
20834 cfg.cn.push(hidden);
20842 * return the real input element.
20844 inputEl: function ()
20846 return this.el.select('input.roo-' + this.inputType,true).first();
20848 hiddenEl: function ()
20850 return this.el.select('input.roo-hidden-value',true).first();
20853 labelEl: function()
20855 return this.el.select('label.control-label',true).first();
20857 /* depricated... */
20861 return this.labelEl();
20864 boxLabelEl: function()
20866 return this.el.select('label.box-label',true).first();
20869 initEvents : function()
20871 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20873 this.inputEl().on('click', this.onClick, this);
20875 if (this.boxLabel) {
20876 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20879 this.startValue = this.getValue();
20882 Roo.bootstrap.CheckBox.register(this);
20886 onClick : function(e)
20888 if(this.fireEvent('click', this, e) !== false){
20889 this.setChecked(!this.checked);
20894 setChecked : function(state,suppressEvent)
20896 this.startValue = this.getValue();
20898 if(this.inputType == 'radio'){
20900 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20901 e.dom.checked = false;
20904 this.inputEl().dom.checked = true;
20906 this.inputEl().dom.value = this.inputValue;
20908 if(suppressEvent !== true){
20909 this.fireEvent('check', this, true);
20917 this.checked = state;
20919 this.inputEl().dom.checked = state;
20922 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20924 if(suppressEvent !== true){
20925 this.fireEvent('check', this, state);
20931 getValue : function()
20933 if(this.inputType == 'radio'){
20934 return this.getGroupValue();
20937 return this.hiddenEl().dom.value;
20941 getGroupValue : function()
20943 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20947 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20950 setValue : function(v,suppressEvent)
20952 if(this.inputType == 'radio'){
20953 this.setGroupValue(v, suppressEvent);
20957 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20962 setGroupValue : function(v, suppressEvent)
20964 this.startValue = this.getValue();
20966 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20967 e.dom.checked = false;
20969 if(e.dom.value == v){
20970 e.dom.checked = true;
20974 if(suppressEvent !== true){
20975 this.fireEvent('check', this, true);
20983 validate : function()
20985 if(this.getVisibilityEl().hasClass('hidden')){
20991 (this.inputType == 'radio' && this.validateRadio()) ||
20992 (this.inputType == 'checkbox' && this.validateCheckbox())
20998 this.markInvalid();
21002 validateRadio : function()
21004 if(this.getVisibilityEl().hasClass('hidden')){
21008 if(this.allowBlank){
21014 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21015 if(!e.dom.checked){
21027 validateCheckbox : function()
21030 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21031 //return (this.getValue() == this.inputValue) ? true : false;
21034 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21042 for(var i in group){
21043 if(group[i].el.isVisible(true)){
21051 for(var i in group){
21056 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21063 * Mark this field as valid
21065 markValid : function()
21069 this.fireEvent('valid', this);
21071 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21074 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21081 if(this.inputType == 'radio'){
21082 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21083 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21084 e.findParent('.form-group', false, true).addClass(_this.validClass);
21091 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21092 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21096 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21102 for(var i in group){
21103 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21104 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21109 * Mark this field as invalid
21110 * @param {String} msg The validation message
21112 markInvalid : function(msg)
21114 if(this.allowBlank){
21120 this.fireEvent('invalid', this, msg);
21122 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21125 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21129 label.markInvalid();
21132 if(this.inputType == 'radio'){
21133 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21134 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21135 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21142 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21143 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21147 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21153 for(var i in group){
21154 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21155 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21160 clearInvalid : function()
21162 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21164 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21166 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21168 if (label && label.iconEl) {
21169 label.iconEl.removeClass(label.validClass);
21170 label.iconEl.removeClass(label.invalidClass);
21174 disable : function()
21176 if(this.inputType != 'radio'){
21177 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21184 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21185 _this.getActionEl().addClass(this.disabledClass);
21186 e.dom.disabled = true;
21190 this.disabled = true;
21191 this.fireEvent("disable", this);
21195 enable : function()
21197 if(this.inputType != 'radio'){
21198 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21205 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21206 _this.getActionEl().removeClass(this.disabledClass);
21207 e.dom.disabled = false;
21211 this.disabled = false;
21212 this.fireEvent("enable", this);
21216 setBoxLabel : function(v)
21221 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21227 Roo.apply(Roo.bootstrap.CheckBox, {
21232 * register a CheckBox Group
21233 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21235 register : function(checkbox)
21237 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21238 this.groups[checkbox.groupId] = {};
21241 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21245 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21249 * fetch a CheckBox Group based on the group ID
21250 * @param {string} the group ID
21251 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21253 get: function(groupId) {
21254 if (typeof(this.groups[groupId]) == 'undefined') {
21258 return this.groups[groupId] ;
21271 * @class Roo.bootstrap.Radio
21272 * @extends Roo.bootstrap.Component
21273 * Bootstrap Radio class
21274 * @cfg {String} boxLabel - the label associated
21275 * @cfg {String} value - the value of radio
21278 * Create a new Radio
21279 * @param {Object} config The config object
21281 Roo.bootstrap.Radio = function(config){
21282 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21286 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21292 getAutoCreate : function()
21296 cls : 'form-group radio',
21301 html : this.boxLabel
21309 initEvents : function()
21311 this.parent().register(this);
21313 this.el.on('click', this.onClick, this);
21317 onClick : function(e)
21319 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21320 this.setChecked(true);
21324 setChecked : function(state, suppressEvent)
21326 this.parent().setValue(this.value, suppressEvent);
21330 setBoxLabel : function(v)
21335 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21350 * @class Roo.bootstrap.SecurePass
21351 * @extends Roo.bootstrap.Input
21352 * Bootstrap SecurePass class
21356 * Create a new SecurePass
21357 * @param {Object} config The config object
21360 Roo.bootstrap.SecurePass = function (config) {
21361 // these go here, so the translation tool can replace them..
21363 PwdEmpty: "Please type a password, and then retype it to confirm.",
21364 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21365 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21366 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21367 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21368 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21369 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21370 TooWeak: "Your password is Too Weak."
21372 this.meterLabel = "Password strength:";
21373 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21374 this.meterClass = [
21375 "roo-password-meter-tooweak",
21376 "roo-password-meter-weak",
21377 "roo-password-meter-medium",
21378 "roo-password-meter-strong",
21379 "roo-password-meter-grey"
21384 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21387 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21389 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21391 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21392 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21393 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21394 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21395 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21396 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21397 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21407 * @cfg {String/Object} Label for the strength meter (defaults to
21408 * 'Password strength:')
21413 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21414 * ['Weak', 'Medium', 'Strong'])
21417 pwdStrengths: false,
21430 initEvents: function ()
21432 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21434 if (this.el.is('input[type=password]') && Roo.isSafari) {
21435 this.el.on('keydown', this.SafariOnKeyDown, this);
21438 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21441 onRender: function (ct, position)
21443 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21444 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21445 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21447 this.trigger.createChild({
21452 cls: 'roo-password-meter-grey col-xs-12',
21455 //width: this.meterWidth + 'px'
21459 cls: 'roo-password-meter-text'
21465 if (this.hideTrigger) {
21466 this.trigger.setDisplayed(false);
21468 this.setSize(this.width || '', this.height || '');
21471 onDestroy: function ()
21473 if (this.trigger) {
21474 this.trigger.removeAllListeners();
21475 this.trigger.remove();
21478 this.wrap.remove();
21480 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21483 checkStrength: function ()
21485 var pwd = this.inputEl().getValue();
21486 if (pwd == this._lastPwd) {
21491 if (this.ClientSideStrongPassword(pwd)) {
21493 } else if (this.ClientSideMediumPassword(pwd)) {
21495 } else if (this.ClientSideWeakPassword(pwd)) {
21501 Roo.log('strength1: ' + strength);
21503 //var pm = this.trigger.child('div/div/div').dom;
21504 var pm = this.trigger.child('div/div');
21505 pm.removeClass(this.meterClass);
21506 pm.addClass(this.meterClass[strength]);
21509 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21511 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21513 this._lastPwd = pwd;
21517 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21519 this._lastPwd = '';
21521 var pm = this.trigger.child('div/div');
21522 pm.removeClass(this.meterClass);
21523 pm.addClass('roo-password-meter-grey');
21526 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21529 this.inputEl().dom.type='password';
21532 validateValue: function (value)
21535 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21538 if (value.length == 0) {
21539 if (this.allowBlank) {
21540 this.clearInvalid();
21544 this.markInvalid(this.errors.PwdEmpty);
21545 this.errorMsg = this.errors.PwdEmpty;
21553 if ('[\x21-\x7e]*'.match(value)) {
21554 this.markInvalid(this.errors.PwdBadChar);
21555 this.errorMsg = this.errors.PwdBadChar;
21558 if (value.length < 6) {
21559 this.markInvalid(this.errors.PwdShort);
21560 this.errorMsg = this.errors.PwdShort;
21563 if (value.length > 16) {
21564 this.markInvalid(this.errors.PwdLong);
21565 this.errorMsg = this.errors.PwdLong;
21569 if (this.ClientSideStrongPassword(value)) {
21571 } else if (this.ClientSideMediumPassword(value)) {
21573 } else if (this.ClientSideWeakPassword(value)) {
21580 if (strength < 2) {
21581 //this.markInvalid(this.errors.TooWeak);
21582 this.errorMsg = this.errors.TooWeak;
21587 console.log('strength2: ' + strength);
21589 //var pm = this.trigger.child('div/div/div').dom;
21591 var pm = this.trigger.child('div/div');
21592 pm.removeClass(this.meterClass);
21593 pm.addClass(this.meterClass[strength]);
21595 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21597 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21599 this.errorMsg = '';
21603 CharacterSetChecks: function (type)
21606 this.fResult = false;
21609 isctype: function (character, type)
21612 case this.kCapitalLetter:
21613 if (character >= 'A' && character <= 'Z') {
21618 case this.kSmallLetter:
21619 if (character >= 'a' && character <= 'z') {
21625 if (character >= '0' && character <= '9') {
21630 case this.kPunctuation:
21631 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21642 IsLongEnough: function (pwd, size)
21644 return !(pwd == null || isNaN(size) || pwd.length < size);
21647 SpansEnoughCharacterSets: function (word, nb)
21649 if (!this.IsLongEnough(word, nb))
21654 var characterSetChecks = new Array(
21655 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21656 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21659 for (var index = 0; index < word.length; ++index) {
21660 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21661 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21662 characterSetChecks[nCharSet].fResult = true;
21669 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21670 if (characterSetChecks[nCharSet].fResult) {
21675 if (nCharSets < nb) {
21681 ClientSideStrongPassword: function (pwd)
21683 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21686 ClientSideMediumPassword: function (pwd)
21688 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21691 ClientSideWeakPassword: function (pwd)
21693 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21696 })//<script type="text/javascript">
21699 * Based Ext JS Library 1.1.1
21700 * Copyright(c) 2006-2007, Ext JS, LLC.
21706 * @class Roo.HtmlEditorCore
21707 * @extends Roo.Component
21708 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21710 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21713 Roo.HtmlEditorCore = function(config){
21716 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21721 * @event initialize
21722 * Fires when the editor is fully initialized (including the iframe)
21723 * @param {Roo.HtmlEditorCore} this
21728 * Fires when the editor is first receives the focus. Any insertion must wait
21729 * until after this event.
21730 * @param {Roo.HtmlEditorCore} this
21734 * @event beforesync
21735 * Fires before the textarea is updated with content from the editor iframe. Return false
21736 * to cancel the sync.
21737 * @param {Roo.HtmlEditorCore} this
21738 * @param {String} html
21742 * @event beforepush
21743 * Fires before the iframe editor is updated with content from the textarea. Return false
21744 * to cancel the push.
21745 * @param {Roo.HtmlEditorCore} this
21746 * @param {String} html
21751 * Fires when the textarea is updated with content from the editor iframe.
21752 * @param {Roo.HtmlEditorCore} this
21753 * @param {String} html
21758 * Fires when the iframe editor is updated with content from the textarea.
21759 * @param {Roo.HtmlEditorCore} this
21760 * @param {String} html
21765 * @event editorevent
21766 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21767 * @param {Roo.HtmlEditorCore} this
21773 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21775 // defaults : white / black...
21776 this.applyBlacklists();
21783 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21787 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21793 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21798 * @cfg {Number} height (in pixels)
21802 * @cfg {Number} width (in pixels)
21807 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21810 stylesheets: false,
21815 // private properties
21816 validationEvent : false,
21818 initialized : false,
21820 sourceEditMode : false,
21821 onFocus : Roo.emptyFn,
21823 hideMode:'offsets',
21827 // blacklist + whitelisted elements..
21834 * Protected method that will not generally be called directly. It
21835 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21836 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21838 getDocMarkup : function(){
21842 // inherit styels from page...??
21843 if (this.stylesheets === false) {
21845 Roo.get(document.head).select('style').each(function(node) {
21846 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21849 Roo.get(document.head).select('link').each(function(node) {
21850 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21853 } else if (!this.stylesheets.length) {
21855 st = '<style type="text/css">' +
21856 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21859 st = '<style type="text/css">' +
21864 st += '<style type="text/css">' +
21865 'IMG { cursor: pointer } ' +
21868 var cls = 'roo-htmleditor-body';
21870 if(this.bodyCls.length){
21871 cls += ' ' + this.bodyCls;
21874 return '<html><head>' + st +
21875 //<style type="text/css">' +
21876 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21878 ' </head><body class="' + cls + '"></body></html>';
21882 onRender : function(ct, position)
21885 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21886 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21889 this.el.dom.style.border = '0 none';
21890 this.el.dom.setAttribute('tabIndex', -1);
21891 this.el.addClass('x-hidden hide');
21895 if(Roo.isIE){ // fix IE 1px bogus margin
21896 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21900 this.frameId = Roo.id();
21904 var iframe = this.owner.wrap.createChild({
21906 cls: 'form-control', // bootstrap..
21908 name: this.frameId,
21909 frameBorder : 'no',
21910 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21915 this.iframe = iframe.dom;
21917 this.assignDocWin();
21919 this.doc.designMode = 'on';
21922 this.doc.write(this.getDocMarkup());
21926 var task = { // must defer to wait for browser to be ready
21928 //console.log("run task?" + this.doc.readyState);
21929 this.assignDocWin();
21930 if(this.doc.body || this.doc.readyState == 'complete'){
21932 this.doc.designMode="on";
21936 Roo.TaskMgr.stop(task);
21937 this.initEditor.defer(10, this);
21944 Roo.TaskMgr.start(task);
21949 onResize : function(w, h)
21951 Roo.log('resize: ' +w + ',' + h );
21952 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21956 if(typeof w == 'number'){
21958 this.iframe.style.width = w + 'px';
21960 if(typeof h == 'number'){
21962 this.iframe.style.height = h + 'px';
21964 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21971 * Toggles the editor between standard and source edit mode.
21972 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21974 toggleSourceEdit : function(sourceEditMode){
21976 this.sourceEditMode = sourceEditMode === true;
21978 if(this.sourceEditMode){
21980 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21983 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21984 //this.iframe.className = '';
21987 //this.setSize(this.owner.wrap.getSize());
21988 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21995 * Protected method that will not generally be called directly. If you need/want
21996 * custom HTML cleanup, this is the method you should override.
21997 * @param {String} html The HTML to be cleaned
21998 * return {String} The cleaned HTML
22000 cleanHtml : function(html){
22001 html = String(html);
22002 if(html.length > 5){
22003 if(Roo.isSafari){ // strip safari nonsense
22004 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22007 if(html == ' '){
22014 * HTML Editor -> Textarea
22015 * Protected method that will not generally be called directly. Syncs the contents
22016 * of the editor iframe with the textarea.
22018 syncValue : function(){
22019 if(this.initialized){
22020 var bd = (this.doc.body || this.doc.documentElement);
22021 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22022 var html = bd.innerHTML;
22024 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22025 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22027 html = '<div style="'+m[0]+'">' + html + '</div>';
22030 html = this.cleanHtml(html);
22031 // fix up the special chars.. normaly like back quotes in word...
22032 // however we do not want to do this with chinese..
22033 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22034 var cc = b.charCodeAt();
22036 (cc >= 0x4E00 && cc < 0xA000 ) ||
22037 (cc >= 0x3400 && cc < 0x4E00 ) ||
22038 (cc >= 0xf900 && cc < 0xfb00 )
22044 if(this.owner.fireEvent('beforesync', this, html) !== false){
22045 this.el.dom.value = html;
22046 this.owner.fireEvent('sync', this, html);
22052 * Protected method that will not generally be called directly. Pushes the value of the textarea
22053 * into the iframe editor.
22055 pushValue : function(){
22056 if(this.initialized){
22057 var v = this.el.dom.value.trim();
22059 // if(v.length < 1){
22063 if(this.owner.fireEvent('beforepush', this, v) !== false){
22064 var d = (this.doc.body || this.doc.documentElement);
22066 this.cleanUpPaste();
22067 this.el.dom.value = d.innerHTML;
22068 this.owner.fireEvent('push', this, v);
22074 deferFocus : function(){
22075 this.focus.defer(10, this);
22079 focus : function(){
22080 if(this.win && !this.sourceEditMode){
22087 assignDocWin: function()
22089 var iframe = this.iframe;
22092 this.doc = iframe.contentWindow.document;
22093 this.win = iframe.contentWindow;
22095 // if (!Roo.get(this.frameId)) {
22098 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22099 // this.win = Roo.get(this.frameId).dom.contentWindow;
22101 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22105 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22106 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22111 initEditor : function(){
22112 //console.log("INIT EDITOR");
22113 this.assignDocWin();
22117 this.doc.designMode="on";
22119 this.doc.write(this.getDocMarkup());
22122 var dbody = (this.doc.body || this.doc.documentElement);
22123 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22124 // this copies styles from the containing element into thsi one..
22125 // not sure why we need all of this..
22126 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22128 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22129 //ss['background-attachment'] = 'fixed'; // w3c
22130 dbody.bgProperties = 'fixed'; // ie
22131 //Roo.DomHelper.applyStyles(dbody, ss);
22132 Roo.EventManager.on(this.doc, {
22133 //'mousedown': this.onEditorEvent,
22134 'mouseup': this.onEditorEvent,
22135 'dblclick': this.onEditorEvent,
22136 'click': this.onEditorEvent,
22137 'keyup': this.onEditorEvent,
22142 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22144 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22145 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22147 this.initialized = true;
22149 this.owner.fireEvent('initialize', this);
22154 onDestroy : function(){
22160 //for (var i =0; i < this.toolbars.length;i++) {
22161 // // fixme - ask toolbars for heights?
22162 // this.toolbars[i].onDestroy();
22165 //this.wrap.dom.innerHTML = '';
22166 //this.wrap.remove();
22171 onFirstFocus : function(){
22173 this.assignDocWin();
22176 this.activated = true;
22179 if(Roo.isGecko){ // prevent silly gecko errors
22181 var s = this.win.getSelection();
22182 if(!s.focusNode || s.focusNode.nodeType != 3){
22183 var r = s.getRangeAt(0);
22184 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22189 this.execCmd('useCSS', true);
22190 this.execCmd('styleWithCSS', false);
22193 this.owner.fireEvent('activate', this);
22197 adjustFont: function(btn){
22198 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22199 //if(Roo.isSafari){ // safari
22202 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22203 if(Roo.isSafari){ // safari
22204 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22205 v = (v < 10) ? 10 : v;
22206 v = (v > 48) ? 48 : v;
22207 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22212 v = Math.max(1, v+adjust);
22214 this.execCmd('FontSize', v );
22217 onEditorEvent : function(e)
22219 this.owner.fireEvent('editorevent', this, e);
22220 // this.updateToolbar();
22221 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22224 insertTag : function(tg)
22226 // could be a bit smarter... -> wrap the current selected tRoo..
22227 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22229 range = this.createRange(this.getSelection());
22230 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22231 wrappingNode.appendChild(range.extractContents());
22232 range.insertNode(wrappingNode);
22239 this.execCmd("formatblock", tg);
22243 insertText : function(txt)
22247 var range = this.createRange();
22248 range.deleteContents();
22249 //alert(Sender.getAttribute('label'));
22251 range.insertNode(this.doc.createTextNode(txt));
22257 * Executes a Midas editor command on the editor document and performs necessary focus and
22258 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22259 * @param {String} cmd The Midas command
22260 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22262 relayCmd : function(cmd, value){
22264 this.execCmd(cmd, value);
22265 this.owner.fireEvent('editorevent', this);
22266 //this.updateToolbar();
22267 this.owner.deferFocus();
22271 * Executes a Midas editor command directly on the editor document.
22272 * For visual commands, you should use {@link #relayCmd} instead.
22273 * <b>This should only be called after the editor is initialized.</b>
22274 * @param {String} cmd The Midas command
22275 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22277 execCmd : function(cmd, value){
22278 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22285 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22287 * @param {String} text | dom node..
22289 insertAtCursor : function(text)
22292 if(!this.activated){
22298 var r = this.doc.selection.createRange();
22309 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22313 // from jquery ui (MIT licenced)
22315 var win = this.win;
22317 if (win.getSelection && win.getSelection().getRangeAt) {
22318 range = win.getSelection().getRangeAt(0);
22319 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22320 range.insertNode(node);
22321 } else if (win.document.selection && win.document.selection.createRange) {
22322 // no firefox support
22323 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22324 win.document.selection.createRange().pasteHTML(txt);
22326 // no firefox support
22327 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22328 this.execCmd('InsertHTML', txt);
22337 mozKeyPress : function(e){
22339 var c = e.getCharCode(), cmd;
22342 c = String.fromCharCode(c).toLowerCase();
22356 this.cleanUpPaste.defer(100, this);
22364 e.preventDefault();
22372 fixKeys : function(){ // load time branching for fastest keydown performance
22374 return function(e){
22375 var k = e.getKey(), r;
22378 r = this.doc.selection.createRange();
22381 r.pasteHTML('    ');
22388 r = this.doc.selection.createRange();
22390 var target = r.parentElement();
22391 if(!target || target.tagName.toLowerCase() != 'li'){
22393 r.pasteHTML('<br />');
22399 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22400 this.cleanUpPaste.defer(100, this);
22406 }else if(Roo.isOpera){
22407 return function(e){
22408 var k = e.getKey();
22412 this.execCmd('InsertHTML','    ');
22415 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22416 this.cleanUpPaste.defer(100, this);
22421 }else if(Roo.isSafari){
22422 return function(e){
22423 var k = e.getKey();
22427 this.execCmd('InsertText','\t');
22431 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22432 this.cleanUpPaste.defer(100, this);
22440 getAllAncestors: function()
22442 var p = this.getSelectedNode();
22445 a.push(p); // push blank onto stack..
22446 p = this.getParentElement();
22450 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22454 a.push(this.doc.body);
22458 lastSelNode : false,
22461 getSelection : function()
22463 this.assignDocWin();
22464 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22467 getSelectedNode: function()
22469 // this may only work on Gecko!!!
22471 // should we cache this!!!!
22476 var range = this.createRange(this.getSelection()).cloneRange();
22479 var parent = range.parentElement();
22481 var testRange = range.duplicate();
22482 testRange.moveToElementText(parent);
22483 if (testRange.inRange(range)) {
22486 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22489 parent = parent.parentElement;
22494 // is ancestor a text element.
22495 var ac = range.commonAncestorContainer;
22496 if (ac.nodeType == 3) {
22497 ac = ac.parentNode;
22500 var ar = ac.childNodes;
22503 var other_nodes = [];
22504 var has_other_nodes = false;
22505 for (var i=0;i<ar.length;i++) {
22506 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22509 // fullly contained node.
22511 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22516 // probably selected..
22517 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22518 other_nodes.push(ar[i]);
22522 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22527 has_other_nodes = true;
22529 if (!nodes.length && other_nodes.length) {
22530 nodes= other_nodes;
22532 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22538 createRange: function(sel)
22540 // this has strange effects when using with
22541 // top toolbar - not sure if it's a great idea.
22542 //this.editor.contentWindow.focus();
22543 if (typeof sel != "undefined") {
22545 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22547 return this.doc.createRange();
22550 return this.doc.createRange();
22553 getParentElement: function()
22556 this.assignDocWin();
22557 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22559 var range = this.createRange(sel);
22562 var p = range.commonAncestorContainer;
22563 while (p.nodeType == 3) { // text node
22574 * Range intersection.. the hard stuff...
22578 * [ -- selected range --- ]
22582 * if end is before start or hits it. fail.
22583 * if start is after end or hits it fail.
22585 * if either hits (but other is outside. - then it's not
22591 // @see http://www.thismuchiknow.co.uk/?p=64.
22592 rangeIntersectsNode : function(range, node)
22594 var nodeRange = node.ownerDocument.createRange();
22596 nodeRange.selectNode(node);
22598 nodeRange.selectNodeContents(node);
22601 var rangeStartRange = range.cloneRange();
22602 rangeStartRange.collapse(true);
22604 var rangeEndRange = range.cloneRange();
22605 rangeEndRange.collapse(false);
22607 var nodeStartRange = nodeRange.cloneRange();
22608 nodeStartRange.collapse(true);
22610 var nodeEndRange = nodeRange.cloneRange();
22611 nodeEndRange.collapse(false);
22613 return rangeStartRange.compareBoundaryPoints(
22614 Range.START_TO_START, nodeEndRange) == -1 &&
22615 rangeEndRange.compareBoundaryPoints(
22616 Range.START_TO_START, nodeStartRange) == 1;
22620 rangeCompareNode : function(range, node)
22622 var nodeRange = node.ownerDocument.createRange();
22624 nodeRange.selectNode(node);
22626 nodeRange.selectNodeContents(node);
22630 range.collapse(true);
22632 nodeRange.collapse(true);
22634 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22635 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22637 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22639 var nodeIsBefore = ss == 1;
22640 var nodeIsAfter = ee == -1;
22642 if (nodeIsBefore && nodeIsAfter) {
22645 if (!nodeIsBefore && nodeIsAfter) {
22646 return 1; //right trailed.
22649 if (nodeIsBefore && !nodeIsAfter) {
22650 return 2; // left trailed.
22656 // private? - in a new class?
22657 cleanUpPaste : function()
22659 // cleans up the whole document..
22660 Roo.log('cleanuppaste');
22662 this.cleanUpChildren(this.doc.body);
22663 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22664 if (clean != this.doc.body.innerHTML) {
22665 this.doc.body.innerHTML = clean;
22670 cleanWordChars : function(input) {// change the chars to hex code
22671 var he = Roo.HtmlEditorCore;
22673 var output = input;
22674 Roo.each(he.swapCodes, function(sw) {
22675 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22677 output = output.replace(swapper, sw[1]);
22684 cleanUpChildren : function (n)
22686 if (!n.childNodes.length) {
22689 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22690 this.cleanUpChild(n.childNodes[i]);
22697 cleanUpChild : function (node)
22700 //console.log(node);
22701 if (node.nodeName == "#text") {
22702 // clean up silly Windows -- stuff?
22705 if (node.nodeName == "#comment") {
22706 node.parentNode.removeChild(node);
22707 // clean up silly Windows -- stuff?
22710 var lcname = node.tagName.toLowerCase();
22711 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22712 // whitelist of tags..
22714 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22716 node.parentNode.removeChild(node);
22721 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22723 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22724 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22726 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22727 // remove_keep_children = true;
22730 if (remove_keep_children) {
22731 this.cleanUpChildren(node);
22732 // inserts everything just before this node...
22733 while (node.childNodes.length) {
22734 var cn = node.childNodes[0];
22735 node.removeChild(cn);
22736 node.parentNode.insertBefore(cn, node);
22738 node.parentNode.removeChild(node);
22742 if (!node.attributes || !node.attributes.length) {
22743 this.cleanUpChildren(node);
22747 function cleanAttr(n,v)
22750 if (v.match(/^\./) || v.match(/^\//)) {
22753 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22756 if (v.match(/^#/)) {
22759 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22760 node.removeAttribute(n);
22764 var cwhite = this.cwhite;
22765 var cblack = this.cblack;
22767 function cleanStyle(n,v)
22769 if (v.match(/expression/)) { //XSS?? should we even bother..
22770 node.removeAttribute(n);
22774 var parts = v.split(/;/);
22777 Roo.each(parts, function(p) {
22778 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22782 var l = p.split(':').shift().replace(/\s+/g,'');
22783 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22785 if ( cwhite.length && cblack.indexOf(l) > -1) {
22786 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22787 //node.removeAttribute(n);
22791 // only allow 'c whitelisted system attributes'
22792 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22793 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22794 //node.removeAttribute(n);
22804 if (clean.length) {
22805 node.setAttribute(n, clean.join(';'));
22807 node.removeAttribute(n);
22813 for (var i = node.attributes.length-1; i > -1 ; i--) {
22814 var a = node.attributes[i];
22817 if (a.name.toLowerCase().substr(0,2)=='on') {
22818 node.removeAttribute(a.name);
22821 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22822 node.removeAttribute(a.name);
22825 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22826 cleanAttr(a.name,a.value); // fixme..
22829 if (a.name == 'style') {
22830 cleanStyle(a.name,a.value);
22833 /// clean up MS crap..
22834 // tecnically this should be a list of valid class'es..
22837 if (a.name == 'class') {
22838 if (a.value.match(/^Mso/)) {
22839 node.className = '';
22842 if (a.value.match(/^body$/)) {
22843 node.className = '';
22854 this.cleanUpChildren(node);
22860 * Clean up MS wordisms...
22862 cleanWord : function(node)
22867 this.cleanWord(this.doc.body);
22870 if (node.nodeName == "#text") {
22871 // clean up silly Windows -- stuff?
22874 if (node.nodeName == "#comment") {
22875 node.parentNode.removeChild(node);
22876 // clean up silly Windows -- stuff?
22880 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22881 node.parentNode.removeChild(node);
22885 // remove - but keep children..
22886 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22887 while (node.childNodes.length) {
22888 var cn = node.childNodes[0];
22889 node.removeChild(cn);
22890 node.parentNode.insertBefore(cn, node);
22892 node.parentNode.removeChild(node);
22893 this.iterateChildren(node, this.cleanWord);
22897 if (node.className.length) {
22899 var cn = node.className.split(/\W+/);
22901 Roo.each(cn, function(cls) {
22902 if (cls.match(/Mso[a-zA-Z]+/)) {
22907 node.className = cna.length ? cna.join(' ') : '';
22909 node.removeAttribute("class");
22913 if (node.hasAttribute("lang")) {
22914 node.removeAttribute("lang");
22917 if (node.hasAttribute("style")) {
22919 var styles = node.getAttribute("style").split(";");
22921 Roo.each(styles, function(s) {
22922 if (!s.match(/:/)) {
22925 var kv = s.split(":");
22926 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22929 // what ever is left... we allow.
22932 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22933 if (!nstyle.length) {
22934 node.removeAttribute('style');
22937 this.iterateChildren(node, this.cleanWord);
22943 * iterateChildren of a Node, calling fn each time, using this as the scole..
22944 * @param {DomNode} node node to iterate children of.
22945 * @param {Function} fn method of this class to call on each item.
22947 iterateChildren : function(node, fn)
22949 if (!node.childNodes.length) {
22952 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22953 fn.call(this, node.childNodes[i])
22959 * cleanTableWidths.
22961 * Quite often pasting from word etc.. results in tables with column and widths.
22962 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22965 cleanTableWidths : function(node)
22970 this.cleanTableWidths(this.doc.body);
22975 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22978 Roo.log(node.tagName);
22979 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22980 this.iterateChildren(node, this.cleanTableWidths);
22983 if (node.hasAttribute('width')) {
22984 node.removeAttribute('width');
22988 if (node.hasAttribute("style")) {
22991 var styles = node.getAttribute("style").split(";");
22993 Roo.each(styles, function(s) {
22994 if (!s.match(/:/)) {
22997 var kv = s.split(":");
22998 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23001 // what ever is left... we allow.
23004 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23005 if (!nstyle.length) {
23006 node.removeAttribute('style');
23010 this.iterateChildren(node, this.cleanTableWidths);
23018 domToHTML : function(currentElement, depth, nopadtext) {
23020 depth = depth || 0;
23021 nopadtext = nopadtext || false;
23023 if (!currentElement) {
23024 return this.domToHTML(this.doc.body);
23027 //Roo.log(currentElement);
23029 var allText = false;
23030 var nodeName = currentElement.nodeName;
23031 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23033 if (nodeName == '#text') {
23035 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23040 if (nodeName != 'BODY') {
23043 // Prints the node tagName, such as <A>, <IMG>, etc
23046 for(i = 0; i < currentElement.attributes.length;i++) {
23048 var aname = currentElement.attributes.item(i).name;
23049 if (!currentElement.attributes.item(i).value.length) {
23052 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23055 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23064 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23067 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23072 // Traverse the tree
23074 var currentElementChild = currentElement.childNodes.item(i);
23075 var allText = true;
23076 var innerHTML = '';
23078 while (currentElementChild) {
23079 // Formatting code (indent the tree so it looks nice on the screen)
23080 var nopad = nopadtext;
23081 if (lastnode == 'SPAN') {
23085 if (currentElementChild.nodeName == '#text') {
23086 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23087 toadd = nopadtext ? toadd : toadd.trim();
23088 if (!nopad && toadd.length > 80) {
23089 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23091 innerHTML += toadd;
23094 currentElementChild = currentElement.childNodes.item(i);
23100 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23102 // Recursively traverse the tree structure of the child node
23103 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23104 lastnode = currentElementChild.nodeName;
23106 currentElementChild=currentElement.childNodes.item(i);
23112 // The remaining code is mostly for formatting the tree
23113 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23118 ret+= "</"+tagName+">";
23124 applyBlacklists : function()
23126 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23127 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23131 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23132 if (b.indexOf(tag) > -1) {
23135 this.white.push(tag);
23139 Roo.each(w, function(tag) {
23140 if (b.indexOf(tag) > -1) {
23143 if (this.white.indexOf(tag) > -1) {
23146 this.white.push(tag);
23151 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23152 if (w.indexOf(tag) > -1) {
23155 this.black.push(tag);
23159 Roo.each(b, function(tag) {
23160 if (w.indexOf(tag) > -1) {
23163 if (this.black.indexOf(tag) > -1) {
23166 this.black.push(tag);
23171 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23172 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23176 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23177 if (b.indexOf(tag) > -1) {
23180 this.cwhite.push(tag);
23184 Roo.each(w, function(tag) {
23185 if (b.indexOf(tag) > -1) {
23188 if (this.cwhite.indexOf(tag) > -1) {
23191 this.cwhite.push(tag);
23196 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23197 if (w.indexOf(tag) > -1) {
23200 this.cblack.push(tag);
23204 Roo.each(b, function(tag) {
23205 if (w.indexOf(tag) > -1) {
23208 if (this.cblack.indexOf(tag) > -1) {
23211 this.cblack.push(tag);
23216 setStylesheets : function(stylesheets)
23218 if(typeof(stylesheets) == 'string'){
23219 Roo.get(this.iframe.contentDocument.head).createChild({
23221 rel : 'stylesheet',
23230 Roo.each(stylesheets, function(s) {
23235 Roo.get(_this.iframe.contentDocument.head).createChild({
23237 rel : 'stylesheet',
23246 removeStylesheets : function()
23250 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23255 setStyle : function(style)
23257 Roo.get(this.iframe.contentDocument.head).createChild({
23266 // hide stuff that is not compatible
23280 * @event specialkey
23284 * @cfg {String} fieldClass @hide
23287 * @cfg {String} focusClass @hide
23290 * @cfg {String} autoCreate @hide
23293 * @cfg {String} inputType @hide
23296 * @cfg {String} invalidClass @hide
23299 * @cfg {String} invalidText @hide
23302 * @cfg {String} msgFx @hide
23305 * @cfg {String} validateOnBlur @hide
23309 Roo.HtmlEditorCore.white = [
23310 'area', 'br', 'img', 'input', 'hr', 'wbr',
23312 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23313 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23314 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23315 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23316 'table', 'ul', 'xmp',
23318 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23321 'dir', 'menu', 'ol', 'ul', 'dl',
23327 Roo.HtmlEditorCore.black = [
23328 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23330 'base', 'basefont', 'bgsound', 'blink', 'body',
23331 'frame', 'frameset', 'head', 'html', 'ilayer',
23332 'iframe', 'layer', 'link', 'meta', 'object',
23333 'script', 'style' ,'title', 'xml' // clean later..
23335 Roo.HtmlEditorCore.clean = [
23336 'script', 'style', 'title', 'xml'
23338 Roo.HtmlEditorCore.remove = [
23343 Roo.HtmlEditorCore.ablack = [
23347 Roo.HtmlEditorCore.aclean = [
23348 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23352 Roo.HtmlEditorCore.pwhite= [
23353 'http', 'https', 'mailto'
23356 // white listed style attributes.
23357 Roo.HtmlEditorCore.cwhite= [
23358 // 'text-align', /// default is to allow most things..
23364 // black listed style attributes.
23365 Roo.HtmlEditorCore.cblack= [
23366 // 'font-size' -- this can be set by the project
23370 Roo.HtmlEditorCore.swapCodes =[
23389 * @class Roo.bootstrap.HtmlEditor
23390 * @extends Roo.bootstrap.TextArea
23391 * Bootstrap HtmlEditor class
23394 * Create a new HtmlEditor
23395 * @param {Object} config The config object
23398 Roo.bootstrap.HtmlEditor = function(config){
23399 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23400 if (!this.toolbars) {
23401 this.toolbars = [];
23404 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23407 * @event initialize
23408 * Fires when the editor is fully initialized (including the iframe)
23409 * @param {HtmlEditor} this
23414 * Fires when the editor is first receives the focus. Any insertion must wait
23415 * until after this event.
23416 * @param {HtmlEditor} this
23420 * @event beforesync
23421 * Fires before the textarea is updated with content from the editor iframe. Return false
23422 * to cancel the sync.
23423 * @param {HtmlEditor} this
23424 * @param {String} html
23428 * @event beforepush
23429 * Fires before the iframe editor is updated with content from the textarea. Return false
23430 * to cancel the push.
23431 * @param {HtmlEditor} this
23432 * @param {String} html
23437 * Fires when the textarea is updated with content from the editor iframe.
23438 * @param {HtmlEditor} this
23439 * @param {String} html
23444 * Fires when the iframe editor is updated with content from the textarea.
23445 * @param {HtmlEditor} this
23446 * @param {String} html
23450 * @event editmodechange
23451 * Fires when the editor switches edit modes
23452 * @param {HtmlEditor} this
23453 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23455 editmodechange: true,
23457 * @event editorevent
23458 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23459 * @param {HtmlEditor} this
23463 * @event firstfocus
23464 * Fires when on first focus - needed by toolbars..
23465 * @param {HtmlEditor} this
23470 * Auto save the htmlEditor value as a file into Events
23471 * @param {HtmlEditor} this
23475 * @event savedpreview
23476 * preview the saved version of htmlEditor
23477 * @param {HtmlEditor} this
23484 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23488 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23493 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23498 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23503 * @cfg {Number} height (in pixels)
23507 * @cfg {Number} width (in pixels)
23512 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23515 stylesheets: false,
23520 // private properties
23521 validationEvent : false,
23523 initialized : false,
23526 onFocus : Roo.emptyFn,
23528 hideMode:'offsets',
23530 tbContainer : false,
23534 toolbarContainer :function() {
23535 return this.wrap.select('.x-html-editor-tb',true).first();
23539 * Protected method that will not generally be called directly. It
23540 * is called when the editor creates its toolbar. Override this method if you need to
23541 * add custom toolbar buttons.
23542 * @param {HtmlEditor} editor
23544 createToolbar : function(){
23545 Roo.log('renewing');
23546 Roo.log("create toolbars");
23548 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23549 this.toolbars[0].render(this.toolbarContainer());
23553 // if (!editor.toolbars || !editor.toolbars.length) {
23554 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23557 // for (var i =0 ; i < editor.toolbars.length;i++) {
23558 // editor.toolbars[i] = Roo.factory(
23559 // typeof(editor.toolbars[i]) == 'string' ?
23560 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23561 // Roo.bootstrap.HtmlEditor);
23562 // editor.toolbars[i].init(editor);
23568 onRender : function(ct, position)
23570 // Roo.log("Call onRender: " + this.xtype);
23572 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23574 this.wrap = this.inputEl().wrap({
23575 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23578 this.editorcore.onRender(ct, position);
23580 if (this.resizable) {
23581 this.resizeEl = new Roo.Resizable(this.wrap, {
23585 minHeight : this.height,
23586 height: this.height,
23587 handles : this.resizable,
23590 resize : function(r, w, h) {
23591 _t.onResize(w,h); // -something
23597 this.createToolbar(this);
23600 if(!this.width && this.resizable){
23601 this.setSize(this.wrap.getSize());
23603 if (this.resizeEl) {
23604 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23605 // should trigger onReize..
23611 onResize : function(w, h)
23613 Roo.log('resize: ' +w + ',' + h );
23614 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23618 if(this.inputEl() ){
23619 if(typeof w == 'number'){
23620 var aw = w - this.wrap.getFrameWidth('lr');
23621 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23624 if(typeof h == 'number'){
23625 var tbh = -11; // fixme it needs to tool bar size!
23626 for (var i =0; i < this.toolbars.length;i++) {
23627 // fixme - ask toolbars for heights?
23628 tbh += this.toolbars[i].el.getHeight();
23629 //if (this.toolbars[i].footer) {
23630 // tbh += this.toolbars[i].footer.el.getHeight();
23638 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23639 ah -= 5; // knock a few pixes off for look..
23640 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23644 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23645 this.editorcore.onResize(ew,eh);
23650 * Toggles the editor between standard and source edit mode.
23651 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23653 toggleSourceEdit : function(sourceEditMode)
23655 this.editorcore.toggleSourceEdit(sourceEditMode);
23657 if(this.editorcore.sourceEditMode){
23658 Roo.log('editor - showing textarea');
23661 // Roo.log(this.syncValue());
23663 this.inputEl().removeClass(['hide', 'x-hidden']);
23664 this.inputEl().dom.removeAttribute('tabIndex');
23665 this.inputEl().focus();
23667 Roo.log('editor - hiding textarea');
23669 // Roo.log(this.pushValue());
23672 this.inputEl().addClass(['hide', 'x-hidden']);
23673 this.inputEl().dom.setAttribute('tabIndex', -1);
23674 //this.deferFocus();
23677 if(this.resizable){
23678 this.setSize(this.wrap.getSize());
23681 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23684 // private (for BoxComponent)
23685 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23687 // private (for BoxComponent)
23688 getResizeEl : function(){
23692 // private (for BoxComponent)
23693 getPositionEl : function(){
23698 initEvents : function(){
23699 this.originalValue = this.getValue();
23703 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23706 // markInvalid : Roo.emptyFn,
23708 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23711 // clearInvalid : Roo.emptyFn,
23713 setValue : function(v){
23714 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23715 this.editorcore.pushValue();
23720 deferFocus : function(){
23721 this.focus.defer(10, this);
23725 focus : function(){
23726 this.editorcore.focus();
23732 onDestroy : function(){
23738 for (var i =0; i < this.toolbars.length;i++) {
23739 // fixme - ask toolbars for heights?
23740 this.toolbars[i].onDestroy();
23743 this.wrap.dom.innerHTML = '';
23744 this.wrap.remove();
23749 onFirstFocus : function(){
23750 //Roo.log("onFirstFocus");
23751 this.editorcore.onFirstFocus();
23752 for (var i =0; i < this.toolbars.length;i++) {
23753 this.toolbars[i].onFirstFocus();
23759 syncValue : function()
23761 this.editorcore.syncValue();
23764 pushValue : function()
23766 this.editorcore.pushValue();
23770 // hide stuff that is not compatible
23784 * @event specialkey
23788 * @cfg {String} fieldClass @hide
23791 * @cfg {String} focusClass @hide
23794 * @cfg {String} autoCreate @hide
23797 * @cfg {String} inputType @hide
23800 * @cfg {String} invalidClass @hide
23803 * @cfg {String} invalidText @hide
23806 * @cfg {String} msgFx @hide
23809 * @cfg {String} validateOnBlur @hide
23818 Roo.namespace('Roo.bootstrap.htmleditor');
23820 * @class Roo.bootstrap.HtmlEditorToolbar1
23825 new Roo.bootstrap.HtmlEditor({
23828 new Roo.bootstrap.HtmlEditorToolbar1({
23829 disable : { fonts: 1 , format: 1, ..., ... , ...],
23835 * @cfg {Object} disable List of elements to disable..
23836 * @cfg {Array} btns List of additional buttons.
23840 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23843 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23846 Roo.apply(this, config);
23848 // default disabled, based on 'good practice'..
23849 this.disable = this.disable || {};
23850 Roo.applyIf(this.disable, {
23853 specialElements : true
23855 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23857 this.editor = config.editor;
23858 this.editorcore = config.editor.editorcore;
23860 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23862 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23863 // dont call parent... till later.
23865 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23870 editorcore : false,
23875 "h1","h2","h3","h4","h5","h6",
23877 "abbr", "acronym", "address", "cite", "samp", "var",
23881 onRender : function(ct, position)
23883 // Roo.log("Call onRender: " + this.xtype);
23885 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23887 this.el.dom.style.marginBottom = '0';
23889 var editorcore = this.editorcore;
23890 var editor= this.editor;
23893 var btn = function(id,cmd , toggle, handler, html){
23895 var event = toggle ? 'toggle' : 'click';
23900 xns: Roo.bootstrap,
23903 enableToggle:toggle !== false,
23905 pressed : toggle ? false : null,
23908 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23909 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23915 // var cb_box = function...
23920 xns: Roo.bootstrap,
23921 glyphicon : 'font',
23925 xns: Roo.bootstrap,
23929 Roo.each(this.formats, function(f) {
23930 style.menu.items.push({
23932 xns: Roo.bootstrap,
23933 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23938 editorcore.insertTag(this.tagname);
23945 children.push(style);
23947 btn('bold',false,true);
23948 btn('italic',false,true);
23949 btn('align-left', 'justifyleft',true);
23950 btn('align-center', 'justifycenter',true);
23951 btn('align-right' , 'justifyright',true);
23952 btn('link', false, false, function(btn) {
23953 //Roo.log("create link?");
23954 var url = prompt(this.createLinkText, this.defaultLinkValue);
23955 if(url && url != 'http:/'+'/'){
23956 this.editorcore.relayCmd('createlink', url);
23959 btn('list','insertunorderedlist',true);
23960 btn('pencil', false,true, function(btn){
23962 this.toggleSourceEdit(btn.pressed);
23965 if (this.editor.btns.length > 0) {
23966 for (var i = 0; i<this.editor.btns.length; i++) {
23967 children.push(this.editor.btns[i]);
23975 xns: Roo.bootstrap,
23980 xns: Roo.bootstrap,
23985 cog.menu.items.push({
23987 xns: Roo.bootstrap,
23988 html : Clean styles,
23993 editorcore.insertTag(this.tagname);
24002 this.xtype = 'NavSimplebar';
24004 for(var i=0;i< children.length;i++) {
24006 this.buttons.add(this.addxtypeChild(children[i]));
24010 editor.on('editorevent', this.updateToolbar, this);
24012 onBtnClick : function(id)
24014 this.editorcore.relayCmd(id);
24015 this.editorcore.focus();
24019 * Protected method that will not generally be called directly. It triggers
24020 * a toolbar update by reading the markup state of the current selection in the editor.
24022 updateToolbar: function(){
24024 if(!this.editorcore.activated){
24025 this.editor.onFirstFocus(); // is this neeed?
24029 var btns = this.buttons;
24030 var doc = this.editorcore.doc;
24031 btns.get('bold').setActive(doc.queryCommandState('bold'));
24032 btns.get('italic').setActive(doc.queryCommandState('italic'));
24033 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24035 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24036 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24037 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24039 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24040 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24043 var ans = this.editorcore.getAllAncestors();
24044 if (this.formatCombo) {
24047 var store = this.formatCombo.store;
24048 this.formatCombo.setValue("");
24049 for (var i =0; i < ans.length;i++) {
24050 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24052 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24060 // hides menus... - so this cant be on a menu...
24061 Roo.bootstrap.MenuMgr.hideAll();
24063 Roo.bootstrap.MenuMgr.hideAll();
24064 //this.editorsyncValue();
24066 onFirstFocus: function() {
24067 this.buttons.each(function(item){
24071 toggleSourceEdit : function(sourceEditMode){
24074 if(sourceEditMode){
24075 Roo.log("disabling buttons");
24076 this.buttons.each( function(item){
24077 if(item.cmd != 'pencil'){
24083 Roo.log("enabling buttons");
24084 if(this.editorcore.initialized){
24085 this.buttons.each( function(item){
24091 Roo.log("calling toggole on editor");
24092 // tell the editor that it's been pressed..
24093 this.editor.toggleSourceEdit(sourceEditMode);
24103 * @class Roo.bootstrap.Table.AbstractSelectionModel
24104 * @extends Roo.util.Observable
24105 * Abstract base class for grid SelectionModels. It provides the interface that should be
24106 * implemented by descendant classes. This class should not be directly instantiated.
24109 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24110 this.locked = false;
24111 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24115 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24116 /** @ignore Called by the grid automatically. Do not call directly. */
24117 init : function(grid){
24123 * Locks the selections.
24126 this.locked = true;
24130 * Unlocks the selections.
24132 unlock : function(){
24133 this.locked = false;
24137 * Returns true if the selections are locked.
24138 * @return {Boolean}
24140 isLocked : function(){
24141 return this.locked;
24145 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24146 * @class Roo.bootstrap.Table.RowSelectionModel
24147 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24148 * It supports multiple selections and keyboard selection/navigation.
24150 * @param {Object} config
24153 Roo.bootstrap.Table.RowSelectionModel = function(config){
24154 Roo.apply(this, config);
24155 this.selections = new Roo.util.MixedCollection(false, function(o){
24160 this.lastActive = false;
24164 * @event selectionchange
24165 * Fires when the selection changes
24166 * @param {SelectionModel} this
24168 "selectionchange" : true,
24170 * @event afterselectionchange
24171 * Fires after the selection changes (eg. by key press or clicking)
24172 * @param {SelectionModel} this
24174 "afterselectionchange" : true,
24176 * @event beforerowselect
24177 * Fires when a row is selected being selected, return false to cancel.
24178 * @param {SelectionModel} this
24179 * @param {Number} rowIndex The selected index
24180 * @param {Boolean} keepExisting False if other selections will be cleared
24182 "beforerowselect" : true,
24185 * Fires when a row is selected.
24186 * @param {SelectionModel} this
24187 * @param {Number} rowIndex The selected index
24188 * @param {Roo.data.Record} r The record
24190 "rowselect" : true,
24192 * @event rowdeselect
24193 * Fires when a row is deselected.
24194 * @param {SelectionModel} this
24195 * @param {Number} rowIndex The selected index
24197 "rowdeselect" : true
24199 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24200 this.locked = false;
24203 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24205 * @cfg {Boolean} singleSelect
24206 * True to allow selection of only one row at a time (defaults to false)
24208 singleSelect : false,
24211 initEvents : function()
24214 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24215 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24216 //}else{ // allow click to work like normal
24217 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24219 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24220 this.grid.on("rowclick", this.handleMouseDown, this);
24222 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24223 "up" : function(e){
24225 this.selectPrevious(e.shiftKey);
24226 }else if(this.last !== false && this.lastActive !== false){
24227 var last = this.last;
24228 this.selectRange(this.last, this.lastActive-1);
24229 this.grid.getView().focusRow(this.lastActive);
24230 if(last !== false){
24234 this.selectFirstRow();
24236 this.fireEvent("afterselectionchange", this);
24238 "down" : function(e){
24240 this.selectNext(e.shiftKey);
24241 }else if(this.last !== false && this.lastActive !== false){
24242 var last = this.last;
24243 this.selectRange(this.last, this.lastActive+1);
24244 this.grid.getView().focusRow(this.lastActive);
24245 if(last !== false){
24249 this.selectFirstRow();
24251 this.fireEvent("afterselectionchange", this);
24255 this.grid.store.on('load', function(){
24256 this.selections.clear();
24259 var view = this.grid.view;
24260 view.on("refresh", this.onRefresh, this);
24261 view.on("rowupdated", this.onRowUpdated, this);
24262 view.on("rowremoved", this.onRemove, this);
24267 onRefresh : function()
24269 var ds = this.grid.store, i, v = this.grid.view;
24270 var s = this.selections;
24271 s.each(function(r){
24272 if((i = ds.indexOfId(r.id)) != -1){
24281 onRemove : function(v, index, r){
24282 this.selections.remove(r);
24286 onRowUpdated : function(v, index, r){
24287 if(this.isSelected(r)){
24288 v.onRowSelect(index);
24294 * @param {Array} records The records to select
24295 * @param {Boolean} keepExisting (optional) True to keep existing selections
24297 selectRecords : function(records, keepExisting)
24300 this.clearSelections();
24302 var ds = this.grid.store;
24303 for(var i = 0, len = records.length; i < len; i++){
24304 this.selectRow(ds.indexOf(records[i]), true);
24309 * Gets the number of selected rows.
24312 getCount : function(){
24313 return this.selections.length;
24317 * Selects the first row in the grid.
24319 selectFirstRow : function(){
24324 * Select the last row.
24325 * @param {Boolean} keepExisting (optional) True to keep existing selections
24327 selectLastRow : function(keepExisting){
24328 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24329 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24333 * Selects the row immediately following the last selected row.
24334 * @param {Boolean} keepExisting (optional) True to keep existing selections
24336 selectNext : function(keepExisting)
24338 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24339 this.selectRow(this.last+1, keepExisting);
24340 this.grid.getView().focusRow(this.last);
24345 * Selects the row that precedes the last selected row.
24346 * @param {Boolean} keepExisting (optional) True to keep existing selections
24348 selectPrevious : function(keepExisting){
24350 this.selectRow(this.last-1, keepExisting);
24351 this.grid.getView().focusRow(this.last);
24356 * Returns the selected records
24357 * @return {Array} Array of selected records
24359 getSelections : function(){
24360 return [].concat(this.selections.items);
24364 * Returns the first selected record.
24367 getSelected : function(){
24368 return this.selections.itemAt(0);
24373 * Clears all selections.
24375 clearSelections : function(fast)
24381 var ds = this.grid.store;
24382 var s = this.selections;
24383 s.each(function(r){
24384 this.deselectRow(ds.indexOfId(r.id));
24388 this.selections.clear();
24395 * Selects all rows.
24397 selectAll : function(){
24401 this.selections.clear();
24402 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24403 this.selectRow(i, true);
24408 * Returns True if there is a selection.
24409 * @return {Boolean}
24411 hasSelection : function(){
24412 return this.selections.length > 0;
24416 * Returns True if the specified row is selected.
24417 * @param {Number/Record} record The record or index of the record to check
24418 * @return {Boolean}
24420 isSelected : function(index){
24421 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24422 return (r && this.selections.key(r.id) ? true : false);
24426 * Returns True if the specified record id is selected.
24427 * @param {String} id The id of record to check
24428 * @return {Boolean}
24430 isIdSelected : function(id){
24431 return (this.selections.key(id) ? true : false);
24436 handleMouseDBClick : function(e, t){
24440 handleMouseDown : function(e, t)
24442 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24443 if(this.isLocked() || rowIndex < 0 ){
24446 if(e.shiftKey && this.last !== false){
24447 var last = this.last;
24448 this.selectRange(last, rowIndex, e.ctrlKey);
24449 this.last = last; // reset the last
24453 var isSelected = this.isSelected(rowIndex);
24454 //Roo.log("select row:" + rowIndex);
24456 this.deselectRow(rowIndex);
24458 this.selectRow(rowIndex, true);
24462 if(e.button !== 0 && isSelected){
24463 alert('rowIndex 2: ' + rowIndex);
24464 view.focusRow(rowIndex);
24465 }else if(e.ctrlKey && isSelected){
24466 this.deselectRow(rowIndex);
24467 }else if(!isSelected){
24468 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24469 view.focusRow(rowIndex);
24473 this.fireEvent("afterselectionchange", this);
24476 handleDragableRowClick : function(grid, rowIndex, e)
24478 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24479 this.selectRow(rowIndex, false);
24480 grid.view.focusRow(rowIndex);
24481 this.fireEvent("afterselectionchange", this);
24486 * Selects multiple rows.
24487 * @param {Array} rows Array of the indexes of the row to select
24488 * @param {Boolean} keepExisting (optional) True to keep existing selections
24490 selectRows : function(rows, keepExisting){
24492 this.clearSelections();
24494 for(var i = 0, len = rows.length; i < len; i++){
24495 this.selectRow(rows[i], true);
24500 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24501 * @param {Number} startRow The index of the first row in the range
24502 * @param {Number} endRow The index of the last row in the range
24503 * @param {Boolean} keepExisting (optional) True to retain existing selections
24505 selectRange : function(startRow, endRow, keepExisting){
24510 this.clearSelections();
24512 if(startRow <= endRow){
24513 for(var i = startRow; i <= endRow; i++){
24514 this.selectRow(i, true);
24517 for(var i = startRow; i >= endRow; i--){
24518 this.selectRow(i, true);
24524 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24525 * @param {Number} startRow The index of the first row in the range
24526 * @param {Number} endRow The index of the last row in the range
24528 deselectRange : function(startRow, endRow, preventViewNotify){
24532 for(var i = startRow; i <= endRow; i++){
24533 this.deselectRow(i, preventViewNotify);
24539 * @param {Number} row The index of the row to select
24540 * @param {Boolean} keepExisting (optional) True to keep existing selections
24542 selectRow : function(index, keepExisting, preventViewNotify)
24544 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24547 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24548 if(!keepExisting || this.singleSelect){
24549 this.clearSelections();
24552 var r = this.grid.store.getAt(index);
24553 //console.log('selectRow - record id :' + r.id);
24555 this.selections.add(r);
24556 this.last = this.lastActive = index;
24557 if(!preventViewNotify){
24558 var proxy = new Roo.Element(
24559 this.grid.getRowDom(index)
24561 proxy.addClass('bg-info info');
24563 this.fireEvent("rowselect", this, index, r);
24564 this.fireEvent("selectionchange", this);
24570 * @param {Number} row The index of the row to deselect
24572 deselectRow : function(index, preventViewNotify)
24577 if(this.last == index){
24580 if(this.lastActive == index){
24581 this.lastActive = false;
24584 var r = this.grid.store.getAt(index);
24589 this.selections.remove(r);
24590 //.console.log('deselectRow - record id :' + r.id);
24591 if(!preventViewNotify){
24593 var proxy = new Roo.Element(
24594 this.grid.getRowDom(index)
24596 proxy.removeClass('bg-info info');
24598 this.fireEvent("rowdeselect", this, index);
24599 this.fireEvent("selectionchange", this);
24603 restoreLast : function(){
24605 this.last = this._last;
24610 acceptsNav : function(row, col, cm){
24611 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24615 onEditorKey : function(field, e){
24616 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24621 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24623 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24625 }else if(k == e.ENTER && !e.ctrlKey){
24629 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24631 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24633 }else if(k == e.ESC){
24637 g.startEditing(newCell[0], newCell[1]);
24643 * Ext JS Library 1.1.1
24644 * Copyright(c) 2006-2007, Ext JS, LLC.
24646 * Originally Released Under LGPL - original licence link has changed is not relivant.
24649 * <script type="text/javascript">
24653 * @class Roo.bootstrap.PagingToolbar
24654 * @extends Roo.bootstrap.NavSimplebar
24655 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24657 * Create a new PagingToolbar
24658 * @param {Object} config The config object
24659 * @param {Roo.data.Store} store
24661 Roo.bootstrap.PagingToolbar = function(config)
24663 // old args format still supported... - xtype is prefered..
24664 // created from xtype...
24666 this.ds = config.dataSource;
24668 if (config.store && !this.ds) {
24669 this.store= Roo.factory(config.store, Roo.data);
24670 this.ds = this.store;
24671 this.ds.xmodule = this.xmodule || false;
24674 this.toolbarItems = [];
24675 if (config.items) {
24676 this.toolbarItems = config.items;
24679 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24684 this.bind(this.ds);
24687 if (Roo.bootstrap.version == 4) {
24688 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24690 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24695 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24697 * @cfg {Roo.data.Store} dataSource
24698 * The underlying data store providing the paged data
24701 * @cfg {String/HTMLElement/Element} container
24702 * container The id or element that will contain the toolbar
24705 * @cfg {Boolean} displayInfo
24706 * True to display the displayMsg (defaults to false)
24709 * @cfg {Number} pageSize
24710 * The number of records to display per page (defaults to 20)
24714 * @cfg {String} displayMsg
24715 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24717 displayMsg : 'Displaying {0} - {1} of {2}',
24719 * @cfg {String} emptyMsg
24720 * The message to display when no records are found (defaults to "No data to display")
24722 emptyMsg : 'No data to display',
24724 * Customizable piece of the default paging text (defaults to "Page")
24727 beforePageText : "Page",
24729 * Customizable piece of the default paging text (defaults to "of %0")
24732 afterPageText : "of {0}",
24734 * Customizable piece of the default paging text (defaults to "First Page")
24737 firstText : "First Page",
24739 * Customizable piece of the default paging text (defaults to "Previous Page")
24742 prevText : "Previous Page",
24744 * Customizable piece of the default paging text (defaults to "Next Page")
24747 nextText : "Next Page",
24749 * Customizable piece of the default paging text (defaults to "Last Page")
24752 lastText : "Last Page",
24754 * Customizable piece of the default paging text (defaults to "Refresh")
24757 refreshText : "Refresh",
24761 onRender : function(ct, position)
24763 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24764 this.navgroup.parentId = this.id;
24765 this.navgroup.onRender(this.el, null);
24766 // add the buttons to the navgroup
24768 if(this.displayInfo){
24769 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24770 this.displayEl = this.el.select('.x-paging-info', true).first();
24771 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24772 // this.displayEl = navel.el.select('span',true).first();
24778 Roo.each(_this.buttons, function(e){ // this might need to use render????
24779 Roo.factory(e).render(_this.el);
24783 Roo.each(_this.toolbarItems, function(e) {
24784 _this.navgroup.addItem(e);
24788 this.first = this.navgroup.addItem({
24789 tooltip: this.firstText,
24790 cls: "prev btn-outline-secondary",
24791 html : ' <i class="fa fa-step-backward"></i>',
24793 preventDefault: true,
24794 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24797 this.prev = this.navgroup.addItem({
24798 tooltip: this.prevText,
24799 cls: "prev btn-outline-secondary",
24800 html : ' <i class="fa fa-backward"></i>',
24802 preventDefault: true,
24803 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24805 //this.addSeparator();
24808 var field = this.navgroup.addItem( {
24810 cls : 'x-paging-position btn-outline-secondary',
24812 html : this.beforePageText +
24813 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24814 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24817 this.field = field.el.select('input', true).first();
24818 this.field.on("keydown", this.onPagingKeydown, this);
24819 this.field.on("focus", function(){this.dom.select();});
24822 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24823 //this.field.setHeight(18);
24824 //this.addSeparator();
24825 this.next = this.navgroup.addItem({
24826 tooltip: this.nextText,
24827 cls: "next btn-outline-secondary",
24828 html : ' <i class="fa fa-forward"></i>',
24830 preventDefault: true,
24831 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24833 this.last = this.navgroup.addItem({
24834 tooltip: this.lastText,
24835 html : ' <i class="fa fa-step-forward"></i>',
24836 cls: "next btn-outline-secondary",
24838 preventDefault: true,
24839 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24841 //this.addSeparator();
24842 this.loading = this.navgroup.addItem({
24843 tooltip: this.refreshText,
24844 cls: "btn-outline-secondary",
24845 html : ' <i class="fa fa-refresh"></i>',
24846 preventDefault: true,
24847 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24853 updateInfo : function(){
24854 if(this.displayEl){
24855 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24856 var msg = count == 0 ?
24860 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24862 this.displayEl.update(msg);
24867 onLoad : function(ds, r, o)
24869 this.cursor = o.params.start ? o.params.start : 0;
24871 var d = this.getPageData(),
24876 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24877 this.field.dom.value = ap;
24878 this.first.setDisabled(ap == 1);
24879 this.prev.setDisabled(ap == 1);
24880 this.next.setDisabled(ap == ps);
24881 this.last.setDisabled(ap == ps);
24882 this.loading.enable();
24887 getPageData : function(){
24888 var total = this.ds.getTotalCount();
24891 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24892 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24897 onLoadError : function(){
24898 this.loading.enable();
24902 onPagingKeydown : function(e){
24903 var k = e.getKey();
24904 var d = this.getPageData();
24906 var v = this.field.dom.value, pageNum;
24907 if(!v || isNaN(pageNum = parseInt(v, 10))){
24908 this.field.dom.value = d.activePage;
24911 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24912 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24915 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))
24917 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24918 this.field.dom.value = pageNum;
24919 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24922 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24924 var v = this.field.dom.value, pageNum;
24925 var increment = (e.shiftKey) ? 10 : 1;
24926 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24929 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24930 this.field.dom.value = d.activePage;
24933 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24935 this.field.dom.value = parseInt(v, 10) + increment;
24936 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24937 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24944 beforeLoad : function(){
24946 this.loading.disable();
24951 onClick : function(which){
24960 ds.load({params:{start: 0, limit: this.pageSize}});
24963 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24966 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24969 var total = ds.getTotalCount();
24970 var extra = total % this.pageSize;
24971 var lastStart = extra ? (total - extra) : total-this.pageSize;
24972 ds.load({params:{start: lastStart, limit: this.pageSize}});
24975 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24981 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24982 * @param {Roo.data.Store} store The data store to unbind
24984 unbind : function(ds){
24985 ds.un("beforeload", this.beforeLoad, this);
24986 ds.un("load", this.onLoad, this);
24987 ds.un("loadexception", this.onLoadError, this);
24988 ds.un("remove", this.updateInfo, this);
24989 ds.un("add", this.updateInfo, this);
24990 this.ds = undefined;
24994 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24995 * @param {Roo.data.Store} store The data store to bind
24997 bind : function(ds){
24998 ds.on("beforeload", this.beforeLoad, this);
24999 ds.on("load", this.onLoad, this);
25000 ds.on("loadexception", this.onLoadError, this);
25001 ds.on("remove", this.updateInfo, this);
25002 ds.on("add", this.updateInfo, this);
25013 * @class Roo.bootstrap.MessageBar
25014 * @extends Roo.bootstrap.Component
25015 * Bootstrap MessageBar class
25016 * @cfg {String} html contents of the MessageBar
25017 * @cfg {String} weight (info | success | warning | danger) default info
25018 * @cfg {String} beforeClass insert the bar before the given class
25019 * @cfg {Boolean} closable (true | false) default false
25020 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25023 * Create a new Element
25024 * @param {Object} config The config object
25027 Roo.bootstrap.MessageBar = function(config){
25028 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25031 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25037 beforeClass: 'bootstrap-sticky-wrap',
25039 getAutoCreate : function(){
25043 cls: 'alert alert-dismissable alert-' + this.weight,
25048 html: this.html || ''
25054 cfg.cls += ' alert-messages-fixed';
25068 onRender : function(ct, position)
25070 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25073 var cfg = Roo.apply({}, this.getAutoCreate());
25077 cfg.cls += ' ' + this.cls;
25080 cfg.style = this.style;
25082 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25084 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25087 this.el.select('>button.close').on('click', this.hide, this);
25093 if (!this.rendered) {
25099 this.fireEvent('show', this);
25105 if (!this.rendered) {
25111 this.fireEvent('hide', this);
25114 update : function()
25116 // var e = this.el.dom.firstChild;
25118 // if(this.closable){
25119 // e = e.nextSibling;
25122 // e.data = this.html || '';
25124 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25140 * @class Roo.bootstrap.Graph
25141 * @extends Roo.bootstrap.Component
25142 * Bootstrap Graph class
25146 @cfg {String} graphtype bar | vbar | pie
25147 @cfg {number} g_x coodinator | centre x (pie)
25148 @cfg {number} g_y coodinator | centre y (pie)
25149 @cfg {number} g_r radius (pie)
25150 @cfg {number} g_height height of the chart (respected by all elements in the set)
25151 @cfg {number} g_width width of the chart (respected by all elements in the set)
25152 @cfg {Object} title The title of the chart
25155 -opts (object) options for the chart
25157 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25158 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25160 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.
25161 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25163 o stretch (boolean)
25165 -opts (object) options for the pie
25168 o startAngle (number)
25169 o endAngle (number)
25173 * Create a new Input
25174 * @param {Object} config The config object
25177 Roo.bootstrap.Graph = function(config){
25178 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25184 * The img click event for the img.
25185 * @param {Roo.EventObject} e
25191 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25202 //g_colors: this.colors,
25209 getAutoCreate : function(){
25220 onRender : function(ct,position){
25223 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25225 if (typeof(Raphael) == 'undefined') {
25226 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25230 this.raphael = Raphael(this.el.dom);
25232 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25233 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25234 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25235 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25237 r.text(160, 10, "Single Series Chart").attr(txtattr);
25238 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25239 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25240 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25242 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25243 r.barchart(330, 10, 300, 220, data1);
25244 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25245 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25248 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25249 // r.barchart(30, 30, 560, 250, xdata, {
25250 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25251 // axis : "0 0 1 1",
25252 // axisxlabels : xdata
25253 // //yvalues : cols,
25256 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25258 // this.load(null,xdata,{
25259 // axis : "0 0 1 1",
25260 // axisxlabels : xdata
25265 load : function(graphtype,xdata,opts)
25267 this.raphael.clear();
25269 graphtype = this.graphtype;
25274 var r = this.raphael,
25275 fin = function () {
25276 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25278 fout = function () {
25279 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25281 pfin = function() {
25282 this.sector.stop();
25283 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25286 this.label[0].stop();
25287 this.label[0].attr({ r: 7.5 });
25288 this.label[1].attr({ "font-weight": 800 });
25291 pfout = function() {
25292 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25295 this.label[0].animate({ r: 5 }, 500, "bounce");
25296 this.label[1].attr({ "font-weight": 400 });
25302 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25305 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25308 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25309 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25311 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25318 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25323 setTitle: function(o)
25328 initEvents: function() {
25331 this.el.on('click', this.onClick, this);
25335 onClick : function(e)
25337 Roo.log('img onclick');
25338 this.fireEvent('click', this, e);
25350 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25353 * @class Roo.bootstrap.dash.NumberBox
25354 * @extends Roo.bootstrap.Component
25355 * Bootstrap NumberBox class
25356 * @cfg {String} headline Box headline
25357 * @cfg {String} content Box content
25358 * @cfg {String} icon Box icon
25359 * @cfg {String} footer Footer text
25360 * @cfg {String} fhref Footer href
25363 * Create a new NumberBox
25364 * @param {Object} config The config object
25368 Roo.bootstrap.dash.NumberBox = function(config){
25369 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25373 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25382 getAutoCreate : function(){
25386 cls : 'small-box ',
25394 cls : 'roo-headline',
25395 html : this.headline
25399 cls : 'roo-content',
25400 html : this.content
25414 cls : 'ion ' + this.icon
25423 cls : 'small-box-footer',
25424 href : this.fhref || '#',
25428 cfg.cn.push(footer);
25435 onRender : function(ct,position){
25436 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25443 setHeadline: function (value)
25445 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25448 setFooter: function (value, href)
25450 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25453 this.el.select('a.small-box-footer',true).first().attr('href', href);
25458 setContent: function (value)
25460 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25463 initEvents: function()
25477 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25480 * @class Roo.bootstrap.dash.TabBox
25481 * @extends Roo.bootstrap.Component
25482 * Bootstrap TabBox class
25483 * @cfg {String} title Title of the TabBox
25484 * @cfg {String} icon Icon of the TabBox
25485 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25486 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25489 * Create a new TabBox
25490 * @param {Object} config The config object
25494 Roo.bootstrap.dash.TabBox = function(config){
25495 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25500 * When a pane is added
25501 * @param {Roo.bootstrap.dash.TabPane} pane
25505 * @event activatepane
25506 * When a pane is activated
25507 * @param {Roo.bootstrap.dash.TabPane} pane
25509 "activatepane" : true
25517 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25522 tabScrollable : false,
25524 getChildContainer : function()
25526 return this.el.select('.tab-content', true).first();
25529 getAutoCreate : function(){
25533 cls: 'pull-left header',
25541 cls: 'fa ' + this.icon
25547 cls: 'nav nav-tabs pull-right',
25553 if(this.tabScrollable){
25560 cls: 'nav nav-tabs pull-right',
25571 cls: 'nav-tabs-custom',
25576 cls: 'tab-content no-padding',
25584 initEvents : function()
25586 //Roo.log('add add pane handler');
25587 this.on('addpane', this.onAddPane, this);
25590 * Updates the box title
25591 * @param {String} html to set the title to.
25593 setTitle : function(value)
25595 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25597 onAddPane : function(pane)
25599 this.panes.push(pane);
25600 //Roo.log('addpane');
25602 // tabs are rendere left to right..
25603 if(!this.showtabs){
25607 var ctr = this.el.select('.nav-tabs', true).first();
25610 var existing = ctr.select('.nav-tab',true);
25611 var qty = existing.getCount();;
25614 var tab = ctr.createChild({
25616 cls : 'nav-tab' + (qty ? '' : ' active'),
25624 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25627 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25629 pane.el.addClass('active');
25634 onTabClick : function(ev,un,ob,pane)
25636 //Roo.log('tab - prev default');
25637 ev.preventDefault();
25640 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25641 pane.tab.addClass('active');
25642 //Roo.log(pane.title);
25643 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25644 // technically we should have a deactivate event.. but maybe add later.
25645 // and it should not de-activate the selected tab...
25646 this.fireEvent('activatepane', pane);
25647 pane.el.addClass('active');
25648 pane.fireEvent('activate');
25653 getActivePane : function()
25656 Roo.each(this.panes, function(p) {
25657 if(p.el.hasClass('active')){
25678 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25680 * @class Roo.bootstrap.TabPane
25681 * @extends Roo.bootstrap.Component
25682 * Bootstrap TabPane class
25683 * @cfg {Boolean} active (false | true) Default false
25684 * @cfg {String} title title of panel
25688 * Create a new TabPane
25689 * @param {Object} config The config object
25692 Roo.bootstrap.dash.TabPane = function(config){
25693 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25699 * When a pane is activated
25700 * @param {Roo.bootstrap.dash.TabPane} pane
25707 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25712 // the tabBox that this is attached to.
25715 getAutoCreate : function()
25723 cfg.cls += ' active';
25728 initEvents : function()
25730 //Roo.log('trigger add pane handler');
25731 this.parent().fireEvent('addpane', this)
25735 * Updates the tab title
25736 * @param {String} html to set the title to.
25738 setTitle: function(str)
25744 this.tab.select('a', true).first().dom.innerHTML = str;
25761 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25764 * @class Roo.bootstrap.menu.Menu
25765 * @extends Roo.bootstrap.Component
25766 * Bootstrap Menu class - container for Menu
25767 * @cfg {String} html Text of the menu
25768 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25769 * @cfg {String} icon Font awesome icon
25770 * @cfg {String} pos Menu align to (top | bottom) default bottom
25774 * Create a new Menu
25775 * @param {Object} config The config object
25779 Roo.bootstrap.menu.Menu = function(config){
25780 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25784 * @event beforeshow
25785 * Fires before this menu is displayed
25786 * @param {Roo.bootstrap.menu.Menu} this
25790 * @event beforehide
25791 * Fires before this menu is hidden
25792 * @param {Roo.bootstrap.menu.Menu} this
25797 * Fires after this menu is displayed
25798 * @param {Roo.bootstrap.menu.Menu} this
25803 * Fires after this menu is hidden
25804 * @param {Roo.bootstrap.menu.Menu} this
25809 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25810 * @param {Roo.bootstrap.menu.Menu} this
25811 * @param {Roo.EventObject} e
25818 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25822 weight : 'default',
25827 getChildContainer : function() {
25828 if(this.isSubMenu){
25832 return this.el.select('ul.dropdown-menu', true).first();
25835 getAutoCreate : function()
25840 cls : 'roo-menu-text',
25848 cls : 'fa ' + this.icon
25859 cls : 'dropdown-button btn btn-' + this.weight,
25864 cls : 'dropdown-toggle btn btn-' + this.weight,
25874 cls : 'dropdown-menu'
25880 if(this.pos == 'top'){
25881 cfg.cls += ' dropup';
25884 if(this.isSubMenu){
25887 cls : 'dropdown-menu'
25894 onRender : function(ct, position)
25896 this.isSubMenu = ct.hasClass('dropdown-submenu');
25898 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25901 initEvents : function()
25903 if(this.isSubMenu){
25907 this.hidden = true;
25909 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25910 this.triggerEl.on('click', this.onTriggerPress, this);
25912 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25913 this.buttonEl.on('click', this.onClick, this);
25919 if(this.isSubMenu){
25923 return this.el.select('ul.dropdown-menu', true).first();
25926 onClick : function(e)
25928 this.fireEvent("click", this, e);
25931 onTriggerPress : function(e)
25933 if (this.isVisible()) {
25940 isVisible : function(){
25941 return !this.hidden;
25946 this.fireEvent("beforeshow", this);
25948 this.hidden = false;
25949 this.el.addClass('open');
25951 Roo.get(document).on("mouseup", this.onMouseUp, this);
25953 this.fireEvent("show", this);
25960 this.fireEvent("beforehide", this);
25962 this.hidden = true;
25963 this.el.removeClass('open');
25965 Roo.get(document).un("mouseup", this.onMouseUp);
25967 this.fireEvent("hide", this);
25970 onMouseUp : function()
25984 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25987 * @class Roo.bootstrap.menu.Item
25988 * @extends Roo.bootstrap.Component
25989 * Bootstrap MenuItem class
25990 * @cfg {Boolean} submenu (true | false) default false
25991 * @cfg {String} html text of the item
25992 * @cfg {String} href the link
25993 * @cfg {Boolean} disable (true | false) default false
25994 * @cfg {Boolean} preventDefault (true | false) default true
25995 * @cfg {String} icon Font awesome icon
25996 * @cfg {String} pos Submenu align to (left | right) default right
26000 * Create a new Item
26001 * @param {Object} config The config object
26005 Roo.bootstrap.menu.Item = function(config){
26006 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26010 * Fires when the mouse is hovering over this menu
26011 * @param {Roo.bootstrap.menu.Item} this
26012 * @param {Roo.EventObject} e
26017 * Fires when the mouse exits this menu
26018 * @param {Roo.bootstrap.menu.Item} this
26019 * @param {Roo.EventObject} e
26025 * The raw click event for the entire grid.
26026 * @param {Roo.EventObject} e
26032 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26037 preventDefault: true,
26042 getAutoCreate : function()
26047 cls : 'roo-menu-item-text',
26055 cls : 'fa ' + this.icon
26064 href : this.href || '#',
26071 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26075 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26077 if(this.pos == 'left'){
26078 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26085 initEvents : function()
26087 this.el.on('mouseover', this.onMouseOver, this);
26088 this.el.on('mouseout', this.onMouseOut, this);
26090 this.el.select('a', true).first().on('click', this.onClick, this);
26094 onClick : function(e)
26096 if(this.preventDefault){
26097 e.preventDefault();
26100 this.fireEvent("click", this, e);
26103 onMouseOver : function(e)
26105 if(this.submenu && this.pos == 'left'){
26106 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26109 this.fireEvent("mouseover", this, e);
26112 onMouseOut : function(e)
26114 this.fireEvent("mouseout", this, e);
26126 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26129 * @class Roo.bootstrap.menu.Separator
26130 * @extends Roo.bootstrap.Component
26131 * Bootstrap Separator class
26134 * Create a new Separator
26135 * @param {Object} config The config object
26139 Roo.bootstrap.menu.Separator = function(config){
26140 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26143 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26145 getAutoCreate : function(){
26166 * @class Roo.bootstrap.Tooltip
26167 * Bootstrap Tooltip class
26168 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26169 * to determine which dom element triggers the tooltip.
26171 * It needs to add support for additional attributes like tooltip-position
26174 * Create a new Toolti
26175 * @param {Object} config The config object
26178 Roo.bootstrap.Tooltip = function(config){
26179 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26181 this.alignment = Roo.bootstrap.Tooltip.alignment;
26183 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26184 this.alignment = config.alignment;
26189 Roo.apply(Roo.bootstrap.Tooltip, {
26191 * @function init initialize tooltip monitoring.
26195 currentTip : false,
26196 currentRegion : false,
26202 Roo.get(document).on('mouseover', this.enter ,this);
26203 Roo.get(document).on('mouseout', this.leave, this);
26206 this.currentTip = new Roo.bootstrap.Tooltip();
26209 enter : function(ev)
26211 var dom = ev.getTarget();
26213 //Roo.log(['enter',dom]);
26214 var el = Roo.fly(dom);
26215 if (this.currentEl) {
26217 //Roo.log(this.currentEl);
26218 //Roo.log(this.currentEl.contains(dom));
26219 if (this.currentEl == el) {
26222 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26228 if (this.currentTip.el) {
26229 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26233 if(!el || el.dom == document){
26239 // you can not look for children, as if el is the body.. then everythign is the child..
26240 if (!el.attr('tooltip')) { //
26241 if (!el.select("[tooltip]").elements.length) {
26244 // is the mouse over this child...?
26245 bindEl = el.select("[tooltip]").first();
26246 var xy = ev.getXY();
26247 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26248 //Roo.log("not in region.");
26251 //Roo.log("child element over..");
26254 this.currentEl = bindEl;
26255 this.currentTip.bind(bindEl);
26256 this.currentRegion = Roo.lib.Region.getRegion(dom);
26257 this.currentTip.enter();
26260 leave : function(ev)
26262 var dom = ev.getTarget();
26263 //Roo.log(['leave',dom]);
26264 if (!this.currentEl) {
26269 if (dom != this.currentEl.dom) {
26272 var xy = ev.getXY();
26273 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26276 // only activate leave if mouse cursor is outside... bounding box..
26281 if (this.currentTip) {
26282 this.currentTip.leave();
26284 //Roo.log('clear currentEl');
26285 this.currentEl = false;
26290 'left' : ['r-l', [-2,0], 'right'],
26291 'right' : ['l-r', [2,0], 'left'],
26292 'bottom' : ['t-b', [0,2], 'top'],
26293 'top' : [ 'b-t', [0,-2], 'bottom']
26299 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26304 delay : null, // can be { show : 300 , hide: 500}
26308 hoverState : null, //???
26310 placement : 'bottom',
26314 getAutoCreate : function(){
26321 cls : 'tooltip-arrow'
26324 cls : 'tooltip-inner'
26331 bind : function(el)
26337 enter : function () {
26339 if (this.timeout != null) {
26340 clearTimeout(this.timeout);
26343 this.hoverState = 'in';
26344 //Roo.log("enter - show");
26345 if (!this.delay || !this.delay.show) {
26350 this.timeout = setTimeout(function () {
26351 if (_t.hoverState == 'in') {
26354 }, this.delay.show);
26358 clearTimeout(this.timeout);
26360 this.hoverState = 'out';
26361 if (!this.delay || !this.delay.hide) {
26367 this.timeout = setTimeout(function () {
26368 //Roo.log("leave - timeout");
26370 if (_t.hoverState == 'out') {
26372 Roo.bootstrap.Tooltip.currentEl = false;
26377 show : function (msg)
26380 this.render(document.body);
26383 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26385 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26387 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26389 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26391 var placement = typeof this.placement == 'function' ?
26392 this.placement.call(this, this.el, on_el) :
26395 var autoToken = /\s?auto?\s?/i;
26396 var autoPlace = autoToken.test(placement);
26398 placement = placement.replace(autoToken, '') || 'top';
26402 //this.el.setXY([0,0]);
26404 //this.el.dom.style.display='block';
26406 //this.el.appendTo(on_el);
26408 var p = this.getPosition();
26409 var box = this.el.getBox();
26415 var align = this.alignment[placement];
26417 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26419 if(placement == 'top' || placement == 'bottom'){
26421 placement = 'right';
26424 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26425 placement = 'left';
26428 var scroll = Roo.select('body', true).first().getScroll();
26430 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26434 align = this.alignment[placement];
26437 this.el.alignTo(this.bindEl, align[0],align[1]);
26438 //var arrow = this.el.select('.arrow',true).first();
26439 //arrow.set(align[2],
26441 this.el.addClass(placement);
26443 this.el.addClass('in fade');
26445 this.hoverState = null;
26447 if (this.el.hasClass('fade')) {
26458 //this.el.setXY([0,0]);
26459 this.el.removeClass('in');
26475 * @class Roo.bootstrap.LocationPicker
26476 * @extends Roo.bootstrap.Component
26477 * Bootstrap LocationPicker class
26478 * @cfg {Number} latitude Position when init default 0
26479 * @cfg {Number} longitude Position when init default 0
26480 * @cfg {Number} zoom default 15
26481 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26482 * @cfg {Boolean} mapTypeControl default false
26483 * @cfg {Boolean} disableDoubleClickZoom default false
26484 * @cfg {Boolean} scrollwheel default true
26485 * @cfg {Boolean} streetViewControl default false
26486 * @cfg {Number} radius default 0
26487 * @cfg {String} locationName
26488 * @cfg {Boolean} draggable default true
26489 * @cfg {Boolean} enableAutocomplete default false
26490 * @cfg {Boolean} enableReverseGeocode default true
26491 * @cfg {String} markerTitle
26494 * Create a new LocationPicker
26495 * @param {Object} config The config object
26499 Roo.bootstrap.LocationPicker = function(config){
26501 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26506 * Fires when the picker initialized.
26507 * @param {Roo.bootstrap.LocationPicker} this
26508 * @param {Google Location} location
26512 * @event positionchanged
26513 * Fires when the picker position changed.
26514 * @param {Roo.bootstrap.LocationPicker} this
26515 * @param {Google Location} location
26517 positionchanged : true,
26520 * Fires when the map resize.
26521 * @param {Roo.bootstrap.LocationPicker} this
26526 * Fires when the map show.
26527 * @param {Roo.bootstrap.LocationPicker} this
26532 * Fires when the map hide.
26533 * @param {Roo.bootstrap.LocationPicker} this
26538 * Fires when click the map.
26539 * @param {Roo.bootstrap.LocationPicker} this
26540 * @param {Map event} e
26544 * @event mapRightClick
26545 * Fires when right click the map.
26546 * @param {Roo.bootstrap.LocationPicker} this
26547 * @param {Map event} e
26549 mapRightClick : true,
26551 * @event markerClick
26552 * Fires when click the marker.
26553 * @param {Roo.bootstrap.LocationPicker} this
26554 * @param {Map event} e
26556 markerClick : true,
26558 * @event markerRightClick
26559 * Fires when right click the marker.
26560 * @param {Roo.bootstrap.LocationPicker} this
26561 * @param {Map event} e
26563 markerRightClick : true,
26565 * @event OverlayViewDraw
26566 * Fires when OverlayView Draw
26567 * @param {Roo.bootstrap.LocationPicker} this
26569 OverlayViewDraw : true,
26571 * @event OverlayViewOnAdd
26572 * Fires when OverlayView Draw
26573 * @param {Roo.bootstrap.LocationPicker} this
26575 OverlayViewOnAdd : true,
26577 * @event OverlayViewOnRemove
26578 * Fires when OverlayView Draw
26579 * @param {Roo.bootstrap.LocationPicker} this
26581 OverlayViewOnRemove : true,
26583 * @event OverlayViewShow
26584 * Fires when OverlayView Draw
26585 * @param {Roo.bootstrap.LocationPicker} this
26586 * @param {Pixel} cpx
26588 OverlayViewShow : true,
26590 * @event OverlayViewHide
26591 * Fires when OverlayView Draw
26592 * @param {Roo.bootstrap.LocationPicker} this
26594 OverlayViewHide : true,
26596 * @event loadexception
26597 * Fires when load google lib failed.
26598 * @param {Roo.bootstrap.LocationPicker} this
26600 loadexception : true
26605 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26607 gMapContext: false,
26613 mapTypeControl: false,
26614 disableDoubleClickZoom: false,
26616 streetViewControl: false,
26620 enableAutocomplete: false,
26621 enableReverseGeocode: true,
26624 getAutoCreate: function()
26629 cls: 'roo-location-picker'
26635 initEvents: function(ct, position)
26637 if(!this.el.getWidth() || this.isApplied()){
26641 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26646 initial: function()
26648 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26649 this.fireEvent('loadexception', this);
26653 if(!this.mapTypeId){
26654 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26657 this.gMapContext = this.GMapContext();
26659 this.initOverlayView();
26661 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26665 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26666 _this.setPosition(_this.gMapContext.marker.position);
26669 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26670 _this.fireEvent('mapClick', this, event);
26674 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26675 _this.fireEvent('mapRightClick', this, event);
26679 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26680 _this.fireEvent('markerClick', this, event);
26684 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26685 _this.fireEvent('markerRightClick', this, event);
26689 this.setPosition(this.gMapContext.location);
26691 this.fireEvent('initial', this, this.gMapContext.location);
26694 initOverlayView: function()
26698 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26702 _this.fireEvent('OverlayViewDraw', _this);
26707 _this.fireEvent('OverlayViewOnAdd', _this);
26710 onRemove: function()
26712 _this.fireEvent('OverlayViewOnRemove', _this);
26715 show: function(cpx)
26717 _this.fireEvent('OverlayViewShow', _this, cpx);
26722 _this.fireEvent('OverlayViewHide', _this);
26728 fromLatLngToContainerPixel: function(event)
26730 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26733 isApplied: function()
26735 return this.getGmapContext() == false ? false : true;
26738 getGmapContext: function()
26740 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26743 GMapContext: function()
26745 var position = new google.maps.LatLng(this.latitude, this.longitude);
26747 var _map = new google.maps.Map(this.el.dom, {
26750 mapTypeId: this.mapTypeId,
26751 mapTypeControl: this.mapTypeControl,
26752 disableDoubleClickZoom: this.disableDoubleClickZoom,
26753 scrollwheel: this.scrollwheel,
26754 streetViewControl: this.streetViewControl,
26755 locationName: this.locationName,
26756 draggable: this.draggable,
26757 enableAutocomplete: this.enableAutocomplete,
26758 enableReverseGeocode: this.enableReverseGeocode
26761 var _marker = new google.maps.Marker({
26762 position: position,
26764 title: this.markerTitle,
26765 draggable: this.draggable
26772 location: position,
26773 radius: this.radius,
26774 locationName: this.locationName,
26775 addressComponents: {
26776 formatted_address: null,
26777 addressLine1: null,
26778 addressLine2: null,
26780 streetNumber: null,
26784 stateOrProvince: null
26787 domContainer: this.el.dom,
26788 geodecoder: new google.maps.Geocoder()
26792 drawCircle: function(center, radius, options)
26794 if (this.gMapContext.circle != null) {
26795 this.gMapContext.circle.setMap(null);
26799 options = Roo.apply({}, options, {
26800 strokeColor: "#0000FF",
26801 strokeOpacity: .35,
26803 fillColor: "#0000FF",
26807 options.map = this.gMapContext.map;
26808 options.radius = radius;
26809 options.center = center;
26810 this.gMapContext.circle = new google.maps.Circle(options);
26811 return this.gMapContext.circle;
26817 setPosition: function(location)
26819 this.gMapContext.location = location;
26820 this.gMapContext.marker.setPosition(location);
26821 this.gMapContext.map.panTo(location);
26822 this.drawCircle(location, this.gMapContext.radius, {});
26826 if (this.gMapContext.settings.enableReverseGeocode) {
26827 this.gMapContext.geodecoder.geocode({
26828 latLng: this.gMapContext.location
26829 }, function(results, status) {
26831 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26832 _this.gMapContext.locationName = results[0].formatted_address;
26833 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26835 _this.fireEvent('positionchanged', this, location);
26842 this.fireEvent('positionchanged', this, location);
26847 google.maps.event.trigger(this.gMapContext.map, "resize");
26849 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26851 this.fireEvent('resize', this);
26854 setPositionByLatLng: function(latitude, longitude)
26856 this.setPosition(new google.maps.LatLng(latitude, longitude));
26859 getCurrentPosition: function()
26862 latitude: this.gMapContext.location.lat(),
26863 longitude: this.gMapContext.location.lng()
26867 getAddressName: function()
26869 return this.gMapContext.locationName;
26872 getAddressComponents: function()
26874 return this.gMapContext.addressComponents;
26877 address_component_from_google_geocode: function(address_components)
26881 for (var i = 0; i < address_components.length; i++) {
26882 var component = address_components[i];
26883 if (component.types.indexOf("postal_code") >= 0) {
26884 result.postalCode = component.short_name;
26885 } else if (component.types.indexOf("street_number") >= 0) {
26886 result.streetNumber = component.short_name;
26887 } else if (component.types.indexOf("route") >= 0) {
26888 result.streetName = component.short_name;
26889 } else if (component.types.indexOf("neighborhood") >= 0) {
26890 result.city = component.short_name;
26891 } else if (component.types.indexOf("locality") >= 0) {
26892 result.city = component.short_name;
26893 } else if (component.types.indexOf("sublocality") >= 0) {
26894 result.district = component.short_name;
26895 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26896 result.stateOrProvince = component.short_name;
26897 } else if (component.types.indexOf("country") >= 0) {
26898 result.country = component.short_name;
26902 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26903 result.addressLine2 = "";
26907 setZoomLevel: function(zoom)
26909 this.gMapContext.map.setZoom(zoom);
26922 this.fireEvent('show', this);
26933 this.fireEvent('hide', this);
26938 Roo.apply(Roo.bootstrap.LocationPicker, {
26940 OverlayView : function(map, options)
26942 options = options || {};
26956 * @class Roo.bootstrap.Alert
26957 * @extends Roo.bootstrap.Component
26958 * Bootstrap Alert class
26959 * @cfg {String} title The title of alert
26960 * @cfg {String} html The content of alert
26961 * @cfg {String} weight ( success | info | warning | danger )
26962 * @cfg {String} faicon font-awesomeicon
26965 * Create a new alert
26966 * @param {Object} config The config object
26970 Roo.bootstrap.Alert = function(config){
26971 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26975 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26982 getAutoCreate : function()
26991 cls : 'roo-alert-icon'
26996 cls : 'roo-alert-title',
27001 cls : 'roo-alert-text',
27008 cfg.cn[0].cls += ' fa ' + this.faicon;
27012 cfg.cls += ' alert-' + this.weight;
27018 initEvents: function()
27020 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27023 setTitle : function(str)
27025 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27028 setText : function(str)
27030 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27033 setWeight : function(weight)
27036 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27039 this.weight = weight;
27041 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27044 setIcon : function(icon)
27047 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27050 this.faicon = icon;
27052 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27073 * @class Roo.bootstrap.UploadCropbox
27074 * @extends Roo.bootstrap.Component
27075 * Bootstrap UploadCropbox class
27076 * @cfg {String} emptyText show when image has been loaded
27077 * @cfg {String} rotateNotify show when image too small to rotate
27078 * @cfg {Number} errorTimeout default 3000
27079 * @cfg {Number} minWidth default 300
27080 * @cfg {Number} minHeight default 300
27081 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27082 * @cfg {Boolean} isDocument (true|false) default false
27083 * @cfg {String} url action url
27084 * @cfg {String} paramName default 'imageUpload'
27085 * @cfg {String} method default POST
27086 * @cfg {Boolean} loadMask (true|false) default true
27087 * @cfg {Boolean} loadingText default 'Loading...'
27090 * Create a new UploadCropbox
27091 * @param {Object} config The config object
27094 Roo.bootstrap.UploadCropbox = function(config){
27095 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27099 * @event beforeselectfile
27100 * Fire before select file
27101 * @param {Roo.bootstrap.UploadCropbox} this
27103 "beforeselectfile" : true,
27106 * Fire after initEvent
27107 * @param {Roo.bootstrap.UploadCropbox} this
27112 * Fire after initEvent
27113 * @param {Roo.bootstrap.UploadCropbox} this
27114 * @param {String} data
27119 * Fire when preparing the file data
27120 * @param {Roo.bootstrap.UploadCropbox} this
27121 * @param {Object} file
27126 * Fire when get exception
27127 * @param {Roo.bootstrap.UploadCropbox} this
27128 * @param {XMLHttpRequest} xhr
27130 "exception" : true,
27132 * @event beforeloadcanvas
27133 * Fire before load the canvas
27134 * @param {Roo.bootstrap.UploadCropbox} this
27135 * @param {String} src
27137 "beforeloadcanvas" : true,
27140 * Fire when trash image
27141 * @param {Roo.bootstrap.UploadCropbox} this
27146 * Fire when download the image
27147 * @param {Roo.bootstrap.UploadCropbox} this
27151 * @event footerbuttonclick
27152 * Fire when footerbuttonclick
27153 * @param {Roo.bootstrap.UploadCropbox} this
27154 * @param {String} type
27156 "footerbuttonclick" : true,
27160 * @param {Roo.bootstrap.UploadCropbox} this
27165 * Fire when rotate the image
27166 * @param {Roo.bootstrap.UploadCropbox} this
27167 * @param {String} pos
27172 * Fire when inspect the file
27173 * @param {Roo.bootstrap.UploadCropbox} this
27174 * @param {Object} file
27179 * Fire when xhr upload the file
27180 * @param {Roo.bootstrap.UploadCropbox} this
27181 * @param {Object} data
27186 * Fire when arrange the file data
27187 * @param {Roo.bootstrap.UploadCropbox} this
27188 * @param {Object} formData
27193 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27196 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27198 emptyText : 'Click to upload image',
27199 rotateNotify : 'Image is too small to rotate',
27200 errorTimeout : 3000,
27214 cropType : 'image/jpeg',
27216 canvasLoaded : false,
27217 isDocument : false,
27219 paramName : 'imageUpload',
27221 loadingText : 'Loading...',
27224 getAutoCreate : function()
27228 cls : 'roo-upload-cropbox',
27232 cls : 'roo-upload-cropbox-selector',
27237 cls : 'roo-upload-cropbox-body',
27238 style : 'cursor:pointer',
27242 cls : 'roo-upload-cropbox-preview'
27246 cls : 'roo-upload-cropbox-thumb'
27250 cls : 'roo-upload-cropbox-empty-notify',
27251 html : this.emptyText
27255 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27256 html : this.rotateNotify
27262 cls : 'roo-upload-cropbox-footer',
27265 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27275 onRender : function(ct, position)
27277 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27279 if (this.buttons.length) {
27281 Roo.each(this.buttons, function(bb) {
27283 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27285 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27291 this.maskEl = this.el;
27295 initEvents : function()
27297 this.urlAPI = (window.createObjectURL && window) ||
27298 (window.URL && URL.revokeObjectURL && URL) ||
27299 (window.webkitURL && webkitURL);
27301 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27302 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27304 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27305 this.selectorEl.hide();
27307 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27308 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27310 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27311 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27312 this.thumbEl.hide();
27314 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27315 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27317 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27318 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27319 this.errorEl.hide();
27321 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27322 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27323 this.footerEl.hide();
27325 this.setThumbBoxSize();
27331 this.fireEvent('initial', this);
27338 window.addEventListener("resize", function() { _this.resize(); } );
27340 this.bodyEl.on('click', this.beforeSelectFile, this);
27343 this.bodyEl.on('touchstart', this.onTouchStart, this);
27344 this.bodyEl.on('touchmove', this.onTouchMove, this);
27345 this.bodyEl.on('touchend', this.onTouchEnd, this);
27349 this.bodyEl.on('mousedown', this.onMouseDown, this);
27350 this.bodyEl.on('mousemove', this.onMouseMove, this);
27351 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27352 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27353 Roo.get(document).on('mouseup', this.onMouseUp, this);
27356 this.selectorEl.on('change', this.onFileSelected, this);
27362 this.baseScale = 1;
27364 this.baseRotate = 1;
27365 this.dragable = false;
27366 this.pinching = false;
27369 this.cropData = false;
27370 this.notifyEl.dom.innerHTML = this.emptyText;
27372 this.selectorEl.dom.value = '';
27376 resize : function()
27378 if(this.fireEvent('resize', this) != false){
27379 this.setThumbBoxPosition();
27380 this.setCanvasPosition();
27384 onFooterButtonClick : function(e, el, o, type)
27387 case 'rotate-left' :
27388 this.onRotateLeft(e);
27390 case 'rotate-right' :
27391 this.onRotateRight(e);
27394 this.beforeSelectFile(e);
27409 this.fireEvent('footerbuttonclick', this, type);
27412 beforeSelectFile : function(e)
27414 e.preventDefault();
27416 if(this.fireEvent('beforeselectfile', this) != false){
27417 this.selectorEl.dom.click();
27421 onFileSelected : function(e)
27423 e.preventDefault();
27425 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27429 var file = this.selectorEl.dom.files[0];
27431 if(this.fireEvent('inspect', this, file) != false){
27432 this.prepare(file);
27437 trash : function(e)
27439 this.fireEvent('trash', this);
27442 download : function(e)
27444 this.fireEvent('download', this);
27447 loadCanvas : function(src)
27449 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27453 this.imageEl = document.createElement('img');
27457 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27459 this.imageEl.src = src;
27463 onLoadCanvas : function()
27465 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27466 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27468 this.bodyEl.un('click', this.beforeSelectFile, this);
27470 this.notifyEl.hide();
27471 this.thumbEl.show();
27472 this.footerEl.show();
27474 this.baseRotateLevel();
27476 if(this.isDocument){
27477 this.setThumbBoxSize();
27480 this.setThumbBoxPosition();
27482 this.baseScaleLevel();
27488 this.canvasLoaded = true;
27491 this.maskEl.unmask();
27496 setCanvasPosition : function()
27498 if(!this.canvasEl){
27502 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27503 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27505 this.previewEl.setLeft(pw);
27506 this.previewEl.setTop(ph);
27510 onMouseDown : function(e)
27514 this.dragable = true;
27515 this.pinching = false;
27517 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27518 this.dragable = false;
27522 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27523 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27527 onMouseMove : function(e)
27531 if(!this.canvasLoaded){
27535 if (!this.dragable){
27539 var minX = Math.ceil(this.thumbEl.getLeft(true));
27540 var minY = Math.ceil(this.thumbEl.getTop(true));
27542 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27543 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27545 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27546 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27548 x = x - this.mouseX;
27549 y = y - this.mouseY;
27551 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27552 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27554 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27555 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27557 this.previewEl.setLeft(bgX);
27558 this.previewEl.setTop(bgY);
27560 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27561 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27564 onMouseUp : function(e)
27568 this.dragable = false;
27571 onMouseWheel : function(e)
27575 this.startScale = this.scale;
27577 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27579 if(!this.zoomable()){
27580 this.scale = this.startScale;
27589 zoomable : function()
27591 var minScale = this.thumbEl.getWidth() / this.minWidth;
27593 if(this.minWidth < this.minHeight){
27594 minScale = this.thumbEl.getHeight() / this.minHeight;
27597 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27598 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27602 (this.rotate == 0 || this.rotate == 180) &&
27604 width > this.imageEl.OriginWidth ||
27605 height > this.imageEl.OriginHeight ||
27606 (width < this.minWidth && height < this.minHeight)
27614 (this.rotate == 90 || this.rotate == 270) &&
27616 width > this.imageEl.OriginWidth ||
27617 height > this.imageEl.OriginHeight ||
27618 (width < this.minHeight && height < this.minWidth)
27625 !this.isDocument &&
27626 (this.rotate == 0 || this.rotate == 180) &&
27628 width < this.minWidth ||
27629 width > this.imageEl.OriginWidth ||
27630 height < this.minHeight ||
27631 height > this.imageEl.OriginHeight
27638 !this.isDocument &&
27639 (this.rotate == 90 || this.rotate == 270) &&
27641 width < this.minHeight ||
27642 width > this.imageEl.OriginWidth ||
27643 height < this.minWidth ||
27644 height > this.imageEl.OriginHeight
27654 onRotateLeft : function(e)
27656 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27658 var minScale = this.thumbEl.getWidth() / this.minWidth;
27660 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27661 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27663 this.startScale = this.scale;
27665 while (this.getScaleLevel() < minScale){
27667 this.scale = this.scale + 1;
27669 if(!this.zoomable()){
27674 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27675 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27680 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27687 this.scale = this.startScale;
27689 this.onRotateFail();
27694 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27696 if(this.isDocument){
27697 this.setThumbBoxSize();
27698 this.setThumbBoxPosition();
27699 this.setCanvasPosition();
27704 this.fireEvent('rotate', this, 'left');
27708 onRotateRight : function(e)
27710 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27712 var minScale = this.thumbEl.getWidth() / this.minWidth;
27714 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27715 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27717 this.startScale = this.scale;
27719 while (this.getScaleLevel() < minScale){
27721 this.scale = this.scale + 1;
27723 if(!this.zoomable()){
27728 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27729 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27734 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27741 this.scale = this.startScale;
27743 this.onRotateFail();
27748 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27750 if(this.isDocument){
27751 this.setThumbBoxSize();
27752 this.setThumbBoxPosition();
27753 this.setCanvasPosition();
27758 this.fireEvent('rotate', this, 'right');
27761 onRotateFail : function()
27763 this.errorEl.show(true);
27767 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27772 this.previewEl.dom.innerHTML = '';
27774 var canvasEl = document.createElement("canvas");
27776 var contextEl = canvasEl.getContext("2d");
27778 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27779 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27780 var center = this.imageEl.OriginWidth / 2;
27782 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27783 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27784 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27785 center = this.imageEl.OriginHeight / 2;
27788 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27790 contextEl.translate(center, center);
27791 contextEl.rotate(this.rotate * Math.PI / 180);
27793 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27795 this.canvasEl = document.createElement("canvas");
27797 this.contextEl = this.canvasEl.getContext("2d");
27799 switch (this.rotate) {
27802 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27803 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
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.OriginHeight * this.getScaleLevel();
27811 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27813 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27814 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);
27818 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27823 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27824 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27826 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27827 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);
27831 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);
27836 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27837 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27839 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27840 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27844 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);
27851 this.previewEl.appendChild(this.canvasEl);
27853 this.setCanvasPosition();
27858 if(!this.canvasLoaded){
27862 var imageCanvas = document.createElement("canvas");
27864 var imageContext = imageCanvas.getContext("2d");
27866 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27867 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27869 var center = imageCanvas.width / 2;
27871 imageContext.translate(center, center);
27873 imageContext.rotate(this.rotate * Math.PI / 180);
27875 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27877 var canvas = document.createElement("canvas");
27879 var context = canvas.getContext("2d");
27881 canvas.width = this.minWidth;
27882 canvas.height = this.minHeight;
27884 switch (this.rotate) {
27887 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27888 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27890 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27891 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27893 var targetWidth = this.minWidth - 2 * x;
27894 var targetHeight = this.minHeight - 2 * y;
27898 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27899 scale = targetWidth / width;
27902 if(x > 0 && y == 0){
27903 scale = targetHeight / height;
27906 if(x > 0 && y > 0){
27907 scale = targetWidth / width;
27909 if(width < height){
27910 scale = targetHeight / height;
27914 context.scale(scale, scale);
27916 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27917 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27919 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27920 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27922 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27927 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27928 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27930 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27931 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27933 var targetWidth = this.minWidth - 2 * x;
27934 var targetHeight = this.minHeight - 2 * y;
27938 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27939 scale = targetWidth / width;
27942 if(x > 0 && y == 0){
27943 scale = targetHeight / height;
27946 if(x > 0 && y > 0){
27947 scale = targetWidth / width;
27949 if(width < height){
27950 scale = targetHeight / height;
27954 context.scale(scale, scale);
27956 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27957 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27959 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27960 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27962 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27964 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27969 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27970 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27972 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27973 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27975 var targetWidth = this.minWidth - 2 * x;
27976 var targetHeight = this.minHeight - 2 * y;
27980 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27981 scale = targetWidth / width;
27984 if(x > 0 && y == 0){
27985 scale = targetHeight / height;
27988 if(x > 0 && y > 0){
27989 scale = targetWidth / width;
27991 if(width < height){
27992 scale = targetHeight / height;
27996 context.scale(scale, scale);
27998 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27999 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28001 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28002 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28004 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28005 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28007 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28012 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28013 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28015 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28016 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28018 var targetWidth = this.minWidth - 2 * x;
28019 var targetHeight = this.minHeight - 2 * y;
28023 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28024 scale = targetWidth / width;
28027 if(x > 0 && y == 0){
28028 scale = targetHeight / height;
28031 if(x > 0 && y > 0){
28032 scale = targetWidth / width;
28034 if(width < height){
28035 scale = targetHeight / height;
28039 context.scale(scale, scale);
28041 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28042 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28044 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28045 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28047 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28049 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28056 this.cropData = canvas.toDataURL(this.cropType);
28058 if(this.fireEvent('crop', this, this.cropData) !== false){
28059 this.process(this.file, this.cropData);
28066 setThumbBoxSize : function()
28070 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28071 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28072 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28074 this.minWidth = width;
28075 this.minHeight = height;
28077 if(this.rotate == 90 || this.rotate == 270){
28078 this.minWidth = height;
28079 this.minHeight = width;
28084 width = Math.ceil(this.minWidth * height / this.minHeight);
28086 if(this.minWidth > this.minHeight){
28088 height = Math.ceil(this.minHeight * width / this.minWidth);
28091 this.thumbEl.setStyle({
28092 width : width + 'px',
28093 height : height + 'px'
28100 setThumbBoxPosition : function()
28102 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28103 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28105 this.thumbEl.setLeft(x);
28106 this.thumbEl.setTop(y);
28110 baseRotateLevel : function()
28112 this.baseRotate = 1;
28115 typeof(this.exif) != 'undefined' &&
28116 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28117 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28119 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28122 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28126 baseScaleLevel : function()
28130 if(this.isDocument){
28132 if(this.baseRotate == 6 || this.baseRotate == 8){
28134 height = this.thumbEl.getHeight();
28135 this.baseScale = height / this.imageEl.OriginWidth;
28137 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28138 width = this.thumbEl.getWidth();
28139 this.baseScale = width / this.imageEl.OriginHeight;
28145 height = this.thumbEl.getHeight();
28146 this.baseScale = height / this.imageEl.OriginHeight;
28148 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28149 width = this.thumbEl.getWidth();
28150 this.baseScale = width / this.imageEl.OriginWidth;
28156 if(this.baseRotate == 6 || this.baseRotate == 8){
28158 width = this.thumbEl.getHeight();
28159 this.baseScale = width / this.imageEl.OriginHeight;
28161 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28162 height = this.thumbEl.getWidth();
28163 this.baseScale = height / this.imageEl.OriginHeight;
28166 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28167 height = this.thumbEl.getWidth();
28168 this.baseScale = height / this.imageEl.OriginHeight;
28170 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28171 width = this.thumbEl.getHeight();
28172 this.baseScale = width / this.imageEl.OriginWidth;
28179 width = this.thumbEl.getWidth();
28180 this.baseScale = width / this.imageEl.OriginWidth;
28182 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28183 height = this.thumbEl.getHeight();
28184 this.baseScale = height / this.imageEl.OriginHeight;
28187 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28189 height = this.thumbEl.getHeight();
28190 this.baseScale = height / this.imageEl.OriginHeight;
28192 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28193 width = this.thumbEl.getWidth();
28194 this.baseScale = width / this.imageEl.OriginWidth;
28202 getScaleLevel : function()
28204 return this.baseScale * Math.pow(1.1, this.scale);
28207 onTouchStart : function(e)
28209 if(!this.canvasLoaded){
28210 this.beforeSelectFile(e);
28214 var touches = e.browserEvent.touches;
28220 if(touches.length == 1){
28221 this.onMouseDown(e);
28225 if(touches.length != 2){
28231 for(var i = 0, finger; finger = touches[i]; i++){
28232 coords.push(finger.pageX, finger.pageY);
28235 var x = Math.pow(coords[0] - coords[2], 2);
28236 var y = Math.pow(coords[1] - coords[3], 2);
28238 this.startDistance = Math.sqrt(x + y);
28240 this.startScale = this.scale;
28242 this.pinching = true;
28243 this.dragable = false;
28247 onTouchMove : function(e)
28249 if(!this.pinching && !this.dragable){
28253 var touches = e.browserEvent.touches;
28260 this.onMouseMove(e);
28266 for(var i = 0, finger; finger = touches[i]; i++){
28267 coords.push(finger.pageX, finger.pageY);
28270 var x = Math.pow(coords[0] - coords[2], 2);
28271 var y = Math.pow(coords[1] - coords[3], 2);
28273 this.endDistance = Math.sqrt(x + y);
28275 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28277 if(!this.zoomable()){
28278 this.scale = this.startScale;
28286 onTouchEnd : function(e)
28288 this.pinching = false;
28289 this.dragable = false;
28293 process : function(file, crop)
28296 this.maskEl.mask(this.loadingText);
28299 this.xhr = new XMLHttpRequest();
28301 file.xhr = this.xhr;
28303 this.xhr.open(this.method, this.url, true);
28306 "Accept": "application/json",
28307 "Cache-Control": "no-cache",
28308 "X-Requested-With": "XMLHttpRequest"
28311 for (var headerName in headers) {
28312 var headerValue = headers[headerName];
28314 this.xhr.setRequestHeader(headerName, headerValue);
28320 this.xhr.onload = function()
28322 _this.xhrOnLoad(_this.xhr);
28325 this.xhr.onerror = function()
28327 _this.xhrOnError(_this.xhr);
28330 var formData = new FormData();
28332 formData.append('returnHTML', 'NO');
28335 formData.append('crop', crop);
28338 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28339 formData.append(this.paramName, file, file.name);
28342 if(typeof(file.filename) != 'undefined'){
28343 formData.append('filename', file.filename);
28346 if(typeof(file.mimetype) != 'undefined'){
28347 formData.append('mimetype', file.mimetype);
28350 if(this.fireEvent('arrange', this, formData) != false){
28351 this.xhr.send(formData);
28355 xhrOnLoad : function(xhr)
28358 this.maskEl.unmask();
28361 if (xhr.readyState !== 4) {
28362 this.fireEvent('exception', this, xhr);
28366 var response = Roo.decode(xhr.responseText);
28368 if(!response.success){
28369 this.fireEvent('exception', this, xhr);
28373 var response = Roo.decode(xhr.responseText);
28375 this.fireEvent('upload', this, response);
28379 xhrOnError : function()
28382 this.maskEl.unmask();
28385 Roo.log('xhr on error');
28387 var response = Roo.decode(xhr.responseText);
28393 prepare : function(file)
28396 this.maskEl.mask(this.loadingText);
28402 if(typeof(file) === 'string'){
28403 this.loadCanvas(file);
28407 if(!file || !this.urlAPI){
28412 this.cropType = file.type;
28416 if(this.fireEvent('prepare', this, this.file) != false){
28418 var reader = new FileReader();
28420 reader.onload = function (e) {
28421 if (e.target.error) {
28422 Roo.log(e.target.error);
28426 var buffer = e.target.result,
28427 dataView = new DataView(buffer),
28429 maxOffset = dataView.byteLength - 4,
28433 if (dataView.getUint16(0) === 0xffd8) {
28434 while (offset < maxOffset) {
28435 markerBytes = dataView.getUint16(offset);
28437 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28438 markerLength = dataView.getUint16(offset + 2) + 2;
28439 if (offset + markerLength > dataView.byteLength) {
28440 Roo.log('Invalid meta data: Invalid segment size.');
28444 if(markerBytes == 0xffe1){
28445 _this.parseExifData(
28452 offset += markerLength;
28462 var url = _this.urlAPI.createObjectURL(_this.file);
28464 _this.loadCanvas(url);
28469 reader.readAsArrayBuffer(this.file);
28475 parseExifData : function(dataView, offset, length)
28477 var tiffOffset = offset + 10,
28481 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28482 // No Exif data, might be XMP data instead
28486 // Check for the ASCII code for "Exif" (0x45786966):
28487 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28488 // No Exif data, might be XMP data instead
28491 if (tiffOffset + 8 > dataView.byteLength) {
28492 Roo.log('Invalid Exif data: Invalid segment size.');
28495 // Check for the two null bytes:
28496 if (dataView.getUint16(offset + 8) !== 0x0000) {
28497 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28500 // Check the byte alignment:
28501 switch (dataView.getUint16(tiffOffset)) {
28503 littleEndian = true;
28506 littleEndian = false;
28509 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28512 // Check for the TIFF tag marker (0x002A):
28513 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28514 Roo.log('Invalid Exif data: Missing TIFF marker.');
28517 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28518 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28520 this.parseExifTags(
28523 tiffOffset + dirOffset,
28528 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28533 if (dirOffset + 6 > dataView.byteLength) {
28534 Roo.log('Invalid Exif data: Invalid directory offset.');
28537 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28538 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28539 if (dirEndOffset + 4 > dataView.byteLength) {
28540 Roo.log('Invalid Exif data: Invalid directory size.');
28543 for (i = 0; i < tagsNumber; i += 1) {
28547 dirOffset + 2 + 12 * i, // tag offset
28551 // Return the offset to the next directory:
28552 return dataView.getUint32(dirEndOffset, littleEndian);
28555 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28557 var tag = dataView.getUint16(offset, littleEndian);
28559 this.exif[tag] = this.getExifValue(
28563 dataView.getUint16(offset + 2, littleEndian), // tag type
28564 dataView.getUint32(offset + 4, littleEndian), // tag length
28569 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28571 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28580 Roo.log('Invalid Exif data: Invalid tag type.');
28584 tagSize = tagType.size * length;
28585 // Determine if the value is contained in the dataOffset bytes,
28586 // or if the value at the dataOffset is a pointer to the actual data:
28587 dataOffset = tagSize > 4 ?
28588 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28589 if (dataOffset + tagSize > dataView.byteLength) {
28590 Roo.log('Invalid Exif data: Invalid data offset.');
28593 if (length === 1) {
28594 return tagType.getValue(dataView, dataOffset, littleEndian);
28597 for (i = 0; i < length; i += 1) {
28598 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28601 if (tagType.ascii) {
28603 // Concatenate the chars:
28604 for (i = 0; i < values.length; i += 1) {
28606 // Ignore the terminating NULL byte(s):
28607 if (c === '\u0000') {
28619 Roo.apply(Roo.bootstrap.UploadCropbox, {
28621 'Orientation': 0x0112
28625 1: 0, //'top-left',
28627 3: 180, //'bottom-right',
28628 // 4: 'bottom-left',
28630 6: 90, //'right-top',
28631 // 7: 'right-bottom',
28632 8: 270 //'left-bottom'
28636 // byte, 8-bit unsigned int:
28638 getValue: function (dataView, dataOffset) {
28639 return dataView.getUint8(dataOffset);
28643 // ascii, 8-bit byte:
28645 getValue: function (dataView, dataOffset) {
28646 return String.fromCharCode(dataView.getUint8(dataOffset));
28651 // short, 16 bit int:
28653 getValue: function (dataView, dataOffset, littleEndian) {
28654 return dataView.getUint16(dataOffset, littleEndian);
28658 // long, 32 bit int:
28660 getValue: function (dataView, dataOffset, littleEndian) {
28661 return dataView.getUint32(dataOffset, littleEndian);
28665 // rational = two long values, first is numerator, second is denominator:
28667 getValue: function (dataView, dataOffset, littleEndian) {
28668 return dataView.getUint32(dataOffset, littleEndian) /
28669 dataView.getUint32(dataOffset + 4, littleEndian);
28673 // slong, 32 bit signed int:
28675 getValue: function (dataView, dataOffset, littleEndian) {
28676 return dataView.getInt32(dataOffset, littleEndian);
28680 // srational, two slongs, first is numerator, second is denominator:
28682 getValue: function (dataView, dataOffset, littleEndian) {
28683 return dataView.getInt32(dataOffset, littleEndian) /
28684 dataView.getInt32(dataOffset + 4, littleEndian);
28694 cls : 'btn-group roo-upload-cropbox-rotate-left',
28695 action : 'rotate-left',
28699 cls : 'btn btn-default',
28700 html : '<i class="fa fa-undo"></i>'
28706 cls : 'btn-group roo-upload-cropbox-picture',
28707 action : 'picture',
28711 cls : 'btn btn-default',
28712 html : '<i class="fa fa-picture-o"></i>'
28718 cls : 'btn-group roo-upload-cropbox-rotate-right',
28719 action : 'rotate-right',
28723 cls : 'btn btn-default',
28724 html : '<i class="fa fa-repeat"></i>'
28732 cls : 'btn-group roo-upload-cropbox-rotate-left',
28733 action : 'rotate-left',
28737 cls : 'btn btn-default',
28738 html : '<i class="fa fa-undo"></i>'
28744 cls : 'btn-group roo-upload-cropbox-download',
28745 action : 'download',
28749 cls : 'btn btn-default',
28750 html : '<i class="fa fa-download"></i>'
28756 cls : 'btn-group roo-upload-cropbox-crop',
28761 cls : 'btn btn-default',
28762 html : '<i class="fa fa-crop"></i>'
28768 cls : 'btn-group roo-upload-cropbox-trash',
28773 cls : 'btn btn-default',
28774 html : '<i class="fa fa-trash"></i>'
28780 cls : 'btn-group roo-upload-cropbox-rotate-right',
28781 action : 'rotate-right',
28785 cls : 'btn btn-default',
28786 html : '<i class="fa fa-repeat"></i>'
28794 cls : 'btn-group roo-upload-cropbox-rotate-left',
28795 action : 'rotate-left',
28799 cls : 'btn btn-default',
28800 html : '<i class="fa fa-undo"></i>'
28806 cls : 'btn-group roo-upload-cropbox-rotate-right',
28807 action : 'rotate-right',
28811 cls : 'btn btn-default',
28812 html : '<i class="fa fa-repeat"></i>'
28825 * @class Roo.bootstrap.DocumentManager
28826 * @extends Roo.bootstrap.Component
28827 * Bootstrap DocumentManager class
28828 * @cfg {String} paramName default 'imageUpload'
28829 * @cfg {String} toolTipName default 'filename'
28830 * @cfg {String} method default POST
28831 * @cfg {String} url action url
28832 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28833 * @cfg {Boolean} multiple multiple upload default true
28834 * @cfg {Number} thumbSize default 300
28835 * @cfg {String} fieldLabel
28836 * @cfg {Number} labelWidth default 4
28837 * @cfg {String} labelAlign (left|top) default left
28838 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28839 * @cfg {Number} labellg set the width of label (1-12)
28840 * @cfg {Number} labelmd set the width of label (1-12)
28841 * @cfg {Number} labelsm set the width of label (1-12)
28842 * @cfg {Number} labelxs set the width of label (1-12)
28845 * Create a new DocumentManager
28846 * @param {Object} config The config object
28849 Roo.bootstrap.DocumentManager = function(config){
28850 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28853 this.delegates = [];
28858 * Fire when initial the DocumentManager
28859 * @param {Roo.bootstrap.DocumentManager} this
28864 * inspect selected file
28865 * @param {Roo.bootstrap.DocumentManager} this
28866 * @param {File} file
28871 * Fire when xhr load exception
28872 * @param {Roo.bootstrap.DocumentManager} this
28873 * @param {XMLHttpRequest} xhr
28875 "exception" : true,
28877 * @event afterupload
28878 * Fire when xhr load exception
28879 * @param {Roo.bootstrap.DocumentManager} this
28880 * @param {XMLHttpRequest} xhr
28882 "afterupload" : true,
28885 * prepare the form data
28886 * @param {Roo.bootstrap.DocumentManager} this
28887 * @param {Object} formData
28892 * Fire when remove the file
28893 * @param {Roo.bootstrap.DocumentManager} this
28894 * @param {Object} file
28899 * Fire after refresh the file
28900 * @param {Roo.bootstrap.DocumentManager} this
28905 * Fire after click the image
28906 * @param {Roo.bootstrap.DocumentManager} this
28907 * @param {Object} file
28912 * Fire when upload a image and editable set to true
28913 * @param {Roo.bootstrap.DocumentManager} this
28914 * @param {Object} file
28918 * @event beforeselectfile
28919 * Fire before select file
28920 * @param {Roo.bootstrap.DocumentManager} this
28922 "beforeselectfile" : true,
28925 * Fire before process file
28926 * @param {Roo.bootstrap.DocumentManager} this
28927 * @param {Object} file
28931 * @event previewrendered
28932 * Fire when preview rendered
28933 * @param {Roo.bootstrap.DocumentManager} this
28934 * @param {Object} file
28936 "previewrendered" : true,
28939 "previewResize" : true
28944 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28953 paramName : 'imageUpload',
28954 toolTipName : 'filename',
28957 labelAlign : 'left',
28967 getAutoCreate : function()
28969 var managerWidget = {
28971 cls : 'roo-document-manager',
28975 cls : 'roo-document-manager-selector',
28980 cls : 'roo-document-manager-uploader',
28984 cls : 'roo-document-manager-upload-btn',
28985 html : '<i class="fa fa-plus"></i>'
28996 cls : 'column col-md-12',
29001 if(this.fieldLabel.length){
29006 cls : 'column col-md-12',
29007 html : this.fieldLabel
29011 cls : 'column col-md-12',
29016 if(this.labelAlign == 'left'){
29021 html : this.fieldLabel
29030 if(this.labelWidth > 12){
29031 content[0].style = "width: " + this.labelWidth + 'px';
29034 if(this.labelWidth < 13 && this.labelmd == 0){
29035 this.labelmd = this.labelWidth;
29038 if(this.labellg > 0){
29039 content[0].cls += ' col-lg-' + this.labellg;
29040 content[1].cls += ' col-lg-' + (12 - this.labellg);
29043 if(this.labelmd > 0){
29044 content[0].cls += ' col-md-' + this.labelmd;
29045 content[1].cls += ' col-md-' + (12 - this.labelmd);
29048 if(this.labelsm > 0){
29049 content[0].cls += ' col-sm-' + this.labelsm;
29050 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29053 if(this.labelxs > 0){
29054 content[0].cls += ' col-xs-' + this.labelxs;
29055 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29063 cls : 'row clearfix',
29071 initEvents : function()
29073 this.managerEl = this.el.select('.roo-document-manager', true).first();
29074 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29076 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29077 this.selectorEl.hide();
29080 this.selectorEl.attr('multiple', 'multiple');
29083 this.selectorEl.on('change', this.onFileSelected, this);
29085 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29086 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29088 this.uploader.on('click', this.onUploaderClick, this);
29090 this.renderProgressDialog();
29094 window.addEventListener("resize", function() { _this.refresh(); } );
29096 this.fireEvent('initial', this);
29099 renderProgressDialog : function()
29103 this.progressDialog = new Roo.bootstrap.Modal({
29104 cls : 'roo-document-manager-progress-dialog',
29105 allow_close : false,
29115 btnclick : function() {
29116 _this.uploadCancel();
29122 this.progressDialog.render(Roo.get(document.body));
29124 this.progress = new Roo.bootstrap.Progress({
29125 cls : 'roo-document-manager-progress',
29130 this.progress.render(this.progressDialog.getChildContainer());
29132 this.progressBar = new Roo.bootstrap.ProgressBar({
29133 cls : 'roo-document-manager-progress-bar',
29136 aria_valuemax : 12,
29140 this.progressBar.render(this.progress.getChildContainer());
29143 onUploaderClick : function(e)
29145 e.preventDefault();
29147 if(this.fireEvent('beforeselectfile', this) != false){
29148 this.selectorEl.dom.click();
29153 onFileSelected : function(e)
29155 e.preventDefault();
29157 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29161 Roo.each(this.selectorEl.dom.files, function(file){
29162 if(this.fireEvent('inspect', this, file) != false){
29163 this.files.push(file);
29173 this.selectorEl.dom.value = '';
29175 if(!this.files || !this.files.length){
29179 if(this.boxes > 0 && this.files.length > this.boxes){
29180 this.files = this.files.slice(0, this.boxes);
29183 this.uploader.show();
29185 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29186 this.uploader.hide();
29195 Roo.each(this.files, function(file){
29197 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29198 var f = this.renderPreview(file);
29203 if(file.type.indexOf('image') != -1){
29204 this.delegates.push(
29206 _this.process(file);
29207 }).createDelegate(this)
29215 _this.process(file);
29216 }).createDelegate(this)
29221 this.files = files;
29223 this.delegates = this.delegates.concat(docs);
29225 if(!this.delegates.length){
29230 this.progressBar.aria_valuemax = this.delegates.length;
29237 arrange : function()
29239 if(!this.delegates.length){
29240 this.progressDialog.hide();
29245 var delegate = this.delegates.shift();
29247 this.progressDialog.show();
29249 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29251 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29256 refresh : function()
29258 this.uploader.show();
29260 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29261 this.uploader.hide();
29264 Roo.isTouch ? this.closable(false) : this.closable(true);
29266 this.fireEvent('refresh', this);
29269 onRemove : function(e, el, o)
29271 e.preventDefault();
29273 this.fireEvent('remove', this, o);
29277 remove : function(o)
29281 Roo.each(this.files, function(file){
29282 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29291 this.files = files;
29298 Roo.each(this.files, function(file){
29303 file.target.remove();
29312 onClick : function(e, el, o)
29314 e.preventDefault();
29316 this.fireEvent('click', this, o);
29320 closable : function(closable)
29322 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29324 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29336 xhrOnLoad : function(xhr)
29338 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29342 if (xhr.readyState !== 4) {
29344 this.fireEvent('exception', this, xhr);
29348 var response = Roo.decode(xhr.responseText);
29350 if(!response.success){
29352 this.fireEvent('exception', this, xhr);
29356 var file = this.renderPreview(response.data);
29358 this.files.push(file);
29362 this.fireEvent('afterupload', this, xhr);
29366 xhrOnError : function(xhr)
29368 Roo.log('xhr on error');
29370 var response = Roo.decode(xhr.responseText);
29377 process : function(file)
29379 if(this.fireEvent('process', this, file) !== false){
29380 if(this.editable && file.type.indexOf('image') != -1){
29381 this.fireEvent('edit', this, file);
29385 this.uploadStart(file, false);
29392 uploadStart : function(file, crop)
29394 this.xhr = new XMLHttpRequest();
29396 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29401 file.xhr = this.xhr;
29403 this.managerEl.createChild({
29405 cls : 'roo-document-manager-loading',
29409 tooltip : file.name,
29410 cls : 'roo-document-manager-thumb',
29411 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29417 this.xhr.open(this.method, this.url, true);
29420 "Accept": "application/json",
29421 "Cache-Control": "no-cache",
29422 "X-Requested-With": "XMLHttpRequest"
29425 for (var headerName in headers) {
29426 var headerValue = headers[headerName];
29428 this.xhr.setRequestHeader(headerName, headerValue);
29434 this.xhr.onload = function()
29436 _this.xhrOnLoad(_this.xhr);
29439 this.xhr.onerror = function()
29441 _this.xhrOnError(_this.xhr);
29444 var formData = new FormData();
29446 formData.append('returnHTML', 'NO');
29449 formData.append('crop', crop);
29452 formData.append(this.paramName, file, file.name);
29459 if(this.fireEvent('prepare', this, formData, options) != false){
29461 if(options.manually){
29465 this.xhr.send(formData);
29469 this.uploadCancel();
29472 uploadCancel : function()
29478 this.delegates = [];
29480 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29487 renderPreview : function(file)
29489 if(typeof(file.target) != 'undefined' && file.target){
29493 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29495 var previewEl = this.managerEl.createChild({
29497 cls : 'roo-document-manager-preview',
29501 tooltip : file[this.toolTipName],
29502 cls : 'roo-document-manager-thumb',
29503 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29508 html : '<i class="fa fa-times-circle"></i>'
29513 var close = previewEl.select('button.close', true).first();
29515 close.on('click', this.onRemove, this, file);
29517 file.target = previewEl;
29519 var image = previewEl.select('img', true).first();
29523 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29525 image.on('click', this.onClick, this, file);
29527 this.fireEvent('previewrendered', this, file);
29533 onPreviewLoad : function(file, image)
29535 if(typeof(file.target) == 'undefined' || !file.target){
29539 var width = image.dom.naturalWidth || image.dom.width;
29540 var height = image.dom.naturalHeight || image.dom.height;
29542 if(!this.previewResize) {
29546 if(width > height){
29547 file.target.addClass('wide');
29551 file.target.addClass('tall');
29556 uploadFromSource : function(file, crop)
29558 this.xhr = new XMLHttpRequest();
29560 this.managerEl.createChild({
29562 cls : 'roo-document-manager-loading',
29566 tooltip : file.name,
29567 cls : 'roo-document-manager-thumb',
29568 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29574 this.xhr.open(this.method, this.url, true);
29577 "Accept": "application/json",
29578 "Cache-Control": "no-cache",
29579 "X-Requested-With": "XMLHttpRequest"
29582 for (var headerName in headers) {
29583 var headerValue = headers[headerName];
29585 this.xhr.setRequestHeader(headerName, headerValue);
29591 this.xhr.onload = function()
29593 _this.xhrOnLoad(_this.xhr);
29596 this.xhr.onerror = function()
29598 _this.xhrOnError(_this.xhr);
29601 var formData = new FormData();
29603 formData.append('returnHTML', 'NO');
29605 formData.append('crop', crop);
29607 if(typeof(file.filename) != 'undefined'){
29608 formData.append('filename', file.filename);
29611 if(typeof(file.mimetype) != 'undefined'){
29612 formData.append('mimetype', file.mimetype);
29617 if(this.fireEvent('prepare', this, formData) != false){
29618 this.xhr.send(formData);
29628 * @class Roo.bootstrap.DocumentViewer
29629 * @extends Roo.bootstrap.Component
29630 * Bootstrap DocumentViewer class
29631 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29632 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29635 * Create a new DocumentViewer
29636 * @param {Object} config The config object
29639 Roo.bootstrap.DocumentViewer = function(config){
29640 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29645 * Fire after initEvent
29646 * @param {Roo.bootstrap.DocumentViewer} this
29652 * @param {Roo.bootstrap.DocumentViewer} this
29657 * Fire after download button
29658 * @param {Roo.bootstrap.DocumentViewer} this
29663 * Fire after trash button
29664 * @param {Roo.bootstrap.DocumentViewer} this
29671 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29673 showDownload : true,
29677 getAutoCreate : function()
29681 cls : 'roo-document-viewer',
29685 cls : 'roo-document-viewer-body',
29689 cls : 'roo-document-viewer-thumb',
29693 cls : 'roo-document-viewer-image'
29701 cls : 'roo-document-viewer-footer',
29704 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29708 cls : 'btn-group roo-document-viewer-download',
29712 cls : 'btn btn-default',
29713 html : '<i class="fa fa-download"></i>'
29719 cls : 'btn-group roo-document-viewer-trash',
29723 cls : 'btn btn-default',
29724 html : '<i class="fa fa-trash"></i>'
29737 initEvents : function()
29739 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29740 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29742 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29743 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29745 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29746 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29748 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29749 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29751 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29752 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29754 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29755 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29757 this.bodyEl.on('click', this.onClick, this);
29758 this.downloadBtn.on('click', this.onDownload, this);
29759 this.trashBtn.on('click', this.onTrash, this);
29761 this.downloadBtn.hide();
29762 this.trashBtn.hide();
29764 if(this.showDownload){
29765 this.downloadBtn.show();
29768 if(this.showTrash){
29769 this.trashBtn.show();
29772 if(!this.showDownload && !this.showTrash) {
29773 this.footerEl.hide();
29778 initial : function()
29780 this.fireEvent('initial', this);
29784 onClick : function(e)
29786 e.preventDefault();
29788 this.fireEvent('click', this);
29791 onDownload : function(e)
29793 e.preventDefault();
29795 this.fireEvent('download', this);
29798 onTrash : function(e)
29800 e.preventDefault();
29802 this.fireEvent('trash', this);
29814 * @class Roo.bootstrap.NavProgressBar
29815 * @extends Roo.bootstrap.Component
29816 * Bootstrap NavProgressBar class
29819 * Create a new nav progress bar
29820 * @param {Object} config The config object
29823 Roo.bootstrap.NavProgressBar = function(config){
29824 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29826 this.bullets = this.bullets || [];
29828 // Roo.bootstrap.NavProgressBar.register(this);
29832 * Fires when the active item changes
29833 * @param {Roo.bootstrap.NavProgressBar} this
29834 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29835 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29842 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29847 getAutoCreate : function()
29849 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29853 cls : 'roo-navigation-bar-group',
29857 cls : 'roo-navigation-top-bar'
29861 cls : 'roo-navigation-bullets-bar',
29865 cls : 'roo-navigation-bar'
29872 cls : 'roo-navigation-bottom-bar'
29882 initEvents: function()
29887 onRender : function(ct, position)
29889 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29891 if(this.bullets.length){
29892 Roo.each(this.bullets, function(b){
29901 addItem : function(cfg)
29903 var item = new Roo.bootstrap.NavProgressItem(cfg);
29905 item.parentId = this.id;
29906 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29909 var top = new Roo.bootstrap.Element({
29911 cls : 'roo-navigation-bar-text'
29914 var bottom = new Roo.bootstrap.Element({
29916 cls : 'roo-navigation-bar-text'
29919 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29920 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29922 var topText = new Roo.bootstrap.Element({
29924 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29927 var bottomText = new Roo.bootstrap.Element({
29929 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29932 topText.onRender(top.el, null);
29933 bottomText.onRender(bottom.el, null);
29936 item.bottomEl = bottom;
29939 this.barItems.push(item);
29944 getActive : function()
29946 var active = false;
29948 Roo.each(this.barItems, function(v){
29950 if (!v.isActive()) {
29962 setActiveItem : function(item)
29966 Roo.each(this.barItems, function(v){
29967 if (v.rid == item.rid) {
29971 if (v.isActive()) {
29972 v.setActive(false);
29977 item.setActive(true);
29979 this.fireEvent('changed', this, item, prev);
29982 getBarItem: function(rid)
29986 Roo.each(this.barItems, function(e) {
29987 if (e.rid != rid) {
29998 indexOfItem : function(item)
30002 Roo.each(this.barItems, function(v, i){
30004 if (v.rid != item.rid) {
30015 setActiveNext : function()
30017 var i = this.indexOfItem(this.getActive());
30019 if (i > this.barItems.length) {
30023 this.setActiveItem(this.barItems[i+1]);
30026 setActivePrev : function()
30028 var i = this.indexOfItem(this.getActive());
30034 this.setActiveItem(this.barItems[i-1]);
30037 format : function()
30039 if(!this.barItems.length){
30043 var width = 100 / this.barItems.length;
30045 Roo.each(this.barItems, function(i){
30046 i.el.setStyle('width', width + '%');
30047 i.topEl.el.setStyle('width', width + '%');
30048 i.bottomEl.el.setStyle('width', width + '%');
30057 * Nav Progress Item
30062 * @class Roo.bootstrap.NavProgressItem
30063 * @extends Roo.bootstrap.Component
30064 * Bootstrap NavProgressItem class
30065 * @cfg {String} rid the reference id
30066 * @cfg {Boolean} active (true|false) Is item active default false
30067 * @cfg {Boolean} disabled (true|false) Is item active default false
30068 * @cfg {String} html
30069 * @cfg {String} position (top|bottom) text position default bottom
30070 * @cfg {String} icon show icon instead of number
30073 * Create a new NavProgressItem
30074 * @param {Object} config The config object
30076 Roo.bootstrap.NavProgressItem = function(config){
30077 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30082 * The raw click event for the entire grid.
30083 * @param {Roo.bootstrap.NavProgressItem} this
30084 * @param {Roo.EventObject} e
30091 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30097 position : 'bottom',
30100 getAutoCreate : function()
30102 var iconCls = 'roo-navigation-bar-item-icon';
30104 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30108 cls: 'roo-navigation-bar-item',
30118 cfg.cls += ' active';
30121 cfg.cls += ' disabled';
30127 disable : function()
30129 this.setDisabled(true);
30132 enable : function()
30134 this.setDisabled(false);
30137 initEvents: function()
30139 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30141 this.iconEl.on('click', this.onClick, this);
30144 onClick : function(e)
30146 e.preventDefault();
30152 if(this.fireEvent('click', this, e) === false){
30156 this.parent().setActiveItem(this);
30159 isActive: function ()
30161 return this.active;
30164 setActive : function(state)
30166 if(this.active == state){
30170 this.active = state;
30173 this.el.addClass('active');
30177 this.el.removeClass('active');
30182 setDisabled : function(state)
30184 if(this.disabled == state){
30188 this.disabled = state;
30191 this.el.addClass('disabled');
30195 this.el.removeClass('disabled');
30198 tooltipEl : function()
30200 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30213 * @class Roo.bootstrap.FieldLabel
30214 * @extends Roo.bootstrap.Component
30215 * Bootstrap FieldLabel class
30216 * @cfg {String} html contents of the element
30217 * @cfg {String} tag tag of the element default label
30218 * @cfg {String} cls class of the element
30219 * @cfg {String} target label target
30220 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30221 * @cfg {String} invalidClass default "text-warning"
30222 * @cfg {String} validClass default "text-success"
30223 * @cfg {String} iconTooltip default "This field is required"
30224 * @cfg {String} indicatorpos (left|right) default left
30227 * Create a new FieldLabel
30228 * @param {Object} config The config object
30231 Roo.bootstrap.FieldLabel = function(config){
30232 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30237 * Fires after the field has been marked as invalid.
30238 * @param {Roo.form.FieldLabel} this
30239 * @param {String} msg The validation message
30244 * Fires after the field has been validated with no errors.
30245 * @param {Roo.form.FieldLabel} this
30251 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30258 invalidClass : 'has-warning',
30259 validClass : 'has-success',
30260 iconTooltip : 'This field is required',
30261 indicatorpos : 'left',
30263 getAutoCreate : function(){
30266 if (!this.allowBlank) {
30272 cls : 'roo-bootstrap-field-label ' + this.cls,
30277 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30278 tooltip : this.iconTooltip
30287 if(this.indicatorpos == 'right'){
30290 cls : 'roo-bootstrap-field-label ' + this.cls,
30299 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30300 tooltip : this.iconTooltip
30309 initEvents: function()
30311 Roo.bootstrap.Element.superclass.initEvents.call(this);
30313 this.indicator = this.indicatorEl();
30315 if(this.indicator){
30316 this.indicator.removeClass('visible');
30317 this.indicator.addClass('invisible');
30320 Roo.bootstrap.FieldLabel.register(this);
30323 indicatorEl : function()
30325 var indicator = this.el.select('i.roo-required-indicator',true).first();
30336 * Mark this field as valid
30338 markValid : function()
30340 if(this.indicator){
30341 this.indicator.removeClass('visible');
30342 this.indicator.addClass('invisible');
30345 this.el.removeClass(this.invalidClass);
30347 this.el.addClass(this.validClass);
30349 this.fireEvent('valid', this);
30353 * Mark this field as invalid
30354 * @param {String} msg The validation message
30356 markInvalid : function(msg)
30358 if(this.indicator){
30359 this.indicator.removeClass('invisible');
30360 this.indicator.addClass('visible');
30363 this.el.removeClass(this.validClass);
30365 this.el.addClass(this.invalidClass);
30367 this.fireEvent('invalid', this, msg);
30373 Roo.apply(Roo.bootstrap.FieldLabel, {
30378 * register a FieldLabel Group
30379 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30381 register : function(label)
30383 if(this.groups.hasOwnProperty(label.target)){
30387 this.groups[label.target] = label;
30391 * fetch a FieldLabel Group based on the target
30392 * @param {string} target
30393 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30395 get: function(target) {
30396 if (typeof(this.groups[target]) == 'undefined') {
30400 return this.groups[target] ;
30409 * page DateSplitField.
30415 * @class Roo.bootstrap.DateSplitField
30416 * @extends Roo.bootstrap.Component
30417 * Bootstrap DateSplitField class
30418 * @cfg {string} fieldLabel - the label associated
30419 * @cfg {Number} labelWidth set the width of label (0-12)
30420 * @cfg {String} labelAlign (top|left)
30421 * @cfg {Boolean} dayAllowBlank (true|false) default false
30422 * @cfg {Boolean} monthAllowBlank (true|false) default false
30423 * @cfg {Boolean} yearAllowBlank (true|false) default false
30424 * @cfg {string} dayPlaceholder
30425 * @cfg {string} monthPlaceholder
30426 * @cfg {string} yearPlaceholder
30427 * @cfg {string} dayFormat default 'd'
30428 * @cfg {string} monthFormat default 'm'
30429 * @cfg {string} yearFormat default 'Y'
30430 * @cfg {Number} labellg set the width of label (1-12)
30431 * @cfg {Number} labelmd set the width of label (1-12)
30432 * @cfg {Number} labelsm set the width of label (1-12)
30433 * @cfg {Number} labelxs set the width of label (1-12)
30437 * Create a new DateSplitField
30438 * @param {Object} config The config object
30441 Roo.bootstrap.DateSplitField = function(config){
30442 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30448 * getting the data of years
30449 * @param {Roo.bootstrap.DateSplitField} this
30450 * @param {Object} years
30455 * getting the data of days
30456 * @param {Roo.bootstrap.DateSplitField} this
30457 * @param {Object} days
30462 * Fires after the field has been marked as invalid.
30463 * @param {Roo.form.Field} this
30464 * @param {String} msg The validation message
30469 * Fires after the field has been validated with no errors.
30470 * @param {Roo.form.Field} this
30476 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30479 labelAlign : 'top',
30481 dayAllowBlank : false,
30482 monthAllowBlank : false,
30483 yearAllowBlank : false,
30484 dayPlaceholder : '',
30485 monthPlaceholder : '',
30486 yearPlaceholder : '',
30490 isFormField : true,
30496 getAutoCreate : function()
30500 cls : 'row roo-date-split-field-group',
30505 cls : 'form-hidden-field roo-date-split-field-group-value',
30511 var labelCls = 'col-md-12';
30512 var contentCls = 'col-md-4';
30514 if(this.fieldLabel){
30518 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30522 html : this.fieldLabel
30527 if(this.labelAlign == 'left'){
30529 if(this.labelWidth > 12){
30530 label.style = "width: " + this.labelWidth + 'px';
30533 if(this.labelWidth < 13 && this.labelmd == 0){
30534 this.labelmd = this.labelWidth;
30537 if(this.labellg > 0){
30538 labelCls = ' col-lg-' + this.labellg;
30539 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30542 if(this.labelmd > 0){
30543 labelCls = ' col-md-' + this.labelmd;
30544 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30547 if(this.labelsm > 0){
30548 labelCls = ' col-sm-' + this.labelsm;
30549 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30552 if(this.labelxs > 0){
30553 labelCls = ' col-xs-' + this.labelxs;
30554 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30558 label.cls += ' ' + labelCls;
30560 cfg.cn.push(label);
30563 Roo.each(['day', 'month', 'year'], function(t){
30566 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30573 inputEl: function ()
30575 return this.el.select('.roo-date-split-field-group-value', true).first();
30578 onRender : function(ct, position)
30582 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30584 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30586 this.dayField = new Roo.bootstrap.ComboBox({
30587 allowBlank : this.dayAllowBlank,
30588 alwaysQuery : true,
30589 displayField : 'value',
30592 forceSelection : true,
30594 placeholder : this.dayPlaceholder,
30595 selectOnFocus : true,
30596 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30597 triggerAction : 'all',
30599 valueField : 'value',
30600 store : new Roo.data.SimpleStore({
30601 data : (function() {
30603 _this.fireEvent('days', _this, days);
30606 fields : [ 'value' ]
30609 select : function (_self, record, index)
30611 _this.setValue(_this.getValue());
30616 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30618 this.monthField = new Roo.bootstrap.MonthField({
30619 after : '<i class=\"fa fa-calendar\"></i>',
30620 allowBlank : this.monthAllowBlank,
30621 placeholder : this.monthPlaceholder,
30624 render : function (_self)
30626 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30627 e.preventDefault();
30631 select : function (_self, oldvalue, newvalue)
30633 _this.setValue(_this.getValue());
30638 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30640 this.yearField = new Roo.bootstrap.ComboBox({
30641 allowBlank : this.yearAllowBlank,
30642 alwaysQuery : true,
30643 displayField : 'value',
30646 forceSelection : true,
30648 placeholder : this.yearPlaceholder,
30649 selectOnFocus : true,
30650 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30651 triggerAction : 'all',
30653 valueField : 'value',
30654 store : new Roo.data.SimpleStore({
30655 data : (function() {
30657 _this.fireEvent('years', _this, years);
30660 fields : [ 'value' ]
30663 select : function (_self, record, index)
30665 _this.setValue(_this.getValue());
30670 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30673 setValue : function(v, format)
30675 this.inputEl.dom.value = v;
30677 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30679 var d = Date.parseDate(v, f);
30686 this.setDay(d.format(this.dayFormat));
30687 this.setMonth(d.format(this.monthFormat));
30688 this.setYear(d.format(this.yearFormat));
30695 setDay : function(v)
30697 this.dayField.setValue(v);
30698 this.inputEl.dom.value = this.getValue();
30703 setMonth : function(v)
30705 this.monthField.setValue(v, true);
30706 this.inputEl.dom.value = this.getValue();
30711 setYear : function(v)
30713 this.yearField.setValue(v);
30714 this.inputEl.dom.value = this.getValue();
30719 getDay : function()
30721 return this.dayField.getValue();
30724 getMonth : function()
30726 return this.monthField.getValue();
30729 getYear : function()
30731 return this.yearField.getValue();
30734 getValue : function()
30736 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30738 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30748 this.inputEl.dom.value = '';
30753 validate : function()
30755 var d = this.dayField.validate();
30756 var m = this.monthField.validate();
30757 var y = this.yearField.validate();
30762 (!this.dayAllowBlank && !d) ||
30763 (!this.monthAllowBlank && !m) ||
30764 (!this.yearAllowBlank && !y)
30769 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30778 this.markInvalid();
30783 markValid : function()
30786 var label = this.el.select('label', true).first();
30787 var icon = this.el.select('i.fa-star', true).first();
30793 this.fireEvent('valid', this);
30797 * Mark this field as invalid
30798 * @param {String} msg The validation message
30800 markInvalid : function(msg)
30803 var label = this.el.select('label', true).first();
30804 var icon = this.el.select('i.fa-star', true).first();
30806 if(label && !icon){
30807 this.el.select('.roo-date-split-field-label', true).createChild({
30809 cls : 'text-danger fa fa-lg fa-star',
30810 tooltip : 'This field is required',
30811 style : 'margin-right:5px;'
30815 this.fireEvent('invalid', this, msg);
30818 clearInvalid : function()
30820 var label = this.el.select('label', true).first();
30821 var icon = this.el.select('i.fa-star', true).first();
30827 this.fireEvent('valid', this);
30830 getName: function()
30840 * http://masonry.desandro.com
30842 * The idea is to render all the bricks based on vertical width...
30844 * The original code extends 'outlayer' - we might need to use that....
30850 * @class Roo.bootstrap.LayoutMasonry
30851 * @extends Roo.bootstrap.Component
30852 * Bootstrap Layout Masonry class
30855 * Create a new Element
30856 * @param {Object} config The config object
30859 Roo.bootstrap.LayoutMasonry = function(config){
30861 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30865 Roo.bootstrap.LayoutMasonry.register(this);
30871 * Fire after layout the items
30872 * @param {Roo.bootstrap.LayoutMasonry} this
30873 * @param {Roo.EventObject} e
30880 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30883 * @cfg {Boolean} isLayoutInstant = no animation?
30885 isLayoutInstant : false, // needed?
30888 * @cfg {Number} boxWidth width of the columns
30893 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30898 * @cfg {Number} padWidth padding below box..
30903 * @cfg {Number} gutter gutter width..
30908 * @cfg {Number} maxCols maximum number of columns
30914 * @cfg {Boolean} isAutoInitial defalut true
30916 isAutoInitial : true,
30921 * @cfg {Boolean} isHorizontal defalut false
30923 isHorizontal : false,
30925 currentSize : null,
30931 bricks: null, //CompositeElement
30935 _isLayoutInited : false,
30937 // isAlternative : false, // only use for vertical layout...
30940 * @cfg {Number} alternativePadWidth padding below box..
30942 alternativePadWidth : 50,
30944 selectedBrick : [],
30946 getAutoCreate : function(){
30948 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30952 cls: 'blog-masonary-wrapper ' + this.cls,
30954 cls : 'mas-boxes masonary'
30961 getChildContainer: function( )
30963 if (this.boxesEl) {
30964 return this.boxesEl;
30967 this.boxesEl = this.el.select('.mas-boxes').first();
30969 return this.boxesEl;
30973 initEvents : function()
30977 if(this.isAutoInitial){
30978 Roo.log('hook children rendered');
30979 this.on('childrenrendered', function() {
30980 Roo.log('children rendered');
30986 initial : function()
30988 this.selectedBrick = [];
30990 this.currentSize = this.el.getBox(true);
30992 Roo.EventManager.onWindowResize(this.resize, this);
30994 if(!this.isAutoInitial){
31002 //this.layout.defer(500,this);
31006 resize : function()
31008 var cs = this.el.getBox(true);
31011 this.currentSize.width == cs.width &&
31012 this.currentSize.x == cs.x &&
31013 this.currentSize.height == cs.height &&
31014 this.currentSize.y == cs.y
31016 Roo.log("no change in with or X or Y");
31020 this.currentSize = cs;
31026 layout : function()
31028 this._resetLayout();
31030 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31032 this.layoutItems( isInstant );
31034 this._isLayoutInited = true;
31036 this.fireEvent('layout', this);
31040 _resetLayout : function()
31042 if(this.isHorizontal){
31043 this.horizontalMeasureColumns();
31047 this.verticalMeasureColumns();
31051 verticalMeasureColumns : function()
31053 this.getContainerWidth();
31055 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31056 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31060 var boxWidth = this.boxWidth + this.padWidth;
31062 if(this.containerWidth < this.boxWidth){
31063 boxWidth = this.containerWidth
31066 var containerWidth = this.containerWidth;
31068 var cols = Math.floor(containerWidth / boxWidth);
31070 this.cols = Math.max( cols, 1 );
31072 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31074 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31076 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31078 this.colWidth = boxWidth + avail - this.padWidth;
31080 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31081 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31084 horizontalMeasureColumns : function()
31086 this.getContainerWidth();
31088 var boxWidth = this.boxWidth;
31090 if(this.containerWidth < boxWidth){
31091 boxWidth = this.containerWidth;
31094 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31096 this.el.setHeight(boxWidth);
31100 getContainerWidth : function()
31102 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31105 layoutItems : function( isInstant )
31107 Roo.log(this.bricks);
31109 var items = Roo.apply([], this.bricks);
31111 if(this.isHorizontal){
31112 this._horizontalLayoutItems( items , isInstant );
31116 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31117 // this._verticalAlternativeLayoutItems( items , isInstant );
31121 this._verticalLayoutItems( items , isInstant );
31125 _verticalLayoutItems : function ( items , isInstant)
31127 if ( !items || !items.length ) {
31132 ['xs', 'xs', 'xs', 'tall'],
31133 ['xs', 'xs', 'tall'],
31134 ['xs', 'xs', 'sm'],
31135 ['xs', 'xs', 'xs'],
31141 ['sm', 'xs', 'xs'],
31145 ['tall', 'xs', 'xs', 'xs'],
31146 ['tall', 'xs', 'xs'],
31158 Roo.each(items, function(item, k){
31160 switch (item.size) {
31161 // these layouts take up a full box,
31172 boxes.push([item]);
31195 var filterPattern = function(box, length)
31203 var pattern = box.slice(0, length);
31207 Roo.each(pattern, function(i){
31208 format.push(i.size);
31211 Roo.each(standard, function(s){
31213 if(String(s) != String(format)){
31222 if(!match && length == 1){
31227 filterPattern(box, length - 1);
31231 queue.push(pattern);
31233 box = box.slice(length, box.length);
31235 filterPattern(box, 4);
31241 Roo.each(boxes, function(box, k){
31247 if(box.length == 1){
31252 filterPattern(box, 4);
31256 this._processVerticalLayoutQueue( queue, isInstant );
31260 // _verticalAlternativeLayoutItems : function( items , isInstant )
31262 // if ( !items || !items.length ) {
31266 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31270 _horizontalLayoutItems : function ( items , isInstant)
31272 if ( !items || !items.length || items.length < 3) {
31278 var eItems = items.slice(0, 3);
31280 items = items.slice(3, items.length);
31283 ['xs', 'xs', 'xs', 'wide'],
31284 ['xs', 'xs', 'wide'],
31285 ['xs', 'xs', 'sm'],
31286 ['xs', 'xs', 'xs'],
31292 ['sm', 'xs', 'xs'],
31296 ['wide', 'xs', 'xs', 'xs'],
31297 ['wide', 'xs', 'xs'],
31310 Roo.each(items, function(item, k){
31312 switch (item.size) {
31323 boxes.push([item]);
31347 var filterPattern = function(box, length)
31355 var pattern = box.slice(0, length);
31359 Roo.each(pattern, function(i){
31360 format.push(i.size);
31363 Roo.each(standard, function(s){
31365 if(String(s) != String(format)){
31374 if(!match && length == 1){
31379 filterPattern(box, length - 1);
31383 queue.push(pattern);
31385 box = box.slice(length, box.length);
31387 filterPattern(box, 4);
31393 Roo.each(boxes, function(box, k){
31399 if(box.length == 1){
31404 filterPattern(box, 4);
31411 var pos = this.el.getBox(true);
31415 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31417 var hit_end = false;
31419 Roo.each(queue, function(box){
31423 Roo.each(box, function(b){
31425 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31435 Roo.each(box, function(b){
31437 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31440 mx = Math.max(mx, b.x);
31444 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31448 Roo.each(box, function(b){
31450 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31464 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31467 /** Sets position of item in DOM
31468 * @param {Element} item
31469 * @param {Number} x - horizontal position
31470 * @param {Number} y - vertical position
31471 * @param {Boolean} isInstant - disables transitions
31473 _processVerticalLayoutQueue : function( queue, isInstant )
31475 var pos = this.el.getBox(true);
31480 for (var i = 0; i < this.cols; i++){
31484 Roo.each(queue, function(box, k){
31486 var col = k % this.cols;
31488 Roo.each(box, function(b,kk){
31490 b.el.position('absolute');
31492 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31493 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31495 if(b.size == 'md-left' || b.size == 'md-right'){
31496 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31497 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31500 b.el.setWidth(width);
31501 b.el.setHeight(height);
31503 b.el.select('iframe',true).setSize(width,height);
31507 for (var i = 0; i < this.cols; i++){
31509 if(maxY[i] < maxY[col]){
31514 col = Math.min(col, i);
31518 x = pos.x + col * (this.colWidth + this.padWidth);
31522 var positions = [];
31524 switch (box.length){
31526 positions = this.getVerticalOneBoxColPositions(x, y, box);
31529 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31532 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31535 positions = this.getVerticalFourBoxColPositions(x, y, box);
31541 Roo.each(box, function(b,kk){
31543 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31545 var sz = b.el.getSize();
31547 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31555 for (var i = 0; i < this.cols; i++){
31556 mY = Math.max(mY, maxY[i]);
31559 this.el.setHeight(mY - pos.y);
31563 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31565 // var pos = this.el.getBox(true);
31568 // var maxX = pos.right;
31570 // var maxHeight = 0;
31572 // Roo.each(items, function(item, k){
31576 // item.el.position('absolute');
31578 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31580 // item.el.setWidth(width);
31582 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31584 // item.el.setHeight(height);
31587 // item.el.setXY([x, y], isInstant ? false : true);
31589 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31592 // y = y + height + this.alternativePadWidth;
31594 // maxHeight = maxHeight + height + this.alternativePadWidth;
31598 // this.el.setHeight(maxHeight);
31602 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31604 var pos = this.el.getBox(true);
31609 var maxX = pos.right;
31611 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31613 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31615 Roo.each(queue, function(box, k){
31617 Roo.each(box, function(b, kk){
31619 b.el.position('absolute');
31621 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31622 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31624 if(b.size == 'md-left' || b.size == 'md-right'){
31625 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31626 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31629 b.el.setWidth(width);
31630 b.el.setHeight(height);
31638 var positions = [];
31640 switch (box.length){
31642 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31645 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31648 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31651 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31657 Roo.each(box, function(b,kk){
31659 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31661 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31669 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31671 Roo.each(eItems, function(b,k){
31673 b.size = (k == 0) ? 'sm' : 'xs';
31674 b.x = (k == 0) ? 2 : 1;
31675 b.y = (k == 0) ? 2 : 1;
31677 b.el.position('absolute');
31679 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31681 b.el.setWidth(width);
31683 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31685 b.el.setHeight(height);
31689 var positions = [];
31692 x : maxX - this.unitWidth * 2 - this.gutter,
31697 x : maxX - this.unitWidth,
31698 y : minY + (this.unitWidth + this.gutter) * 2
31702 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31706 Roo.each(eItems, function(b,k){
31708 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31714 getVerticalOneBoxColPositions : function(x, y, box)
31718 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31720 if(box[0].size == 'md-left'){
31724 if(box[0].size == 'md-right'){
31729 x : x + (this.unitWidth + this.gutter) * rand,
31736 getVerticalTwoBoxColPositions : function(x, y, box)
31740 if(box[0].size == 'xs'){
31744 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31748 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31762 x : x + (this.unitWidth + this.gutter) * 2,
31763 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31770 getVerticalThreeBoxColPositions : function(x, y, box)
31774 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31782 x : x + (this.unitWidth + this.gutter) * 1,
31787 x : x + (this.unitWidth + this.gutter) * 2,
31795 if(box[0].size == 'xs' && box[1].size == 'xs'){
31804 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31808 x : x + (this.unitWidth + this.gutter) * 1,
31822 x : x + (this.unitWidth + this.gutter) * 2,
31827 x : x + (this.unitWidth + this.gutter) * 2,
31828 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31835 getVerticalFourBoxColPositions : function(x, y, box)
31839 if(box[0].size == 'xs'){
31848 y : y + (this.unitHeight + this.gutter) * 1
31853 y : y + (this.unitHeight + this.gutter) * 2
31857 x : x + (this.unitWidth + this.gutter) * 1,
31871 x : x + (this.unitWidth + this.gutter) * 2,
31876 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31877 y : y + (this.unitHeight + this.gutter) * 1
31881 x : x + (this.unitWidth + this.gutter) * 2,
31882 y : y + (this.unitWidth + this.gutter) * 2
31889 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31893 if(box[0].size == 'md-left'){
31895 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31902 if(box[0].size == 'md-right'){
31904 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31905 y : minY + (this.unitWidth + this.gutter) * 1
31911 var rand = Math.floor(Math.random() * (4 - box[0].y));
31914 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31915 y : minY + (this.unitWidth + this.gutter) * rand
31922 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31926 if(box[0].size == 'xs'){
31929 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31934 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31935 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31943 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31948 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31949 y : minY + (this.unitWidth + this.gutter) * 2
31956 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31960 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31963 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31968 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31969 y : minY + (this.unitWidth + this.gutter) * 1
31973 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31974 y : minY + (this.unitWidth + this.gutter) * 2
31981 if(box[0].size == 'xs' && box[1].size == 'xs'){
31984 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31989 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31994 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31995 y : minY + (this.unitWidth + this.gutter) * 1
32003 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32008 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32009 y : minY + (this.unitWidth + this.gutter) * 2
32013 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32014 y : minY + (this.unitWidth + this.gutter) * 2
32021 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32025 if(box[0].size == 'xs'){
32028 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32033 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32038 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),
32043 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32044 y : minY + (this.unitWidth + this.gutter) * 1
32052 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32057 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32058 y : minY + (this.unitWidth + this.gutter) * 2
32062 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32063 y : minY + (this.unitWidth + this.gutter) * 2
32067 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),
32068 y : minY + (this.unitWidth + this.gutter) * 2
32076 * remove a Masonry Brick
32077 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32079 removeBrick : function(brick_id)
32085 for (var i = 0; i<this.bricks.length; i++) {
32086 if (this.bricks[i].id == brick_id) {
32087 this.bricks.splice(i,1);
32088 this.el.dom.removeChild(Roo.get(brick_id).dom);
32095 * adds a Masonry Brick
32096 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32098 addBrick : function(cfg)
32100 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32101 //this.register(cn);
32102 cn.parentId = this.id;
32103 cn.render(this.el);
32108 * register a Masonry Brick
32109 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32112 register : function(brick)
32114 this.bricks.push(brick);
32115 brick.masonryId = this.id;
32119 * clear all the Masonry Brick
32121 clearAll : function()
32124 //this.getChildContainer().dom.innerHTML = "";
32125 this.el.dom.innerHTML = '';
32128 getSelected : function()
32130 if (!this.selectedBrick) {
32134 return this.selectedBrick;
32138 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32142 * register a Masonry Layout
32143 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32146 register : function(layout)
32148 this.groups[layout.id] = layout;
32151 * fetch a Masonry Layout based on the masonry layout ID
32152 * @param {string} the masonry layout to add
32153 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32156 get: function(layout_id) {
32157 if (typeof(this.groups[layout_id]) == 'undefined') {
32160 return this.groups[layout_id] ;
32172 * http://masonry.desandro.com
32174 * The idea is to render all the bricks based on vertical width...
32176 * The original code extends 'outlayer' - we might need to use that....
32182 * @class Roo.bootstrap.LayoutMasonryAuto
32183 * @extends Roo.bootstrap.Component
32184 * Bootstrap Layout Masonry class
32187 * Create a new Element
32188 * @param {Object} config The config object
32191 Roo.bootstrap.LayoutMasonryAuto = function(config){
32192 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32195 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32198 * @cfg {Boolean} isFitWidth - resize the width..
32200 isFitWidth : false, // options..
32202 * @cfg {Boolean} isOriginLeft = left align?
32204 isOriginLeft : true,
32206 * @cfg {Boolean} isOriginTop = top align?
32208 isOriginTop : false,
32210 * @cfg {Boolean} isLayoutInstant = no animation?
32212 isLayoutInstant : false, // needed?
32214 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32216 isResizingContainer : true,
32218 * @cfg {Number} columnWidth width of the columns
32224 * @cfg {Number} maxCols maximum number of columns
32229 * @cfg {Number} padHeight padding below box..
32235 * @cfg {Boolean} isAutoInitial defalut true
32238 isAutoInitial : true,
32244 initialColumnWidth : 0,
32245 currentSize : null,
32247 colYs : null, // array.
32254 bricks: null, //CompositeElement
32255 cols : 0, // array?
32256 // element : null, // wrapped now this.el
32257 _isLayoutInited : null,
32260 getAutoCreate : function(){
32264 cls: 'blog-masonary-wrapper ' + this.cls,
32266 cls : 'mas-boxes masonary'
32273 getChildContainer: function( )
32275 if (this.boxesEl) {
32276 return this.boxesEl;
32279 this.boxesEl = this.el.select('.mas-boxes').first();
32281 return this.boxesEl;
32285 initEvents : function()
32289 if(this.isAutoInitial){
32290 Roo.log('hook children rendered');
32291 this.on('childrenrendered', function() {
32292 Roo.log('children rendered');
32299 initial : function()
32301 this.reloadItems();
32303 this.currentSize = this.el.getBox(true);
32305 /// was window resize... - let's see if this works..
32306 Roo.EventManager.onWindowResize(this.resize, this);
32308 if(!this.isAutoInitial){
32313 this.layout.defer(500,this);
32316 reloadItems: function()
32318 this.bricks = this.el.select('.masonry-brick', true);
32320 this.bricks.each(function(b) {
32321 //Roo.log(b.getSize());
32322 if (!b.attr('originalwidth')) {
32323 b.attr('originalwidth', b.getSize().width);
32328 Roo.log(this.bricks.elements.length);
32331 resize : function()
32334 var cs = this.el.getBox(true);
32336 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32337 Roo.log("no change in with or X");
32340 this.currentSize = cs;
32344 layout : function()
32347 this._resetLayout();
32348 //this._manageStamps();
32350 // don't animate first layout
32351 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32352 this.layoutItems( isInstant );
32354 // flag for initalized
32355 this._isLayoutInited = true;
32358 layoutItems : function( isInstant )
32360 //var items = this._getItemsForLayout( this.items );
32361 // original code supports filtering layout items.. we just ignore it..
32363 this._layoutItems( this.bricks , isInstant );
32365 this._postLayout();
32367 _layoutItems : function ( items , isInstant)
32369 //this.fireEvent( 'layout', this, items );
32372 if ( !items || !items.elements.length ) {
32373 // no items, emit event with empty array
32378 items.each(function(item) {
32379 Roo.log("layout item");
32381 // get x/y object from method
32382 var position = this._getItemLayoutPosition( item );
32384 position.item = item;
32385 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32386 queue.push( position );
32389 this._processLayoutQueue( queue );
32391 /** Sets position of item in DOM
32392 * @param {Element} item
32393 * @param {Number} x - horizontal position
32394 * @param {Number} y - vertical position
32395 * @param {Boolean} isInstant - disables transitions
32397 _processLayoutQueue : function( queue )
32399 for ( var i=0, len = queue.length; i < len; i++ ) {
32400 var obj = queue[i];
32401 obj.item.position('absolute');
32402 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32408 * Any logic you want to do after each layout,
32409 * i.e. size the container
32411 _postLayout : function()
32413 this.resizeContainer();
32416 resizeContainer : function()
32418 if ( !this.isResizingContainer ) {
32421 var size = this._getContainerSize();
32423 this.el.setSize(size.width,size.height);
32424 this.boxesEl.setSize(size.width,size.height);
32430 _resetLayout : function()
32432 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32433 this.colWidth = this.el.getWidth();
32434 //this.gutter = this.el.getWidth();
32436 this.measureColumns();
32442 this.colYs.push( 0 );
32448 measureColumns : function()
32450 this.getContainerWidth();
32451 // if columnWidth is 0, default to outerWidth of first item
32452 if ( !this.columnWidth ) {
32453 var firstItem = this.bricks.first();
32454 Roo.log(firstItem);
32455 this.columnWidth = this.containerWidth;
32456 if (firstItem && firstItem.attr('originalwidth') ) {
32457 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32459 // columnWidth fall back to item of first element
32460 Roo.log("set column width?");
32461 this.initialColumnWidth = this.columnWidth ;
32463 // if first elem has no width, default to size of container
32468 if (this.initialColumnWidth) {
32469 this.columnWidth = this.initialColumnWidth;
32474 // column width is fixed at the top - however if container width get's smaller we should
32477 // this bit calcs how man columns..
32479 var columnWidth = this.columnWidth += this.gutter;
32481 // calculate columns
32482 var containerWidth = this.containerWidth + this.gutter;
32484 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32485 // fix rounding errors, typically with gutters
32486 var excess = columnWidth - containerWidth % columnWidth;
32489 // if overshoot is less than a pixel, round up, otherwise floor it
32490 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32491 cols = Math[ mathMethod ]( cols );
32492 this.cols = Math.max( cols, 1 );
32493 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32495 // padding positioning..
32496 var totalColWidth = this.cols * this.columnWidth;
32497 var padavail = this.containerWidth - totalColWidth;
32498 // so for 2 columns - we need 3 'pads'
32500 var padNeeded = (1+this.cols) * this.padWidth;
32502 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32504 this.columnWidth += padExtra
32505 //this.padWidth = Math.floor(padavail / ( this.cols));
32507 // adjust colum width so that padding is fixed??
32509 // we have 3 columns ... total = width * 3
32510 // we have X left over... that should be used by
32512 //if (this.expandC) {
32520 getContainerWidth : function()
32522 /* // container is parent if fit width
32523 var container = this.isFitWidth ? this.element.parentNode : this.element;
32524 // check that this.size and size are there
32525 // IE8 triggers resize on body size change, so they might not be
32527 var size = getSize( container ); //FIXME
32528 this.containerWidth = size && size.innerWidth; //FIXME
32531 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32535 _getItemLayoutPosition : function( item ) // what is item?
32537 // we resize the item to our columnWidth..
32539 item.setWidth(this.columnWidth);
32540 item.autoBoxAdjust = false;
32542 var sz = item.getSize();
32544 // how many columns does this brick span
32545 var remainder = this.containerWidth % this.columnWidth;
32547 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32548 // round if off by 1 pixel, otherwise use ceil
32549 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32550 colSpan = Math.min( colSpan, this.cols );
32552 // normally this should be '1' as we dont' currently allow multi width columns..
32554 var colGroup = this._getColGroup( colSpan );
32555 // get the minimum Y value from the columns
32556 var minimumY = Math.min.apply( Math, colGroup );
32557 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32559 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32561 // position the brick
32563 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32564 y: this.currentSize.y + minimumY + this.padHeight
32568 // apply setHeight to necessary columns
32569 var setHeight = minimumY + sz.height + this.padHeight;
32570 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32572 var setSpan = this.cols + 1 - colGroup.length;
32573 for ( var i = 0; i < setSpan; i++ ) {
32574 this.colYs[ shortColIndex + i ] = setHeight ;
32581 * @param {Number} colSpan - number of columns the element spans
32582 * @returns {Array} colGroup
32584 _getColGroup : function( colSpan )
32586 if ( colSpan < 2 ) {
32587 // if brick spans only one column, use all the column Ys
32592 // how many different places could this brick fit horizontally
32593 var groupCount = this.cols + 1 - colSpan;
32594 // for each group potential horizontal position
32595 for ( var i = 0; i < groupCount; i++ ) {
32596 // make an array of colY values for that one group
32597 var groupColYs = this.colYs.slice( i, i + colSpan );
32598 // and get the max value of the array
32599 colGroup[i] = Math.max.apply( Math, groupColYs );
32604 _manageStamp : function( stamp )
32606 var stampSize = stamp.getSize();
32607 var offset = stamp.getBox();
32608 // get the columns that this stamp affects
32609 var firstX = this.isOriginLeft ? offset.x : offset.right;
32610 var lastX = firstX + stampSize.width;
32611 var firstCol = Math.floor( firstX / this.columnWidth );
32612 firstCol = Math.max( 0, firstCol );
32614 var lastCol = Math.floor( lastX / this.columnWidth );
32615 // lastCol should not go over if multiple of columnWidth #425
32616 lastCol -= lastX % this.columnWidth ? 0 : 1;
32617 lastCol = Math.min( this.cols - 1, lastCol );
32619 // set colYs to bottom of the stamp
32620 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32623 for ( var i = firstCol; i <= lastCol; i++ ) {
32624 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32629 _getContainerSize : function()
32631 this.maxY = Math.max.apply( Math, this.colYs );
32636 if ( this.isFitWidth ) {
32637 size.width = this._getContainerFitWidth();
32643 _getContainerFitWidth : function()
32645 var unusedCols = 0;
32646 // count unused columns
32649 if ( this.colYs[i] !== 0 ) {
32654 // fit container to columns that have been used
32655 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32658 needsResizeLayout : function()
32660 var previousWidth = this.containerWidth;
32661 this.getContainerWidth();
32662 return previousWidth !== this.containerWidth;
32677 * @class Roo.bootstrap.MasonryBrick
32678 * @extends Roo.bootstrap.Component
32679 * Bootstrap MasonryBrick class
32682 * Create a new MasonryBrick
32683 * @param {Object} config The config object
32686 Roo.bootstrap.MasonryBrick = function(config){
32688 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32690 Roo.bootstrap.MasonryBrick.register(this);
32696 * When a MasonryBrick is clcik
32697 * @param {Roo.bootstrap.MasonryBrick} this
32698 * @param {Roo.EventObject} e
32704 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32707 * @cfg {String} title
32711 * @cfg {String} html
32715 * @cfg {String} bgimage
32719 * @cfg {String} videourl
32723 * @cfg {String} cls
32727 * @cfg {String} href
32731 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32736 * @cfg {String} placetitle (center|bottom)
32741 * @cfg {Boolean} isFitContainer defalut true
32743 isFitContainer : true,
32746 * @cfg {Boolean} preventDefault defalut false
32748 preventDefault : false,
32751 * @cfg {Boolean} inverse defalut false
32753 maskInverse : false,
32755 getAutoCreate : function()
32757 if(!this.isFitContainer){
32758 return this.getSplitAutoCreate();
32761 var cls = 'masonry-brick masonry-brick-full';
32763 if(this.href.length){
32764 cls += ' masonry-brick-link';
32767 if(this.bgimage.length){
32768 cls += ' masonry-brick-image';
32771 if(this.maskInverse){
32772 cls += ' mask-inverse';
32775 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32776 cls += ' enable-mask';
32780 cls += ' masonry-' + this.size + '-brick';
32783 if(this.placetitle.length){
32785 switch (this.placetitle) {
32787 cls += ' masonry-center-title';
32790 cls += ' masonry-bottom-title';
32797 if(!this.html.length && !this.bgimage.length){
32798 cls += ' masonry-center-title';
32801 if(!this.html.length && this.bgimage.length){
32802 cls += ' masonry-bottom-title';
32807 cls += ' ' + this.cls;
32811 tag: (this.href.length) ? 'a' : 'div',
32816 cls: 'masonry-brick-mask'
32820 cls: 'masonry-brick-paragraph',
32826 if(this.href.length){
32827 cfg.href = this.href;
32830 var cn = cfg.cn[1].cn;
32832 if(this.title.length){
32835 cls: 'masonry-brick-title',
32840 if(this.html.length){
32843 cls: 'masonry-brick-text',
32848 if (!this.title.length && !this.html.length) {
32849 cfg.cn[1].cls += ' hide';
32852 if(this.bgimage.length){
32855 cls: 'masonry-brick-image-view',
32860 if(this.videourl.length){
32861 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32862 // youtube support only?
32865 cls: 'masonry-brick-image-view',
32868 allowfullscreen : true
32876 getSplitAutoCreate : function()
32878 var cls = 'masonry-brick masonry-brick-split';
32880 if(this.href.length){
32881 cls += ' masonry-brick-link';
32884 if(this.bgimage.length){
32885 cls += ' masonry-brick-image';
32889 cls += ' masonry-' + this.size + '-brick';
32892 switch (this.placetitle) {
32894 cls += ' masonry-center-title';
32897 cls += ' masonry-bottom-title';
32900 if(!this.bgimage.length){
32901 cls += ' masonry-center-title';
32904 if(this.bgimage.length){
32905 cls += ' masonry-bottom-title';
32911 cls += ' ' + this.cls;
32915 tag: (this.href.length) ? 'a' : 'div',
32920 cls: 'masonry-brick-split-head',
32924 cls: 'masonry-brick-paragraph',
32931 cls: 'masonry-brick-split-body',
32937 if(this.href.length){
32938 cfg.href = this.href;
32941 if(this.title.length){
32942 cfg.cn[0].cn[0].cn.push({
32944 cls: 'masonry-brick-title',
32949 if(this.html.length){
32950 cfg.cn[1].cn.push({
32952 cls: 'masonry-brick-text',
32957 if(this.bgimage.length){
32958 cfg.cn[0].cn.push({
32960 cls: 'masonry-brick-image-view',
32965 if(this.videourl.length){
32966 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32967 // youtube support only?
32968 cfg.cn[0].cn.cn.push({
32970 cls: 'masonry-brick-image-view',
32973 allowfullscreen : true
32980 initEvents: function()
32982 switch (this.size) {
33015 this.el.on('touchstart', this.onTouchStart, this);
33016 this.el.on('touchmove', this.onTouchMove, this);
33017 this.el.on('touchend', this.onTouchEnd, this);
33018 this.el.on('contextmenu', this.onContextMenu, this);
33020 this.el.on('mouseenter' ,this.enter, this);
33021 this.el.on('mouseleave', this.leave, this);
33022 this.el.on('click', this.onClick, this);
33025 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33026 this.parent().bricks.push(this);
33031 onClick: function(e, el)
33033 var time = this.endTimer - this.startTimer;
33034 // Roo.log(e.preventDefault());
33037 e.preventDefault();
33042 if(!this.preventDefault){
33046 e.preventDefault();
33048 if (this.activeClass != '') {
33049 this.selectBrick();
33052 this.fireEvent('click', this, e);
33055 enter: 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.9, true);
33068 leave: function(e, el)
33070 e.preventDefault();
33072 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33076 if(this.bgimage.length && this.html.length){
33077 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33081 onTouchStart: function(e, el)
33083 // e.preventDefault();
33085 this.touchmoved = false;
33087 if(!this.isFitContainer){
33091 if(!this.bgimage.length || !this.html.length){
33095 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33097 this.timer = new Date().getTime();
33101 onTouchMove: function(e, el)
33103 this.touchmoved = true;
33106 onContextMenu : function(e,el)
33108 e.preventDefault();
33109 e.stopPropagation();
33113 onTouchEnd: function(e, el)
33115 // e.preventDefault();
33117 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33124 if(!this.bgimage.length || !this.html.length){
33126 if(this.href.length){
33127 window.location.href = this.href;
33133 if(!this.isFitContainer){
33137 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33139 window.location.href = this.href;
33142 //selection on single brick only
33143 selectBrick : function() {
33145 if (!this.parentId) {
33149 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33150 var index = m.selectedBrick.indexOf(this.id);
33153 m.selectedBrick.splice(index,1);
33154 this.el.removeClass(this.activeClass);
33158 for(var i = 0; i < m.selectedBrick.length; i++) {
33159 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33160 b.el.removeClass(b.activeClass);
33163 m.selectedBrick = [];
33165 m.selectedBrick.push(this.id);
33166 this.el.addClass(this.activeClass);
33170 isSelected : function(){
33171 return this.el.hasClass(this.activeClass);
33176 Roo.apply(Roo.bootstrap.MasonryBrick, {
33179 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33181 * register a Masonry Brick
33182 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33185 register : function(brick)
33187 //this.groups[brick.id] = brick;
33188 this.groups.add(brick.id, brick);
33191 * fetch a masonry brick based on the masonry brick ID
33192 * @param {string} the masonry brick to add
33193 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33196 get: function(brick_id)
33198 // if (typeof(this.groups[brick_id]) == 'undefined') {
33201 // return this.groups[brick_id] ;
33203 if(this.groups.key(brick_id)) {
33204 return this.groups.key(brick_id);
33222 * @class Roo.bootstrap.Brick
33223 * @extends Roo.bootstrap.Component
33224 * Bootstrap Brick class
33227 * Create a new Brick
33228 * @param {Object} config The config object
33231 Roo.bootstrap.Brick = function(config){
33232 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33238 * When a Brick is click
33239 * @param {Roo.bootstrap.Brick} this
33240 * @param {Roo.EventObject} e
33246 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33249 * @cfg {String} title
33253 * @cfg {String} html
33257 * @cfg {String} bgimage
33261 * @cfg {String} cls
33265 * @cfg {String} href
33269 * @cfg {String} video
33273 * @cfg {Boolean} square
33277 getAutoCreate : function()
33279 var cls = 'roo-brick';
33281 if(this.href.length){
33282 cls += ' roo-brick-link';
33285 if(this.bgimage.length){
33286 cls += ' roo-brick-image';
33289 if(!this.html.length && !this.bgimage.length){
33290 cls += ' roo-brick-center-title';
33293 if(!this.html.length && this.bgimage.length){
33294 cls += ' roo-brick-bottom-title';
33298 cls += ' ' + this.cls;
33302 tag: (this.href.length) ? 'a' : 'div',
33307 cls: 'roo-brick-paragraph',
33313 if(this.href.length){
33314 cfg.href = this.href;
33317 var cn = cfg.cn[0].cn;
33319 if(this.title.length){
33322 cls: 'roo-brick-title',
33327 if(this.html.length){
33330 cls: 'roo-brick-text',
33337 if(this.bgimage.length){
33340 cls: 'roo-brick-image-view',
33348 initEvents: function()
33350 if(this.title.length || this.html.length){
33351 this.el.on('mouseenter' ,this.enter, this);
33352 this.el.on('mouseleave', this.leave, this);
33355 Roo.EventManager.onWindowResize(this.resize, this);
33357 if(this.bgimage.length){
33358 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33359 this.imageEl.on('load', this.onImageLoad, this);
33366 onImageLoad : function()
33371 resize : function()
33373 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33375 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33377 if(this.bgimage.length){
33378 var image = this.el.select('.roo-brick-image-view', true).first();
33380 image.setWidth(paragraph.getWidth());
33383 image.setHeight(paragraph.getWidth());
33386 this.el.setHeight(image.getHeight());
33387 paragraph.setHeight(image.getHeight());
33393 enter: function(e, el)
33395 e.preventDefault();
33397 if(this.bgimage.length){
33398 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33399 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33403 leave: function(e, el)
33405 e.preventDefault();
33407 if(this.bgimage.length){
33408 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33409 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33424 * @class Roo.bootstrap.NumberField
33425 * @extends Roo.bootstrap.Input
33426 * Bootstrap NumberField class
33432 * Create a new NumberField
33433 * @param {Object} config The config object
33436 Roo.bootstrap.NumberField = function(config){
33437 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33440 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33443 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33445 allowDecimals : true,
33447 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33449 decimalSeparator : ".",
33451 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33453 decimalPrecision : 2,
33455 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33457 allowNegative : true,
33460 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33464 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33466 minValue : Number.NEGATIVE_INFINITY,
33468 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33470 maxValue : Number.MAX_VALUE,
33472 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33474 minText : "The minimum value for this field is {0}",
33476 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33478 maxText : "The maximum value for this field is {0}",
33480 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33481 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33483 nanText : "{0} is not a valid number",
33485 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33487 thousandsDelimiter : false,
33489 * @cfg {String} valueAlign alignment of value
33491 valueAlign : "left",
33493 getAutoCreate : function()
33495 var hiddenInput = {
33499 cls: 'hidden-number-input'
33503 hiddenInput.name = this.name;
33508 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33510 this.name = hiddenInput.name;
33512 if(cfg.cn.length > 0) {
33513 cfg.cn.push(hiddenInput);
33520 initEvents : function()
33522 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33524 var allowed = "0123456789";
33526 if(this.allowDecimals){
33527 allowed += this.decimalSeparator;
33530 if(this.allowNegative){
33534 if(this.thousandsDelimiter) {
33538 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33540 var keyPress = function(e){
33542 var k = e.getKey();
33544 var c = e.getCharCode();
33547 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33548 allowed.indexOf(String.fromCharCode(c)) === -1
33554 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33558 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33563 this.el.on("keypress", keyPress, this);
33566 validateValue : function(value)
33569 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33573 var num = this.parseValue(value);
33576 this.markInvalid(String.format(this.nanText, value));
33580 if(num < this.minValue){
33581 this.markInvalid(String.format(this.minText, this.minValue));
33585 if(num > this.maxValue){
33586 this.markInvalid(String.format(this.maxText, this.maxValue));
33593 getValue : function()
33595 var v = this.hiddenEl().getValue();
33597 return this.fixPrecision(this.parseValue(v));
33600 parseValue : function(value)
33602 if(this.thousandsDelimiter) {
33604 r = new RegExp(",", "g");
33605 value = value.replace(r, "");
33608 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33609 return isNaN(value) ? '' : value;
33612 fixPrecision : function(value)
33614 if(this.thousandsDelimiter) {
33616 r = new RegExp(",", "g");
33617 value = value.replace(r, "");
33620 var nan = isNaN(value);
33622 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33623 return nan ? '' : value;
33625 return parseFloat(value).toFixed(this.decimalPrecision);
33628 setValue : function(v)
33630 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33636 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33638 this.inputEl().dom.value = (v == '') ? '' :
33639 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33641 if(!this.allowZero && v === '0') {
33642 this.hiddenEl().dom.value = '';
33643 this.inputEl().dom.value = '';
33650 decimalPrecisionFcn : function(v)
33652 return Math.floor(v);
33655 beforeBlur : function()
33657 var v = this.parseValue(this.getRawValue());
33659 if(v || v === 0 || v === ''){
33664 hiddenEl : function()
33666 return this.el.select('input.hidden-number-input',true).first();
33678 * @class Roo.bootstrap.DocumentSlider
33679 * @extends Roo.bootstrap.Component
33680 * Bootstrap DocumentSlider class
33683 * Create a new DocumentViewer
33684 * @param {Object} config The config object
33687 Roo.bootstrap.DocumentSlider = function(config){
33688 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33695 * Fire after initEvent
33696 * @param {Roo.bootstrap.DocumentSlider} this
33701 * Fire after update
33702 * @param {Roo.bootstrap.DocumentSlider} this
33708 * @param {Roo.bootstrap.DocumentSlider} this
33714 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33720 getAutoCreate : function()
33724 cls : 'roo-document-slider',
33728 cls : 'roo-document-slider-header',
33732 cls : 'roo-document-slider-header-title'
33738 cls : 'roo-document-slider-body',
33742 cls : 'roo-document-slider-prev',
33746 cls : 'fa fa-chevron-left'
33752 cls : 'roo-document-slider-thumb',
33756 cls : 'roo-document-slider-image'
33762 cls : 'roo-document-slider-next',
33766 cls : 'fa fa-chevron-right'
33778 initEvents : function()
33780 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33781 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33783 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33784 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33786 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33787 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33789 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33790 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33792 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33793 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33795 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33796 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33798 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33799 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33801 this.thumbEl.on('click', this.onClick, this);
33803 this.prevIndicator.on('click', this.prev, this);
33805 this.nextIndicator.on('click', this.next, this);
33809 initial : function()
33811 if(this.files.length){
33812 this.indicator = 1;
33816 this.fireEvent('initial', this);
33819 update : function()
33821 this.imageEl.attr('src', this.files[this.indicator - 1]);
33823 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33825 this.prevIndicator.show();
33827 if(this.indicator == 1){
33828 this.prevIndicator.hide();
33831 this.nextIndicator.show();
33833 if(this.indicator == this.files.length){
33834 this.nextIndicator.hide();
33837 this.thumbEl.scrollTo('top');
33839 this.fireEvent('update', this);
33842 onClick : function(e)
33844 e.preventDefault();
33846 this.fireEvent('click', this);
33851 e.preventDefault();
33853 this.indicator = Math.max(1, this.indicator - 1);
33860 e.preventDefault();
33862 this.indicator = Math.min(this.files.length, this.indicator + 1);
33876 * @class Roo.bootstrap.RadioSet
33877 * @extends Roo.bootstrap.Input
33878 * Bootstrap RadioSet class
33879 * @cfg {String} indicatorpos (left|right) default left
33880 * @cfg {Boolean} inline (true|false) inline the element (default true)
33881 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33883 * Create a new RadioSet
33884 * @param {Object} config The config object
33887 Roo.bootstrap.RadioSet = function(config){
33889 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33893 Roo.bootstrap.RadioSet.register(this);
33898 * Fires when the element is checked or unchecked.
33899 * @param {Roo.bootstrap.RadioSet} this This radio
33900 * @param {Roo.bootstrap.Radio} item The checked item
33905 * Fires when the element is click.
33906 * @param {Roo.bootstrap.RadioSet} this This radio set
33907 * @param {Roo.bootstrap.Radio} item The checked item
33908 * @param {Roo.EventObject} e The event object
33915 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33923 indicatorpos : 'left',
33925 getAutoCreate : function()
33929 cls : 'roo-radio-set-label',
33933 html : this.fieldLabel
33938 if(this.indicatorpos == 'left'){
33941 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33942 tooltip : 'This field is required'
33947 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33948 tooltip : 'This field is required'
33954 cls : 'roo-radio-set-items'
33957 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33959 if (align === 'left' && this.fieldLabel.length) {
33962 cls : "roo-radio-set-right",
33968 if(this.labelWidth > 12){
33969 label.style = "width: " + this.labelWidth + 'px';
33972 if(this.labelWidth < 13 && this.labelmd == 0){
33973 this.labelmd = this.labelWidth;
33976 if(this.labellg > 0){
33977 label.cls += ' col-lg-' + this.labellg;
33978 items.cls += ' col-lg-' + (12 - this.labellg);
33981 if(this.labelmd > 0){
33982 label.cls += ' col-md-' + this.labelmd;
33983 items.cls += ' col-md-' + (12 - this.labelmd);
33986 if(this.labelsm > 0){
33987 label.cls += ' col-sm-' + this.labelsm;
33988 items.cls += ' col-sm-' + (12 - this.labelsm);
33991 if(this.labelxs > 0){
33992 label.cls += ' col-xs-' + this.labelxs;
33993 items.cls += ' col-xs-' + (12 - this.labelxs);
33999 cls : 'roo-radio-set',
34003 cls : 'roo-radio-set-input',
34006 value : this.value ? this.value : ''
34013 if(this.weight.length){
34014 cfg.cls += ' roo-radio-' + this.weight;
34018 cfg.cls += ' roo-radio-set-inline';
34022 ['xs','sm','md','lg'].map(function(size){
34023 if (settings[size]) {
34024 cfg.cls += ' col-' + size + '-' + settings[size];
34032 initEvents : function()
34034 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34035 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34037 if(!this.fieldLabel.length){
34038 this.labelEl.hide();
34041 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34042 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34044 this.indicator = this.indicatorEl();
34046 if(this.indicator){
34047 this.indicator.addClass('invisible');
34050 this.originalValue = this.getValue();
34054 inputEl: function ()
34056 return this.el.select('.roo-radio-set-input', true).first();
34059 getChildContainer : function()
34061 return this.itemsEl;
34064 register : function(item)
34066 this.radioes.push(item);
34070 validate : function()
34072 if(this.getVisibilityEl().hasClass('hidden')){
34078 Roo.each(this.radioes, function(i){
34087 if(this.allowBlank) {
34091 if(this.disabled || valid){
34096 this.markInvalid();
34101 markValid : function()
34103 if(this.labelEl.isVisible(true)){
34104 this.indicatorEl().removeClass('visible');
34105 this.indicatorEl().addClass('invisible');
34108 this.el.removeClass([this.invalidClass, this.validClass]);
34109 this.el.addClass(this.validClass);
34111 this.fireEvent('valid', this);
34114 markInvalid : function(msg)
34116 if(this.allowBlank || this.disabled){
34120 if(this.labelEl.isVisible(true)){
34121 this.indicatorEl().removeClass('invisible');
34122 this.indicatorEl().addClass('visible');
34125 this.el.removeClass([this.invalidClass, this.validClass]);
34126 this.el.addClass(this.invalidClass);
34128 this.fireEvent('invalid', this, msg);
34132 setValue : function(v, suppressEvent)
34134 if(this.value === v){
34141 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34144 Roo.each(this.radioes, function(i){
34146 i.el.removeClass('checked');
34149 Roo.each(this.radioes, function(i){
34151 if(i.value === v || i.value.toString() === v.toString()){
34153 i.el.addClass('checked');
34155 if(suppressEvent !== true){
34156 this.fireEvent('check', this, i);
34167 clearInvalid : function(){
34169 if(!this.el || this.preventMark){
34173 this.el.removeClass([this.invalidClass]);
34175 this.fireEvent('valid', this);
34180 Roo.apply(Roo.bootstrap.RadioSet, {
34184 register : function(set)
34186 this.groups[set.name] = set;
34189 get: function(name)
34191 if (typeof(this.groups[name]) == 'undefined') {
34195 return this.groups[name] ;
34201 * Ext JS Library 1.1.1
34202 * Copyright(c) 2006-2007, Ext JS, LLC.
34204 * Originally Released Under LGPL - original licence link has changed is not relivant.
34207 * <script type="text/javascript">
34212 * @class Roo.bootstrap.SplitBar
34213 * @extends Roo.util.Observable
34214 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34218 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34219 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34220 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34221 split.minSize = 100;
34222 split.maxSize = 600;
34223 split.animate = true;
34224 split.on('moved', splitterMoved);
34227 * Create a new SplitBar
34228 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34229 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34230 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34231 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34232 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34233 position of the SplitBar).
34235 Roo.bootstrap.SplitBar = function(cfg){
34240 // dragElement : elm
34241 // resizingElement: el,
34243 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34244 // placement : Roo.bootstrap.SplitBar.LEFT ,
34245 // existingProxy ???
34248 this.el = Roo.get(cfg.dragElement, true);
34249 this.el.dom.unselectable = "on";
34251 this.resizingEl = Roo.get(cfg.resizingElement, true);
34255 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34256 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34259 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34262 * The minimum size of the resizing element. (Defaults to 0)
34268 * The maximum size of the resizing element. (Defaults to 2000)
34271 this.maxSize = 2000;
34274 * Whether to animate the transition to the new size
34277 this.animate = false;
34280 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34283 this.useShim = false;
34288 if(!cfg.existingProxy){
34290 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34292 this.proxy = Roo.get(cfg.existingProxy).dom;
34295 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34298 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34301 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34304 this.dragSpecs = {};
34307 * @private The adapter to use to positon and resize elements
34309 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34310 this.adapter.init(this);
34312 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34314 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34315 this.el.addClass("roo-splitbar-h");
34318 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34319 this.el.addClass("roo-splitbar-v");
34325 * Fires when the splitter is moved (alias for {@link #event-moved})
34326 * @param {Roo.bootstrap.SplitBar} this
34327 * @param {Number} newSize the new width or height
34332 * Fires when the splitter is moved
34333 * @param {Roo.bootstrap.SplitBar} this
34334 * @param {Number} newSize the new width or height
34338 * @event beforeresize
34339 * Fires before the splitter is dragged
34340 * @param {Roo.bootstrap.SplitBar} this
34342 "beforeresize" : true,
34344 "beforeapply" : true
34347 Roo.util.Observable.call(this);
34350 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34351 onStartProxyDrag : function(x, y){
34352 this.fireEvent("beforeresize", this);
34354 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34356 o.enableDisplayMode("block");
34357 // all splitbars share the same overlay
34358 Roo.bootstrap.SplitBar.prototype.overlay = o;
34360 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34361 this.overlay.show();
34362 Roo.get(this.proxy).setDisplayed("block");
34363 var size = this.adapter.getElementSize(this);
34364 this.activeMinSize = this.getMinimumSize();;
34365 this.activeMaxSize = this.getMaximumSize();;
34366 var c1 = size - this.activeMinSize;
34367 var c2 = Math.max(this.activeMaxSize - size, 0);
34368 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34369 this.dd.resetConstraints();
34370 this.dd.setXConstraint(
34371 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34372 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34374 this.dd.setYConstraint(0, 0);
34376 this.dd.resetConstraints();
34377 this.dd.setXConstraint(0, 0);
34378 this.dd.setYConstraint(
34379 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34380 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34383 this.dragSpecs.startSize = size;
34384 this.dragSpecs.startPoint = [x, y];
34385 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34389 * @private Called after the drag operation by the DDProxy
34391 onEndProxyDrag : function(e){
34392 Roo.get(this.proxy).setDisplayed(false);
34393 var endPoint = Roo.lib.Event.getXY(e);
34395 this.overlay.hide();
34398 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34399 newSize = this.dragSpecs.startSize +
34400 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34401 endPoint[0] - this.dragSpecs.startPoint[0] :
34402 this.dragSpecs.startPoint[0] - endPoint[0]
34405 newSize = this.dragSpecs.startSize +
34406 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34407 endPoint[1] - this.dragSpecs.startPoint[1] :
34408 this.dragSpecs.startPoint[1] - endPoint[1]
34411 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34412 if(newSize != this.dragSpecs.startSize){
34413 if(this.fireEvent('beforeapply', this, newSize) !== false){
34414 this.adapter.setElementSize(this, newSize);
34415 this.fireEvent("moved", this, newSize);
34416 this.fireEvent("resize", this, newSize);
34422 * Get the adapter this SplitBar uses
34423 * @return The adapter object
34425 getAdapter : function(){
34426 return this.adapter;
34430 * Set the adapter this SplitBar uses
34431 * @param {Object} adapter A SplitBar adapter object
34433 setAdapter : function(adapter){
34434 this.adapter = adapter;
34435 this.adapter.init(this);
34439 * Gets the minimum size for the resizing element
34440 * @return {Number} The minimum size
34442 getMinimumSize : function(){
34443 return this.minSize;
34447 * Sets the minimum size for the resizing element
34448 * @param {Number} minSize The minimum size
34450 setMinimumSize : function(minSize){
34451 this.minSize = minSize;
34455 * Gets the maximum size for the resizing element
34456 * @return {Number} The maximum size
34458 getMaximumSize : function(){
34459 return this.maxSize;
34463 * Sets the maximum size for the resizing element
34464 * @param {Number} maxSize The maximum size
34466 setMaximumSize : function(maxSize){
34467 this.maxSize = maxSize;
34471 * Sets the initialize size for the resizing element
34472 * @param {Number} size The initial size
34474 setCurrentSize : function(size){
34475 var oldAnimate = this.animate;
34476 this.animate = false;
34477 this.adapter.setElementSize(this, size);
34478 this.animate = oldAnimate;
34482 * Destroy this splitbar.
34483 * @param {Boolean} removeEl True to remove the element
34485 destroy : function(removeEl){
34487 this.shim.remove();
34490 this.proxy.parentNode.removeChild(this.proxy);
34498 * @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.
34500 Roo.bootstrap.SplitBar.createProxy = function(dir){
34501 var proxy = new Roo.Element(document.createElement("div"));
34502 proxy.unselectable();
34503 var cls = 'roo-splitbar-proxy';
34504 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34505 document.body.appendChild(proxy.dom);
34510 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34511 * Default Adapter. It assumes the splitter and resizing element are not positioned
34512 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34514 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34517 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34518 // do nothing for now
34519 init : function(s){
34523 * Called before drag operations to get the current size of the resizing element.
34524 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34526 getElementSize : function(s){
34527 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34528 return s.resizingEl.getWidth();
34530 return s.resizingEl.getHeight();
34535 * Called after drag operations to set the size of the resizing element.
34536 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34537 * @param {Number} newSize The new size to set
34538 * @param {Function} onComplete A function to be invoked when resizing is complete
34540 setElementSize : function(s, newSize, onComplete){
34541 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34543 s.resizingEl.setWidth(newSize);
34545 onComplete(s, newSize);
34548 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34553 s.resizingEl.setHeight(newSize);
34555 onComplete(s, newSize);
34558 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34565 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34566 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34567 * Adapter that moves the splitter element to align with the resized sizing element.
34568 * Used with an absolute positioned SplitBar.
34569 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34570 * document.body, make sure you assign an id to the body element.
34572 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34573 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34574 this.container = Roo.get(container);
34577 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34578 init : function(s){
34579 this.basic.init(s);
34582 getElementSize : function(s){
34583 return this.basic.getElementSize(s);
34586 setElementSize : function(s, newSize, onComplete){
34587 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34590 moveSplitter : function(s){
34591 var yes = Roo.bootstrap.SplitBar;
34592 switch(s.placement){
34594 s.el.setX(s.resizingEl.getRight());
34597 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34600 s.el.setY(s.resizingEl.getBottom());
34603 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34610 * Orientation constant - Create a vertical SplitBar
34614 Roo.bootstrap.SplitBar.VERTICAL = 1;
34617 * Orientation constant - Create a horizontal SplitBar
34621 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34624 * Placement constant - The resizing element is to the left of the splitter element
34628 Roo.bootstrap.SplitBar.LEFT = 1;
34631 * Placement constant - The resizing element is to the right of the splitter element
34635 Roo.bootstrap.SplitBar.RIGHT = 2;
34638 * Placement constant - The resizing element is positioned above the splitter element
34642 Roo.bootstrap.SplitBar.TOP = 3;
34645 * Placement constant - The resizing element is positioned under splitter element
34649 Roo.bootstrap.SplitBar.BOTTOM = 4;
34650 Roo.namespace("Roo.bootstrap.layout");/*
34652 * Ext JS Library 1.1.1
34653 * Copyright(c) 2006-2007, Ext JS, LLC.
34655 * Originally Released Under LGPL - original licence link has changed is not relivant.
34658 * <script type="text/javascript">
34662 * @class Roo.bootstrap.layout.Manager
34663 * @extends Roo.bootstrap.Component
34664 * Base class for layout managers.
34666 Roo.bootstrap.layout.Manager = function(config)
34668 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34674 /** false to disable window resize monitoring @type Boolean */
34675 this.monitorWindowResize = true;
34680 * Fires when a layout is performed.
34681 * @param {Roo.LayoutManager} this
34685 * @event regionresized
34686 * Fires when the user resizes a region.
34687 * @param {Roo.LayoutRegion} region The resized region
34688 * @param {Number} newSize The new size (width for east/west, height for north/south)
34690 "regionresized" : true,
34692 * @event regioncollapsed
34693 * Fires when a region is collapsed.
34694 * @param {Roo.LayoutRegion} region The collapsed region
34696 "regioncollapsed" : true,
34698 * @event regionexpanded
34699 * Fires when a region is expanded.
34700 * @param {Roo.LayoutRegion} region The expanded region
34702 "regionexpanded" : true
34704 this.updating = false;
34707 this.el = Roo.get(config.el);
34713 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34718 monitorWindowResize : true,
34724 onRender : function(ct, position)
34727 this.el = Roo.get(ct);
34730 //this.fireEvent('render',this);
34734 initEvents: function()
34738 // ie scrollbar fix
34739 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34740 document.body.scroll = "no";
34741 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34742 this.el.position('relative');
34744 this.id = this.el.id;
34745 this.el.addClass("roo-layout-container");
34746 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34747 if(this.el.dom != document.body ) {
34748 this.el.on('resize', this.layout,this);
34749 this.el.on('show', this.layout,this);
34755 * Returns true if this layout is currently being updated
34756 * @return {Boolean}
34758 isUpdating : function(){
34759 return this.updating;
34763 * Suspend the LayoutManager from doing auto-layouts while
34764 * making multiple add or remove calls
34766 beginUpdate : function(){
34767 this.updating = true;
34771 * Restore auto-layouts and optionally disable the manager from performing a layout
34772 * @param {Boolean} noLayout true to disable a layout update
34774 endUpdate : function(noLayout){
34775 this.updating = false;
34781 layout: function(){
34785 onRegionResized : function(region, newSize){
34786 this.fireEvent("regionresized", region, newSize);
34790 onRegionCollapsed : function(region){
34791 this.fireEvent("regioncollapsed", region);
34794 onRegionExpanded : function(region){
34795 this.fireEvent("regionexpanded", region);
34799 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34800 * performs box-model adjustments.
34801 * @return {Object} The size as an object {width: (the width), height: (the height)}
34803 getViewSize : function()
34806 if(this.el.dom != document.body){
34807 size = this.el.getSize();
34809 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34811 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34812 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34817 * Returns the Element this layout is bound to.
34818 * @return {Roo.Element}
34820 getEl : function(){
34825 * Returns the specified region.
34826 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34827 * @return {Roo.LayoutRegion}
34829 getRegion : function(target){
34830 return this.regions[target.toLowerCase()];
34833 onWindowResize : function(){
34834 if(this.monitorWindowResize){
34841 * Ext JS Library 1.1.1
34842 * Copyright(c) 2006-2007, Ext JS, LLC.
34844 * Originally Released Under LGPL - original licence link has changed is not relivant.
34847 * <script type="text/javascript">
34850 * @class Roo.bootstrap.layout.Border
34851 * @extends Roo.bootstrap.layout.Manager
34852 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34853 * please see: examples/bootstrap/nested.html<br><br>
34855 <b>The container the layout is rendered into can be either the body element or any other element.
34856 If it is not the body element, the container needs to either be an absolute positioned element,
34857 or you will need to add "position:relative" to the css of the container. You will also need to specify
34858 the container size if it is not the body element.</b>
34861 * Create a new Border
34862 * @param {Object} config Configuration options
34864 Roo.bootstrap.layout.Border = function(config){
34865 config = config || {};
34866 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34870 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34871 if(config[region]){
34872 config[region].region = region;
34873 this.addRegion(config[region]);
34879 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34881 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34883 * Creates and adds a new region if it doesn't already exist.
34884 * @param {String} target The target region key (north, south, east, west or center).
34885 * @param {Object} config The regions config object
34886 * @return {BorderLayoutRegion} The new region
34888 addRegion : function(config)
34890 if(!this.regions[config.region]){
34891 var r = this.factory(config);
34892 this.bindRegion(r);
34894 return this.regions[config.region];
34898 bindRegion : function(r){
34899 this.regions[r.config.region] = r;
34901 r.on("visibilitychange", this.layout, this);
34902 r.on("paneladded", this.layout, this);
34903 r.on("panelremoved", this.layout, this);
34904 r.on("invalidated", this.layout, this);
34905 r.on("resized", this.onRegionResized, this);
34906 r.on("collapsed", this.onRegionCollapsed, this);
34907 r.on("expanded", this.onRegionExpanded, this);
34911 * Performs a layout update.
34913 layout : function()
34915 if(this.updating) {
34919 // render all the rebions if they have not been done alreayd?
34920 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34921 if(this.regions[region] && !this.regions[region].bodyEl){
34922 this.regions[region].onRender(this.el)
34926 var size = this.getViewSize();
34927 var w = size.width;
34928 var h = size.height;
34933 //var x = 0, y = 0;
34935 var rs = this.regions;
34936 var north = rs["north"];
34937 var south = rs["south"];
34938 var west = rs["west"];
34939 var east = rs["east"];
34940 var center = rs["center"];
34941 //if(this.hideOnLayout){ // not supported anymore
34942 //c.el.setStyle("display", "none");
34944 if(north && north.isVisible()){
34945 var b = north.getBox();
34946 var m = north.getMargins();
34947 b.width = w - (m.left+m.right);
34950 centerY = b.height + b.y + m.bottom;
34951 centerH -= centerY;
34952 north.updateBox(this.safeBox(b));
34954 if(south && south.isVisible()){
34955 var b = south.getBox();
34956 var m = south.getMargins();
34957 b.width = w - (m.left+m.right);
34959 var totalHeight = (b.height + m.top + m.bottom);
34960 b.y = h - totalHeight + m.top;
34961 centerH -= totalHeight;
34962 south.updateBox(this.safeBox(b));
34964 if(west && west.isVisible()){
34965 var b = west.getBox();
34966 var m = west.getMargins();
34967 b.height = centerH - (m.top+m.bottom);
34969 b.y = centerY + m.top;
34970 var totalWidth = (b.width + m.left + m.right);
34971 centerX += totalWidth;
34972 centerW -= totalWidth;
34973 west.updateBox(this.safeBox(b));
34975 if(east && east.isVisible()){
34976 var b = east.getBox();
34977 var m = east.getMargins();
34978 b.height = centerH - (m.top+m.bottom);
34979 var totalWidth = (b.width + m.left + m.right);
34980 b.x = w - totalWidth + m.left;
34981 b.y = centerY + m.top;
34982 centerW -= totalWidth;
34983 east.updateBox(this.safeBox(b));
34986 var m = center.getMargins();
34988 x: centerX + m.left,
34989 y: centerY + m.top,
34990 width: centerW - (m.left+m.right),
34991 height: centerH - (m.top+m.bottom)
34993 //if(this.hideOnLayout){
34994 //center.el.setStyle("display", "block");
34996 center.updateBox(this.safeBox(centerBox));
34999 this.fireEvent("layout", this);
35003 safeBox : function(box){
35004 box.width = Math.max(0, box.width);
35005 box.height = Math.max(0, box.height);
35010 * Adds a ContentPanel (or subclass) to this layout.
35011 * @param {String} target The target region key (north, south, east, west or center).
35012 * @param {Roo.ContentPanel} panel The panel to add
35013 * @return {Roo.ContentPanel} The added panel
35015 add : function(target, panel){
35017 target = target.toLowerCase();
35018 return this.regions[target].add(panel);
35022 * Remove a ContentPanel (or subclass) to this layout.
35023 * @param {String} target The target region key (north, south, east, west or center).
35024 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35025 * @return {Roo.ContentPanel} The removed panel
35027 remove : function(target, panel){
35028 target = target.toLowerCase();
35029 return this.regions[target].remove(panel);
35033 * Searches all regions for a panel with the specified id
35034 * @param {String} panelId
35035 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35037 findPanel : function(panelId){
35038 var rs = this.regions;
35039 for(var target in rs){
35040 if(typeof rs[target] != "function"){
35041 var p = rs[target].getPanel(panelId);
35051 * Searches all regions for a panel with the specified id and activates (shows) it.
35052 * @param {String/ContentPanel} panelId The panels id or the panel itself
35053 * @return {Roo.ContentPanel} The shown panel or null
35055 showPanel : function(panelId) {
35056 var rs = this.regions;
35057 for(var target in rs){
35058 var r = rs[target];
35059 if(typeof r != "function"){
35060 if(r.hasPanel(panelId)){
35061 return r.showPanel(panelId);
35069 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35070 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35073 restoreState : function(provider){
35075 provider = Roo.state.Manager;
35077 var sm = new Roo.LayoutStateManager();
35078 sm.init(this, provider);
35084 * Adds a xtype elements to the layout.
35088 xtype : 'ContentPanel',
35095 xtype : 'NestedLayoutPanel',
35101 items : [ ... list of content panels or nested layout panels.. ]
35105 * @param {Object} cfg Xtype definition of item to add.
35107 addxtype : function(cfg)
35109 // basically accepts a pannel...
35110 // can accept a layout region..!?!?
35111 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35114 // theory? children can only be panels??
35116 //if (!cfg.xtype.match(/Panel$/)) {
35121 if (typeof(cfg.region) == 'undefined') {
35122 Roo.log("Failed to add Panel, region was not set");
35126 var region = cfg.region;
35132 xitems = cfg.items;
35139 case 'Content': // ContentPanel (el, cfg)
35140 case 'Scroll': // ContentPanel (el, cfg)
35142 cfg.autoCreate = true;
35143 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35145 // var el = this.el.createChild();
35146 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35149 this.add(region, ret);
35153 case 'TreePanel': // our new panel!
35154 cfg.el = this.el.createChild();
35155 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35156 this.add(region, ret);
35161 // create a new Layout (which is a Border Layout...
35163 var clayout = cfg.layout;
35164 clayout.el = this.el.createChild();
35165 clayout.items = clayout.items || [];
35169 // replace this exitems with the clayout ones..
35170 xitems = clayout.items;
35172 // force background off if it's in center...
35173 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35174 cfg.background = false;
35176 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35179 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35180 //console.log('adding nested layout panel ' + cfg.toSource());
35181 this.add(region, ret);
35182 nb = {}; /// find first...
35187 // needs grid and region
35189 //var el = this.getRegion(region).el.createChild();
35191 *var el = this.el.createChild();
35192 // create the grid first...
35193 cfg.grid.container = el;
35194 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35197 if (region == 'center' && this.active ) {
35198 cfg.background = false;
35201 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35203 this.add(region, ret);
35205 if (cfg.background) {
35206 // render grid on panel activation (if panel background)
35207 ret.on('activate', function(gp) {
35208 if (!gp.grid.rendered) {
35209 // gp.grid.render(el);
35213 // cfg.grid.render(el);
35219 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35220 // it was the old xcomponent building that caused this before.
35221 // espeically if border is the top element in the tree.
35231 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35233 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35234 this.add(region, ret);
35238 throw "Can not add '" + cfg.xtype + "' to Border";
35244 this.beginUpdate();
35248 Roo.each(xitems, function(i) {
35249 region = nb && i.region ? i.region : false;
35251 var add = ret.addxtype(i);
35254 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35255 if (!i.background) {
35256 abn[region] = nb[region] ;
35263 // make the last non-background panel active..
35264 //if (nb) { Roo.log(abn); }
35267 for(var r in abn) {
35268 region = this.getRegion(r);
35270 // tried using nb[r], but it does not work..
35272 region.showPanel(abn[r]);
35283 factory : function(cfg)
35286 var validRegions = Roo.bootstrap.layout.Border.regions;
35288 var target = cfg.region;
35291 var r = Roo.bootstrap.layout;
35295 return new r.North(cfg);
35297 return new r.South(cfg);
35299 return new r.East(cfg);
35301 return new r.West(cfg);
35303 return new r.Center(cfg);
35305 throw 'Layout region "'+target+'" not supported.';
35312 * Ext JS Library 1.1.1
35313 * Copyright(c) 2006-2007, Ext JS, LLC.
35315 * Originally Released Under LGPL - original licence link has changed is not relivant.
35318 * <script type="text/javascript">
35322 * @class Roo.bootstrap.layout.Basic
35323 * @extends Roo.util.Observable
35324 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35325 * and does not have a titlebar, tabs or any other features. All it does is size and position
35326 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35327 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35328 * @cfg {string} region the region that it inhabits..
35329 * @cfg {bool} skipConfig skip config?
35333 Roo.bootstrap.layout.Basic = function(config){
35335 this.mgr = config.mgr;
35337 this.position = config.region;
35339 var skipConfig = config.skipConfig;
35343 * @scope Roo.BasicLayoutRegion
35347 * @event beforeremove
35348 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35349 * @param {Roo.LayoutRegion} this
35350 * @param {Roo.ContentPanel} panel The panel
35351 * @param {Object} e The cancel event object
35353 "beforeremove" : true,
35355 * @event invalidated
35356 * Fires when the layout for this region is changed.
35357 * @param {Roo.LayoutRegion} this
35359 "invalidated" : true,
35361 * @event visibilitychange
35362 * Fires when this region is shown or hidden
35363 * @param {Roo.LayoutRegion} this
35364 * @param {Boolean} visibility true or false
35366 "visibilitychange" : true,
35368 * @event paneladded
35369 * Fires when a panel is added.
35370 * @param {Roo.LayoutRegion} this
35371 * @param {Roo.ContentPanel} panel The panel
35373 "paneladded" : true,
35375 * @event panelremoved
35376 * Fires when a panel is removed.
35377 * @param {Roo.LayoutRegion} this
35378 * @param {Roo.ContentPanel} panel The panel
35380 "panelremoved" : true,
35382 * @event beforecollapse
35383 * Fires when this region before collapse.
35384 * @param {Roo.LayoutRegion} this
35386 "beforecollapse" : true,
35389 * Fires when this region is collapsed.
35390 * @param {Roo.LayoutRegion} this
35392 "collapsed" : true,
35395 * Fires when this region is expanded.
35396 * @param {Roo.LayoutRegion} this
35401 * Fires when this region is slid into view.
35402 * @param {Roo.LayoutRegion} this
35404 "slideshow" : true,
35407 * Fires when this region slides out of view.
35408 * @param {Roo.LayoutRegion} this
35410 "slidehide" : true,
35412 * @event panelactivated
35413 * Fires when a panel is activated.
35414 * @param {Roo.LayoutRegion} this
35415 * @param {Roo.ContentPanel} panel The activated panel
35417 "panelactivated" : true,
35420 * Fires when the user resizes this region.
35421 * @param {Roo.LayoutRegion} this
35422 * @param {Number} newSize The new size (width for east/west, height for north/south)
35426 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35427 this.panels = new Roo.util.MixedCollection();
35428 this.panels.getKey = this.getPanelId.createDelegate(this);
35430 this.activePanel = null;
35431 // ensure listeners are added...
35433 if (config.listeners || config.events) {
35434 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35435 listeners : config.listeners || {},
35436 events : config.events || {}
35440 if(skipConfig !== true){
35441 this.applyConfig(config);
35445 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35447 getPanelId : function(p){
35451 applyConfig : function(config){
35452 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35453 this.config = config;
35458 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35459 * the width, for horizontal (north, south) the height.
35460 * @param {Number} newSize The new width or height
35462 resizeTo : function(newSize){
35463 var el = this.el ? this.el :
35464 (this.activePanel ? this.activePanel.getEl() : null);
35466 switch(this.position){
35469 el.setWidth(newSize);
35470 this.fireEvent("resized", this, newSize);
35474 el.setHeight(newSize);
35475 this.fireEvent("resized", this, newSize);
35481 getBox : function(){
35482 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35485 getMargins : function(){
35486 return this.margins;
35489 updateBox : function(box){
35491 var el = this.activePanel.getEl();
35492 el.dom.style.left = box.x + "px";
35493 el.dom.style.top = box.y + "px";
35494 this.activePanel.setSize(box.width, box.height);
35498 * Returns the container element for this region.
35499 * @return {Roo.Element}
35501 getEl : function(){
35502 return this.activePanel;
35506 * Returns true if this region is currently visible.
35507 * @return {Boolean}
35509 isVisible : function(){
35510 return this.activePanel ? true : false;
35513 setActivePanel : function(panel){
35514 panel = this.getPanel(panel);
35515 if(this.activePanel && this.activePanel != panel){
35516 this.activePanel.setActiveState(false);
35517 this.activePanel.getEl().setLeftTop(-10000,-10000);
35519 this.activePanel = panel;
35520 panel.setActiveState(true);
35522 panel.setSize(this.box.width, this.box.height);
35524 this.fireEvent("panelactivated", this, panel);
35525 this.fireEvent("invalidated");
35529 * Show the specified panel.
35530 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35531 * @return {Roo.ContentPanel} The shown panel or null
35533 showPanel : function(panel){
35534 panel = this.getPanel(panel);
35536 this.setActivePanel(panel);
35542 * Get the active panel for this region.
35543 * @return {Roo.ContentPanel} The active panel or null
35545 getActivePanel : function(){
35546 return this.activePanel;
35550 * Add the passed ContentPanel(s)
35551 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35552 * @return {Roo.ContentPanel} The panel added (if only one was added)
35554 add : function(panel){
35555 if(arguments.length > 1){
35556 for(var i = 0, len = arguments.length; i < len; i++) {
35557 this.add(arguments[i]);
35561 if(this.hasPanel(panel)){
35562 this.showPanel(panel);
35565 var el = panel.getEl();
35566 if(el.dom.parentNode != this.mgr.el.dom){
35567 this.mgr.el.dom.appendChild(el.dom);
35569 if(panel.setRegion){
35570 panel.setRegion(this);
35572 this.panels.add(panel);
35573 el.setStyle("position", "absolute");
35574 if(!panel.background){
35575 this.setActivePanel(panel);
35576 if(this.config.initialSize && this.panels.getCount()==1){
35577 this.resizeTo(this.config.initialSize);
35580 this.fireEvent("paneladded", this, panel);
35585 * Returns true if the panel is in this region.
35586 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35587 * @return {Boolean}
35589 hasPanel : function(panel){
35590 if(typeof panel == "object"){ // must be panel obj
35591 panel = panel.getId();
35593 return this.getPanel(panel) ? true : false;
35597 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35598 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35599 * @param {Boolean} preservePanel Overrides the config preservePanel option
35600 * @return {Roo.ContentPanel} The panel that was removed
35602 remove : function(panel, preservePanel){
35603 panel = this.getPanel(panel);
35608 this.fireEvent("beforeremove", this, panel, e);
35609 if(e.cancel === true){
35612 var panelId = panel.getId();
35613 this.panels.removeKey(panelId);
35618 * Returns the panel specified or null if it's not in this region.
35619 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35620 * @return {Roo.ContentPanel}
35622 getPanel : function(id){
35623 if(typeof id == "object"){ // must be panel obj
35626 return this.panels.get(id);
35630 * Returns this regions position (north/south/east/west/center).
35633 getPosition: function(){
35634 return this.position;
35638 * Ext JS Library 1.1.1
35639 * Copyright(c) 2006-2007, Ext JS, LLC.
35641 * Originally Released Under LGPL - original licence link has changed is not relivant.
35644 * <script type="text/javascript">
35648 * @class Roo.bootstrap.layout.Region
35649 * @extends Roo.bootstrap.layout.Basic
35650 * This class represents a region in a layout manager.
35652 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35653 * @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})
35654 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35655 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35656 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35657 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35658 * @cfg {String} title The title for the region (overrides panel titles)
35659 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35660 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35661 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35662 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35663 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35664 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35665 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35666 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35667 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35668 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35670 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35671 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35672 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35673 * @cfg {Number} width For East/West panels
35674 * @cfg {Number} height For North/South panels
35675 * @cfg {Boolean} split To show the splitter
35676 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35678 * @cfg {string} cls Extra CSS classes to add to region
35680 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35681 * @cfg {string} region the region that it inhabits..
35684 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35685 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35687 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35688 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35689 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35691 Roo.bootstrap.layout.Region = function(config)
35693 this.applyConfig(config);
35695 var mgr = config.mgr;
35696 var pos = config.region;
35697 config.skipConfig = true;
35698 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35701 this.onRender(mgr.el);
35704 this.visible = true;
35705 this.collapsed = false;
35706 this.unrendered_panels = [];
35709 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35711 position: '', // set by wrapper (eg. north/south etc..)
35712 unrendered_panels : null, // unrendered panels.
35713 createBody : function(){
35714 /** This region's body element
35715 * @type Roo.Element */
35716 this.bodyEl = this.el.createChild({
35718 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35722 onRender: function(ctr, pos)
35724 var dh = Roo.DomHelper;
35725 /** This region's container element
35726 * @type Roo.Element */
35727 this.el = dh.append(ctr.dom, {
35729 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35731 /** This region's title element
35732 * @type Roo.Element */
35734 this.titleEl = dh.append(this.el.dom,
35737 unselectable: "on",
35738 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35740 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35741 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35744 this.titleEl.enableDisplayMode();
35745 /** This region's title text element
35746 * @type HTMLElement */
35747 this.titleTextEl = this.titleEl.dom.firstChild;
35748 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35750 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35751 this.closeBtn.enableDisplayMode();
35752 this.closeBtn.on("click", this.closeClicked, this);
35753 this.closeBtn.hide();
35755 this.createBody(this.config);
35756 if(this.config.hideWhenEmpty){
35758 this.on("paneladded", this.validateVisibility, this);
35759 this.on("panelremoved", this.validateVisibility, this);
35761 if(this.autoScroll){
35762 this.bodyEl.setStyle("overflow", "auto");
35764 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35766 //if(c.titlebar !== false){
35767 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35768 this.titleEl.hide();
35770 this.titleEl.show();
35771 if(this.config.title){
35772 this.titleTextEl.innerHTML = this.config.title;
35776 if(this.config.collapsed){
35777 this.collapse(true);
35779 if(this.config.hidden){
35783 if (this.unrendered_panels && this.unrendered_panels.length) {
35784 for (var i =0;i< this.unrendered_panels.length; i++) {
35785 this.add(this.unrendered_panels[i]);
35787 this.unrendered_panels = null;
35793 applyConfig : function(c)
35796 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35797 var dh = Roo.DomHelper;
35798 if(c.titlebar !== false){
35799 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35800 this.collapseBtn.on("click", this.collapse, this);
35801 this.collapseBtn.enableDisplayMode();
35803 if(c.showPin === true || this.showPin){
35804 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35805 this.stickBtn.enableDisplayMode();
35806 this.stickBtn.on("click", this.expand, this);
35807 this.stickBtn.hide();
35812 /** This region's collapsed element
35813 * @type Roo.Element */
35816 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35817 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35820 if(c.floatable !== false){
35821 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35822 this.collapsedEl.on("click", this.collapseClick, this);
35825 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35826 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35827 id: "message", unselectable: "on", style:{"float":"left"}});
35828 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35830 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35831 this.expandBtn.on("click", this.expand, this);
35835 if(this.collapseBtn){
35836 this.collapseBtn.setVisible(c.collapsible == true);
35839 this.cmargins = c.cmargins || this.cmargins ||
35840 (this.position == "west" || this.position == "east" ?
35841 {top: 0, left: 2, right:2, bottom: 0} :
35842 {top: 2, left: 0, right:0, bottom: 2});
35844 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35847 this.bottomTabs = c.tabPosition != "top";
35849 this.autoScroll = c.autoScroll || false;
35854 this.duration = c.duration || .30;
35855 this.slideDuration = c.slideDuration || .45;
35860 * Returns true if this region is currently visible.
35861 * @return {Boolean}
35863 isVisible : function(){
35864 return this.visible;
35868 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35869 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35871 //setCollapsedTitle : function(title){
35872 // title = title || " ";
35873 // if(this.collapsedTitleTextEl){
35874 // this.collapsedTitleTextEl.innerHTML = title;
35878 getBox : function(){
35880 // if(!this.collapsed){
35881 b = this.el.getBox(false, true);
35883 // b = this.collapsedEl.getBox(false, true);
35888 getMargins : function(){
35889 return this.margins;
35890 //return this.collapsed ? this.cmargins : this.margins;
35893 highlight : function(){
35894 this.el.addClass("x-layout-panel-dragover");
35897 unhighlight : function(){
35898 this.el.removeClass("x-layout-panel-dragover");
35901 updateBox : function(box)
35903 if (!this.bodyEl) {
35904 return; // not rendered yet..
35908 if(!this.collapsed){
35909 this.el.dom.style.left = box.x + "px";
35910 this.el.dom.style.top = box.y + "px";
35911 this.updateBody(box.width, box.height);
35913 this.collapsedEl.dom.style.left = box.x + "px";
35914 this.collapsedEl.dom.style.top = box.y + "px";
35915 this.collapsedEl.setSize(box.width, box.height);
35918 this.tabs.autoSizeTabs();
35922 updateBody : function(w, h)
35925 this.el.setWidth(w);
35926 w -= this.el.getBorderWidth("rl");
35927 if(this.config.adjustments){
35928 w += this.config.adjustments[0];
35931 if(h !== null && h > 0){
35932 this.el.setHeight(h);
35933 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35934 h -= this.el.getBorderWidth("tb");
35935 if(this.config.adjustments){
35936 h += this.config.adjustments[1];
35938 this.bodyEl.setHeight(h);
35940 h = this.tabs.syncHeight(h);
35943 if(this.panelSize){
35944 w = w !== null ? w : this.panelSize.width;
35945 h = h !== null ? h : this.panelSize.height;
35947 if(this.activePanel){
35948 var el = this.activePanel.getEl();
35949 w = w !== null ? w : el.getWidth();
35950 h = h !== null ? h : el.getHeight();
35951 this.panelSize = {width: w, height: h};
35952 this.activePanel.setSize(w, h);
35954 if(Roo.isIE && this.tabs){
35955 this.tabs.el.repaint();
35960 * Returns the container element for this region.
35961 * @return {Roo.Element}
35963 getEl : function(){
35968 * Hides this region.
35971 //if(!this.collapsed){
35972 this.el.dom.style.left = "-2000px";
35975 // this.collapsedEl.dom.style.left = "-2000px";
35976 // this.collapsedEl.hide();
35978 this.visible = false;
35979 this.fireEvent("visibilitychange", this, false);
35983 * Shows this region if it was previously hidden.
35986 //if(!this.collapsed){
35989 // this.collapsedEl.show();
35991 this.visible = true;
35992 this.fireEvent("visibilitychange", this, true);
35995 closeClicked : function(){
35996 if(this.activePanel){
35997 this.remove(this.activePanel);
36001 collapseClick : function(e){
36003 e.stopPropagation();
36006 e.stopPropagation();
36012 * Collapses this region.
36013 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36016 collapse : function(skipAnim, skipCheck = false){
36017 if(this.collapsed) {
36021 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36023 this.collapsed = true;
36025 this.split.el.hide();
36027 if(this.config.animate && skipAnim !== true){
36028 this.fireEvent("invalidated", this);
36029 this.animateCollapse();
36031 this.el.setLocation(-20000,-20000);
36033 this.collapsedEl.show();
36034 this.fireEvent("collapsed", this);
36035 this.fireEvent("invalidated", this);
36041 animateCollapse : function(){
36046 * Expands this region if it was previously collapsed.
36047 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36048 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36051 expand : function(e, skipAnim){
36053 e.stopPropagation();
36055 if(!this.collapsed || this.el.hasActiveFx()) {
36059 this.afterSlideIn();
36062 this.collapsed = false;
36063 if(this.config.animate && skipAnim !== true){
36064 this.animateExpand();
36068 this.split.el.show();
36070 this.collapsedEl.setLocation(-2000,-2000);
36071 this.collapsedEl.hide();
36072 this.fireEvent("invalidated", this);
36073 this.fireEvent("expanded", this);
36077 animateExpand : function(){
36081 initTabs : function()
36083 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36085 var ts = new Roo.bootstrap.panel.Tabs({
36086 el: this.bodyEl.dom,
36087 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36088 disableTooltips: this.config.disableTabTips,
36089 toolbar : this.config.toolbar
36092 if(this.config.hideTabs){
36093 ts.stripWrap.setDisplayed(false);
36096 ts.resizeTabs = this.config.resizeTabs === true;
36097 ts.minTabWidth = this.config.minTabWidth || 40;
36098 ts.maxTabWidth = this.config.maxTabWidth || 250;
36099 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36100 ts.monitorResize = false;
36101 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36102 ts.bodyEl.addClass('roo-layout-tabs-body');
36103 this.panels.each(this.initPanelAsTab, this);
36106 initPanelAsTab : function(panel){
36107 var ti = this.tabs.addTab(
36111 this.config.closeOnTab && panel.isClosable(),
36114 if(panel.tabTip !== undefined){
36115 ti.setTooltip(panel.tabTip);
36117 ti.on("activate", function(){
36118 this.setActivePanel(panel);
36121 if(this.config.closeOnTab){
36122 ti.on("beforeclose", function(t, e){
36124 this.remove(panel);
36128 panel.tabItem = ti;
36133 updatePanelTitle : function(panel, title)
36135 if(this.activePanel == panel){
36136 this.updateTitle(title);
36139 var ti = this.tabs.getTab(panel.getEl().id);
36141 if(panel.tabTip !== undefined){
36142 ti.setTooltip(panel.tabTip);
36147 updateTitle : function(title){
36148 if(this.titleTextEl && !this.config.title){
36149 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36153 setActivePanel : function(panel)
36155 panel = this.getPanel(panel);
36156 if(this.activePanel && this.activePanel != panel){
36157 if(this.activePanel.setActiveState(false) === false){
36161 this.activePanel = panel;
36162 panel.setActiveState(true);
36163 if(this.panelSize){
36164 panel.setSize(this.panelSize.width, this.panelSize.height);
36167 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36169 this.updateTitle(panel.getTitle());
36171 this.fireEvent("invalidated", this);
36173 this.fireEvent("panelactivated", this, panel);
36177 * Shows the specified panel.
36178 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36179 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36181 showPanel : function(panel)
36183 panel = this.getPanel(panel);
36186 var tab = this.tabs.getTab(panel.getEl().id);
36187 if(tab.isHidden()){
36188 this.tabs.unhideTab(tab.id);
36192 this.setActivePanel(panel);
36199 * Get the active panel for this region.
36200 * @return {Roo.ContentPanel} The active panel or null
36202 getActivePanel : function(){
36203 return this.activePanel;
36206 validateVisibility : function(){
36207 if(this.panels.getCount() < 1){
36208 this.updateTitle(" ");
36209 this.closeBtn.hide();
36212 if(!this.isVisible()){
36219 * Adds the passed ContentPanel(s) to this region.
36220 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36221 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36223 add : function(panel)
36225 if(arguments.length > 1){
36226 for(var i = 0, len = arguments.length; i < len; i++) {
36227 this.add(arguments[i]);
36232 // if we have not been rendered yet, then we can not really do much of this..
36233 if (!this.bodyEl) {
36234 this.unrendered_panels.push(panel);
36241 if(this.hasPanel(panel)){
36242 this.showPanel(panel);
36245 panel.setRegion(this);
36246 this.panels.add(panel);
36247 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36248 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36249 // and hide them... ???
36250 this.bodyEl.dom.appendChild(panel.getEl().dom);
36251 if(panel.background !== true){
36252 this.setActivePanel(panel);
36254 this.fireEvent("paneladded", this, panel);
36261 this.initPanelAsTab(panel);
36265 if(panel.background !== true){
36266 this.tabs.activate(panel.getEl().id);
36268 this.fireEvent("paneladded", this, panel);
36273 * Hides the tab for the specified panel.
36274 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36276 hidePanel : function(panel){
36277 if(this.tabs && (panel = this.getPanel(panel))){
36278 this.tabs.hideTab(panel.getEl().id);
36283 * Unhides the tab for a previously hidden panel.
36284 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36286 unhidePanel : function(panel){
36287 if(this.tabs && (panel = this.getPanel(panel))){
36288 this.tabs.unhideTab(panel.getEl().id);
36292 clearPanels : function(){
36293 while(this.panels.getCount() > 0){
36294 this.remove(this.panels.first());
36299 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36300 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36301 * @param {Boolean} preservePanel Overrides the config preservePanel option
36302 * @return {Roo.ContentPanel} The panel that was removed
36304 remove : function(panel, preservePanel)
36306 panel = this.getPanel(panel);
36311 this.fireEvent("beforeremove", this, panel, e);
36312 if(e.cancel === true){
36315 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36316 var panelId = panel.getId();
36317 this.panels.removeKey(panelId);
36319 document.body.appendChild(panel.getEl().dom);
36322 this.tabs.removeTab(panel.getEl().id);
36323 }else if (!preservePanel){
36324 this.bodyEl.dom.removeChild(panel.getEl().dom);
36326 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36327 var p = this.panels.first();
36328 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36329 tempEl.appendChild(p.getEl().dom);
36330 this.bodyEl.update("");
36331 this.bodyEl.dom.appendChild(p.getEl().dom);
36333 this.updateTitle(p.getTitle());
36335 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36336 this.setActivePanel(p);
36338 panel.setRegion(null);
36339 if(this.activePanel == panel){
36340 this.activePanel = null;
36342 if(this.config.autoDestroy !== false && preservePanel !== true){
36343 try{panel.destroy();}catch(e){}
36345 this.fireEvent("panelremoved", this, panel);
36350 * Returns the TabPanel component used by this region
36351 * @return {Roo.TabPanel}
36353 getTabs : function(){
36357 createTool : function(parentEl, className){
36358 var btn = Roo.DomHelper.append(parentEl, {
36360 cls: "x-layout-tools-button",
36363 cls: "roo-layout-tools-button-inner " + className,
36367 btn.addClassOnOver("roo-layout-tools-button-over");
36372 * Ext JS Library 1.1.1
36373 * Copyright(c) 2006-2007, Ext JS, LLC.
36375 * Originally Released Under LGPL - original licence link has changed is not relivant.
36378 * <script type="text/javascript">
36384 * @class Roo.SplitLayoutRegion
36385 * @extends Roo.LayoutRegion
36386 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36388 Roo.bootstrap.layout.Split = function(config){
36389 this.cursor = config.cursor;
36390 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36393 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36395 splitTip : "Drag to resize.",
36396 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36397 useSplitTips : false,
36399 applyConfig : function(config){
36400 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36403 onRender : function(ctr,pos) {
36405 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36406 if(!this.config.split){
36411 var splitEl = Roo.DomHelper.append(ctr.dom, {
36413 id: this.el.id + "-split",
36414 cls: "roo-layout-split roo-layout-split-"+this.position,
36417 /** The SplitBar for this region
36418 * @type Roo.SplitBar */
36419 // does not exist yet...
36420 Roo.log([this.position, this.orientation]);
36422 this.split = new Roo.bootstrap.SplitBar({
36423 dragElement : splitEl,
36424 resizingElement: this.el,
36425 orientation : this.orientation
36428 this.split.on("moved", this.onSplitMove, this);
36429 this.split.useShim = this.config.useShim === true;
36430 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36431 if(this.useSplitTips){
36432 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36434 //if(config.collapsible){
36435 // this.split.el.on("dblclick", this.collapse, this);
36438 if(typeof this.config.minSize != "undefined"){
36439 this.split.minSize = this.config.minSize;
36441 if(typeof this.config.maxSize != "undefined"){
36442 this.split.maxSize = this.config.maxSize;
36444 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36445 this.hideSplitter();
36450 getHMaxSize : function(){
36451 var cmax = this.config.maxSize || 10000;
36452 var center = this.mgr.getRegion("center");
36453 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36456 getVMaxSize : function(){
36457 var cmax = this.config.maxSize || 10000;
36458 var center = this.mgr.getRegion("center");
36459 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36462 onSplitMove : function(split, newSize){
36463 this.fireEvent("resized", this, newSize);
36467 * Returns the {@link Roo.SplitBar} for this region.
36468 * @return {Roo.SplitBar}
36470 getSplitBar : function(){
36475 this.hideSplitter();
36476 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36479 hideSplitter : function(){
36481 this.split.el.setLocation(-2000,-2000);
36482 this.split.el.hide();
36488 this.split.el.show();
36490 Roo.bootstrap.layout.Split.superclass.show.call(this);
36493 beforeSlide: function(){
36494 if(Roo.isGecko){// firefox overflow auto bug workaround
36495 this.bodyEl.clip();
36497 this.tabs.bodyEl.clip();
36499 if(this.activePanel){
36500 this.activePanel.getEl().clip();
36502 if(this.activePanel.beforeSlide){
36503 this.activePanel.beforeSlide();
36509 afterSlide : function(){
36510 if(Roo.isGecko){// firefox overflow auto bug workaround
36511 this.bodyEl.unclip();
36513 this.tabs.bodyEl.unclip();
36515 if(this.activePanel){
36516 this.activePanel.getEl().unclip();
36517 if(this.activePanel.afterSlide){
36518 this.activePanel.afterSlide();
36524 initAutoHide : function(){
36525 if(this.autoHide !== false){
36526 if(!this.autoHideHd){
36527 var st = new Roo.util.DelayedTask(this.slideIn, this);
36528 this.autoHideHd = {
36529 "mouseout": function(e){
36530 if(!e.within(this.el, true)){
36534 "mouseover" : function(e){
36540 this.el.on(this.autoHideHd);
36544 clearAutoHide : function(){
36545 if(this.autoHide !== false){
36546 this.el.un("mouseout", this.autoHideHd.mouseout);
36547 this.el.un("mouseover", this.autoHideHd.mouseover);
36551 clearMonitor : function(){
36552 Roo.get(document).un("click", this.slideInIf, this);
36555 // these names are backwards but not changed for compat
36556 slideOut : function(){
36557 if(this.isSlid || this.el.hasActiveFx()){
36560 this.isSlid = true;
36561 if(this.collapseBtn){
36562 this.collapseBtn.hide();
36564 this.closeBtnState = this.closeBtn.getStyle('display');
36565 this.closeBtn.hide();
36567 this.stickBtn.show();
36570 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36571 this.beforeSlide();
36572 this.el.setStyle("z-index", 10001);
36573 this.el.slideIn(this.getSlideAnchor(), {
36574 callback: function(){
36576 this.initAutoHide();
36577 Roo.get(document).on("click", this.slideInIf, this);
36578 this.fireEvent("slideshow", this);
36585 afterSlideIn : function(){
36586 this.clearAutoHide();
36587 this.isSlid = false;
36588 this.clearMonitor();
36589 this.el.setStyle("z-index", "");
36590 if(this.collapseBtn){
36591 this.collapseBtn.show();
36593 this.closeBtn.setStyle('display', this.closeBtnState);
36595 this.stickBtn.hide();
36597 this.fireEvent("slidehide", this);
36600 slideIn : function(cb){
36601 if(!this.isSlid || this.el.hasActiveFx()){
36605 this.isSlid = false;
36606 this.beforeSlide();
36607 this.el.slideOut(this.getSlideAnchor(), {
36608 callback: function(){
36609 this.el.setLeftTop(-10000, -10000);
36611 this.afterSlideIn();
36619 slideInIf : function(e){
36620 if(!e.within(this.el)){
36625 animateCollapse : function(){
36626 this.beforeSlide();
36627 this.el.setStyle("z-index", 20000);
36628 var anchor = this.getSlideAnchor();
36629 this.el.slideOut(anchor, {
36630 callback : function(){
36631 this.el.setStyle("z-index", "");
36632 this.collapsedEl.slideIn(anchor, {duration:.3});
36634 this.el.setLocation(-10000,-10000);
36636 this.fireEvent("collapsed", this);
36643 animateExpand : function(){
36644 this.beforeSlide();
36645 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36646 this.el.setStyle("z-index", 20000);
36647 this.collapsedEl.hide({
36650 this.el.slideIn(this.getSlideAnchor(), {
36651 callback : function(){
36652 this.el.setStyle("z-index", "");
36655 this.split.el.show();
36657 this.fireEvent("invalidated", this);
36658 this.fireEvent("expanded", this);
36686 getAnchor : function(){
36687 return this.anchors[this.position];
36690 getCollapseAnchor : function(){
36691 return this.canchors[this.position];
36694 getSlideAnchor : function(){
36695 return this.sanchors[this.position];
36698 getAlignAdj : function(){
36699 var cm = this.cmargins;
36700 switch(this.position){
36716 getExpandAdj : function(){
36717 var c = this.collapsedEl, cm = this.cmargins;
36718 switch(this.position){
36720 return [-(cm.right+c.getWidth()+cm.left), 0];
36723 return [cm.right+c.getWidth()+cm.left, 0];
36726 return [0, -(cm.top+cm.bottom+c.getHeight())];
36729 return [0, cm.top+cm.bottom+c.getHeight()];
36735 * Ext JS Library 1.1.1
36736 * Copyright(c) 2006-2007, Ext JS, LLC.
36738 * Originally Released Under LGPL - original licence link has changed is not relivant.
36741 * <script type="text/javascript">
36744 * These classes are private internal classes
36746 Roo.bootstrap.layout.Center = function(config){
36747 config.region = "center";
36748 Roo.bootstrap.layout.Region.call(this, config);
36749 this.visible = true;
36750 this.minWidth = config.minWidth || 20;
36751 this.minHeight = config.minHeight || 20;
36754 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36756 // center panel can't be hidden
36760 // center panel can't be hidden
36763 getMinWidth: function(){
36764 return this.minWidth;
36767 getMinHeight: function(){
36768 return this.minHeight;
36781 Roo.bootstrap.layout.North = function(config)
36783 config.region = 'north';
36784 config.cursor = 'n-resize';
36786 Roo.bootstrap.layout.Split.call(this, config);
36790 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36791 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36792 this.split.el.addClass("roo-layout-split-v");
36794 var size = config.initialSize || config.height;
36795 if(typeof size != "undefined"){
36796 this.el.setHeight(size);
36799 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36801 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36805 getBox : function(){
36806 if(this.collapsed){
36807 return this.collapsedEl.getBox();
36809 var box = this.el.getBox();
36811 box.height += this.split.el.getHeight();
36816 updateBox : function(box){
36817 if(this.split && !this.collapsed){
36818 box.height -= this.split.el.getHeight();
36819 this.split.el.setLeft(box.x);
36820 this.split.el.setTop(box.y+box.height);
36821 this.split.el.setWidth(box.width);
36823 if(this.collapsed){
36824 this.updateBody(box.width, null);
36826 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36834 Roo.bootstrap.layout.South = function(config){
36835 config.region = 'south';
36836 config.cursor = 's-resize';
36837 Roo.bootstrap.layout.Split.call(this, config);
36839 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36840 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36841 this.split.el.addClass("roo-layout-split-v");
36843 var size = config.initialSize || config.height;
36844 if(typeof size != "undefined"){
36845 this.el.setHeight(size);
36849 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36850 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36851 getBox : function(){
36852 if(this.collapsed){
36853 return this.collapsedEl.getBox();
36855 var box = this.el.getBox();
36857 var sh = this.split.el.getHeight();
36864 updateBox : function(box){
36865 if(this.split && !this.collapsed){
36866 var sh = this.split.el.getHeight();
36869 this.split.el.setLeft(box.x);
36870 this.split.el.setTop(box.y-sh);
36871 this.split.el.setWidth(box.width);
36873 if(this.collapsed){
36874 this.updateBody(box.width, null);
36876 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36880 Roo.bootstrap.layout.East = function(config){
36881 config.region = "east";
36882 config.cursor = "e-resize";
36883 Roo.bootstrap.layout.Split.call(this, config);
36885 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36886 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36887 this.split.el.addClass("roo-layout-split-h");
36889 var size = config.initialSize || config.width;
36890 if(typeof size != "undefined"){
36891 this.el.setWidth(size);
36894 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36895 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36896 getBox : function(){
36897 if(this.collapsed){
36898 return this.collapsedEl.getBox();
36900 var box = this.el.getBox();
36902 var sw = this.split.el.getWidth();
36909 updateBox : function(box){
36910 if(this.split && !this.collapsed){
36911 var sw = this.split.el.getWidth();
36913 this.split.el.setLeft(box.x);
36914 this.split.el.setTop(box.y);
36915 this.split.el.setHeight(box.height);
36918 if(this.collapsed){
36919 this.updateBody(null, box.height);
36921 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36925 Roo.bootstrap.layout.West = function(config){
36926 config.region = "west";
36927 config.cursor = "w-resize";
36929 Roo.bootstrap.layout.Split.call(this, config);
36931 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36932 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36933 this.split.el.addClass("roo-layout-split-h");
36937 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36938 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36940 onRender: function(ctr, pos)
36942 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36943 var size = this.config.initialSize || this.config.width;
36944 if(typeof size != "undefined"){
36945 this.el.setWidth(size);
36949 getBox : function(){
36950 if(this.collapsed){
36951 return this.collapsedEl.getBox();
36953 var box = this.el.getBox();
36955 box.width += this.split.el.getWidth();
36960 updateBox : function(box){
36961 if(this.split && !this.collapsed){
36962 var sw = this.split.el.getWidth();
36964 this.split.el.setLeft(box.x+box.width);
36965 this.split.el.setTop(box.y);
36966 this.split.el.setHeight(box.height);
36968 if(this.collapsed){
36969 this.updateBody(null, box.height);
36971 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36974 Roo.namespace("Roo.bootstrap.panel");/*
36976 * Ext JS Library 1.1.1
36977 * Copyright(c) 2006-2007, Ext JS, LLC.
36979 * Originally Released Under LGPL - original licence link has changed is not relivant.
36982 * <script type="text/javascript">
36985 * @class Roo.ContentPanel
36986 * @extends Roo.util.Observable
36987 * A basic ContentPanel element.
36988 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36989 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36990 * @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
36991 * @cfg {Boolean} closable True if the panel can be closed/removed
36992 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36993 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36994 * @cfg {Toolbar} toolbar A toolbar for this panel
36995 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36996 * @cfg {String} title The title for this panel
36997 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36998 * @cfg {String} url Calls {@link #setUrl} with this value
36999 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37000 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37001 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37002 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37003 * @cfg {Boolean} badges render the badges
37006 * Create a new ContentPanel.
37007 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37008 * @param {String/Object} config A string to set only the title or a config object
37009 * @param {String} content (optional) Set the HTML content for this panel
37010 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37012 Roo.bootstrap.panel.Content = function( config){
37014 this.tpl = config.tpl || false;
37016 var el = config.el;
37017 var content = config.content;
37019 if(config.autoCreate){ // xtype is available if this is called from factory
37022 this.el = Roo.get(el);
37023 if(!this.el && config && config.autoCreate){
37024 if(typeof config.autoCreate == "object"){
37025 if(!config.autoCreate.id){
37026 config.autoCreate.id = config.id||el;
37028 this.el = Roo.DomHelper.append(document.body,
37029 config.autoCreate, true);
37031 var elcfg = { tag: "div",
37032 cls: "roo-layout-inactive-content",
37036 elcfg.html = config.html;
37040 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37043 this.closable = false;
37044 this.loaded = false;
37045 this.active = false;
37048 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37050 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37052 this.wrapEl = this.el; //this.el.wrap();
37054 if (config.toolbar.items) {
37055 ti = config.toolbar.items ;
37056 delete config.toolbar.items ;
37060 this.toolbar.render(this.wrapEl, 'before');
37061 for(var i =0;i < ti.length;i++) {
37062 // Roo.log(['add child', items[i]]);
37063 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37065 this.toolbar.items = nitems;
37066 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37067 delete config.toolbar;
37071 // xtype created footer. - not sure if will work as we normally have to render first..
37072 if (this.footer && !this.footer.el && this.footer.xtype) {
37073 if (!this.wrapEl) {
37074 this.wrapEl = this.el.wrap();
37077 this.footer.container = this.wrapEl.createChild();
37079 this.footer = Roo.factory(this.footer, Roo);
37084 if(typeof config == "string"){
37085 this.title = config;
37087 Roo.apply(this, config);
37091 this.resizeEl = Roo.get(this.resizeEl, true);
37093 this.resizeEl = this.el;
37095 // handle view.xtype
37103 * Fires when this panel is activated.
37104 * @param {Roo.ContentPanel} this
37108 * @event deactivate
37109 * Fires when this panel is activated.
37110 * @param {Roo.ContentPanel} this
37112 "deactivate" : true,
37116 * Fires when this panel is resized if fitToFrame is true.
37117 * @param {Roo.ContentPanel} this
37118 * @param {Number} width The width after any component adjustments
37119 * @param {Number} height The height after any component adjustments
37125 * Fires when this tab is created
37126 * @param {Roo.ContentPanel} this
37137 if(this.autoScroll){
37138 this.resizeEl.setStyle("overflow", "auto");
37140 // fix randome scrolling
37141 //this.el.on('scroll', function() {
37142 // Roo.log('fix random scolling');
37143 // this.scrollTo('top',0);
37146 content = content || this.content;
37148 this.setContent(content);
37150 if(config && config.url){
37151 this.setUrl(this.url, this.params, this.loadOnce);
37156 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37158 if (this.view && typeof(this.view.xtype) != 'undefined') {
37159 this.view.el = this.el.appendChild(document.createElement("div"));
37160 this.view = Roo.factory(this.view);
37161 this.view.render && this.view.render(false, '');
37165 this.fireEvent('render', this);
37168 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37172 setRegion : function(region){
37173 this.region = region;
37174 this.setActiveClass(region && !this.background);
37178 setActiveClass: function(state)
37181 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37182 this.el.setStyle('position','relative');
37184 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37185 this.el.setStyle('position', 'absolute');
37190 * Returns the toolbar for this Panel if one was configured.
37191 * @return {Roo.Toolbar}
37193 getToolbar : function(){
37194 return this.toolbar;
37197 setActiveState : function(active)
37199 this.active = active;
37200 this.setActiveClass(active);
37202 if(this.fireEvent("deactivate", this) === false){
37207 this.fireEvent("activate", this);
37211 * Updates this panel's element
37212 * @param {String} content The new content
37213 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37215 setContent : function(content, loadScripts){
37216 this.el.update(content, loadScripts);
37219 ignoreResize : function(w, h){
37220 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37223 this.lastSize = {width: w, height: h};
37228 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37229 * @return {Roo.UpdateManager} The UpdateManager
37231 getUpdateManager : function(){
37232 return this.el.getUpdateManager();
37235 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37236 * @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:
37239 url: "your-url.php",
37240 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37241 callback: yourFunction,
37242 scope: yourObject, //(optional scope)
37245 text: "Loading...",
37250 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37251 * 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.
37252 * @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}
37253 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37254 * @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.
37255 * @return {Roo.ContentPanel} this
37258 var um = this.el.getUpdateManager();
37259 um.update.apply(um, arguments);
37265 * 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.
37266 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37267 * @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)
37268 * @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)
37269 * @return {Roo.UpdateManager} The UpdateManager
37271 setUrl : function(url, params, loadOnce){
37272 if(this.refreshDelegate){
37273 this.removeListener("activate", this.refreshDelegate);
37275 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37276 this.on("activate", this.refreshDelegate);
37277 return this.el.getUpdateManager();
37280 _handleRefresh : function(url, params, loadOnce){
37281 if(!loadOnce || !this.loaded){
37282 var updater = this.el.getUpdateManager();
37283 updater.update(url, params, this._setLoaded.createDelegate(this));
37287 _setLoaded : function(){
37288 this.loaded = true;
37292 * Returns this panel's id
37295 getId : function(){
37300 * Returns this panel's element - used by regiosn to add.
37301 * @return {Roo.Element}
37303 getEl : function(){
37304 return this.wrapEl || this.el;
37309 adjustForComponents : function(width, height)
37311 //Roo.log('adjustForComponents ');
37312 if(this.resizeEl != this.el){
37313 width -= this.el.getFrameWidth('lr');
37314 height -= this.el.getFrameWidth('tb');
37317 var te = this.toolbar.getEl();
37318 te.setWidth(width);
37319 height -= te.getHeight();
37322 var te = this.footer.getEl();
37323 te.setWidth(width);
37324 height -= te.getHeight();
37328 if(this.adjustments){
37329 width += this.adjustments[0];
37330 height += this.adjustments[1];
37332 return {"width": width, "height": height};
37335 setSize : function(width, height){
37336 if(this.fitToFrame && !this.ignoreResize(width, height)){
37337 if(this.fitContainer && this.resizeEl != this.el){
37338 this.el.setSize(width, height);
37340 var size = this.adjustForComponents(width, height);
37341 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37342 this.fireEvent('resize', this, size.width, size.height);
37347 * Returns this panel's title
37350 getTitle : function(){
37352 if (typeof(this.title) != 'object') {
37357 for (var k in this.title) {
37358 if (!this.title.hasOwnProperty(k)) {
37362 if (k.indexOf('-') >= 0) {
37363 var s = k.split('-');
37364 for (var i = 0; i<s.length; i++) {
37365 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37368 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37375 * Set this panel's title
37376 * @param {String} title
37378 setTitle : function(title){
37379 this.title = title;
37381 this.region.updatePanelTitle(this, title);
37386 * Returns true is this panel was configured to be closable
37387 * @return {Boolean}
37389 isClosable : function(){
37390 return this.closable;
37393 beforeSlide : function(){
37395 this.resizeEl.clip();
37398 afterSlide : function(){
37400 this.resizeEl.unclip();
37404 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37405 * Will fail silently if the {@link #setUrl} method has not been called.
37406 * This does not activate the panel, just updates its content.
37408 refresh : function(){
37409 if(this.refreshDelegate){
37410 this.loaded = false;
37411 this.refreshDelegate();
37416 * Destroys this panel
37418 destroy : function(){
37419 this.el.removeAllListeners();
37420 var tempEl = document.createElement("span");
37421 tempEl.appendChild(this.el.dom);
37422 tempEl.innerHTML = "";
37428 * form - if the content panel contains a form - this is a reference to it.
37429 * @type {Roo.form.Form}
37433 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37434 * This contains a reference to it.
37440 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37450 * @param {Object} cfg Xtype definition of item to add.
37454 getChildContainer: function () {
37455 return this.getEl();
37460 var ret = new Roo.factory(cfg);
37465 if (cfg.xtype.match(/^Form$/)) {
37468 //if (this.footer) {
37469 // el = this.footer.container.insertSibling(false, 'before');
37471 el = this.el.createChild();
37474 this.form = new Roo.form.Form(cfg);
37477 if ( this.form.allItems.length) {
37478 this.form.render(el.dom);
37482 // should only have one of theses..
37483 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37484 // views.. should not be just added - used named prop 'view''
37486 cfg.el = this.el.appendChild(document.createElement("div"));
37489 var ret = new Roo.factory(cfg);
37491 ret.render && ret.render(false, ''); // render blank..
37501 * @class Roo.bootstrap.panel.Grid
37502 * @extends Roo.bootstrap.panel.Content
37504 * Create a new GridPanel.
37505 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37506 * @param {Object} config A the config object
37512 Roo.bootstrap.panel.Grid = function(config)
37516 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37517 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37519 config.el = this.wrapper;
37520 //this.el = this.wrapper;
37522 if (config.container) {
37523 // ctor'ed from a Border/panel.grid
37526 this.wrapper.setStyle("overflow", "hidden");
37527 this.wrapper.addClass('roo-grid-container');
37532 if(config.toolbar){
37533 var tool_el = this.wrapper.createChild();
37534 this.toolbar = Roo.factory(config.toolbar);
37536 if (config.toolbar.items) {
37537 ti = config.toolbar.items ;
37538 delete config.toolbar.items ;
37542 this.toolbar.render(tool_el);
37543 for(var i =0;i < ti.length;i++) {
37544 // Roo.log(['add child', items[i]]);
37545 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37547 this.toolbar.items = nitems;
37549 delete config.toolbar;
37552 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37553 config.grid.scrollBody = true;;
37554 config.grid.monitorWindowResize = false; // turn off autosizing
37555 config.grid.autoHeight = false;
37556 config.grid.autoWidth = false;
37558 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37560 if (config.background) {
37561 // render grid on panel activation (if panel background)
37562 this.on('activate', function(gp) {
37563 if (!gp.grid.rendered) {
37564 gp.grid.render(this.wrapper);
37565 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37570 this.grid.render(this.wrapper);
37571 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37574 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37575 // ??? needed ??? config.el = this.wrapper;
37580 // xtype created footer. - not sure if will work as we normally have to render first..
37581 if (this.footer && !this.footer.el && this.footer.xtype) {
37583 var ctr = this.grid.getView().getFooterPanel(true);
37584 this.footer.dataSource = this.grid.dataSource;
37585 this.footer = Roo.factory(this.footer, Roo);
37586 this.footer.render(ctr);
37596 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37597 getId : function(){
37598 return this.grid.id;
37602 * Returns the grid for this panel
37603 * @return {Roo.bootstrap.Table}
37605 getGrid : function(){
37609 setSize : function(width, height){
37610 if(!this.ignoreResize(width, height)){
37611 var grid = this.grid;
37612 var size = this.adjustForComponents(width, height);
37613 var gridel = grid.getGridEl();
37614 gridel.setSize(size.width, size.height);
37616 var thd = grid.getGridEl().select('thead',true).first();
37617 var tbd = grid.getGridEl().select('tbody', true).first();
37619 tbd.setSize(width, height - thd.getHeight());
37628 beforeSlide : function(){
37629 this.grid.getView().scroller.clip();
37632 afterSlide : function(){
37633 this.grid.getView().scroller.unclip();
37636 destroy : function(){
37637 this.grid.destroy();
37639 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37644 * @class Roo.bootstrap.panel.Nest
37645 * @extends Roo.bootstrap.panel.Content
37647 * Create a new Panel, that can contain a layout.Border.
37650 * @param {Roo.BorderLayout} layout The layout for this panel
37651 * @param {String/Object} config A string to set only the title or a config object
37653 Roo.bootstrap.panel.Nest = function(config)
37655 // construct with only one argument..
37656 /* FIXME - implement nicer consturctors
37657 if (layout.layout) {
37659 layout = config.layout;
37660 delete config.layout;
37662 if (layout.xtype && !layout.getEl) {
37663 // then layout needs constructing..
37664 layout = Roo.factory(layout, Roo);
37668 config.el = config.layout.getEl();
37670 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37672 config.layout.monitorWindowResize = false; // turn off autosizing
37673 this.layout = config.layout;
37674 this.layout.getEl().addClass("roo-layout-nested-layout");
37681 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37683 setSize : function(width, height){
37684 if(!this.ignoreResize(width, height)){
37685 var size = this.adjustForComponents(width, height);
37686 var el = this.layout.getEl();
37687 if (size.height < 1) {
37688 el.setWidth(size.width);
37690 el.setSize(size.width, size.height);
37692 var touch = el.dom.offsetWidth;
37693 this.layout.layout();
37694 // ie requires a double layout on the first pass
37695 if(Roo.isIE && !this.initialized){
37696 this.initialized = true;
37697 this.layout.layout();
37702 // activate all subpanels if not currently active..
37704 setActiveState : function(active){
37705 this.active = active;
37706 this.setActiveClass(active);
37709 this.fireEvent("deactivate", this);
37713 this.fireEvent("activate", this);
37714 // not sure if this should happen before or after..
37715 if (!this.layout) {
37716 return; // should not happen..
37719 for (var r in this.layout.regions) {
37720 reg = this.layout.getRegion(r);
37721 if (reg.getActivePanel()) {
37722 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37723 reg.setActivePanel(reg.getActivePanel());
37726 if (!reg.panels.length) {
37729 reg.showPanel(reg.getPanel(0));
37738 * Returns the nested BorderLayout for this panel
37739 * @return {Roo.BorderLayout}
37741 getLayout : function(){
37742 return this.layout;
37746 * Adds a xtype elements to the layout of the nested panel
37750 xtype : 'ContentPanel',
37757 xtype : 'NestedLayoutPanel',
37763 items : [ ... list of content panels or nested layout panels.. ]
37767 * @param {Object} cfg Xtype definition of item to add.
37769 addxtype : function(cfg) {
37770 return this.layout.addxtype(cfg);
37775 * Ext JS Library 1.1.1
37776 * Copyright(c) 2006-2007, Ext JS, LLC.
37778 * Originally Released Under LGPL - original licence link has changed is not relivant.
37781 * <script type="text/javascript">
37784 * @class Roo.TabPanel
37785 * @extends Roo.util.Observable
37786 * A lightweight tab container.
37790 // basic tabs 1, built from existing content
37791 var tabs = new Roo.TabPanel("tabs1");
37792 tabs.addTab("script", "View Script");
37793 tabs.addTab("markup", "View Markup");
37794 tabs.activate("script");
37796 // more advanced tabs, built from javascript
37797 var jtabs = new Roo.TabPanel("jtabs");
37798 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37800 // set up the UpdateManager
37801 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37802 var updater = tab2.getUpdateManager();
37803 updater.setDefaultUrl("ajax1.htm");
37804 tab2.on('activate', updater.refresh, updater, true);
37806 // Use setUrl for Ajax loading
37807 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37808 tab3.setUrl("ajax2.htm", null, true);
37811 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37814 jtabs.activate("jtabs-1");
37817 * Create a new TabPanel.
37818 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37819 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37821 Roo.bootstrap.panel.Tabs = function(config){
37823 * The container element for this TabPanel.
37824 * @type Roo.Element
37826 this.el = Roo.get(config.el);
37829 if(typeof config == "boolean"){
37830 this.tabPosition = config ? "bottom" : "top";
37832 Roo.apply(this, config);
37836 if(this.tabPosition == "bottom"){
37837 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37838 this.el.addClass("roo-tabs-bottom");
37840 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37841 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37842 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37844 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37846 if(this.tabPosition != "bottom"){
37847 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37848 * @type Roo.Element
37850 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37851 this.el.addClass("roo-tabs-top");
37855 this.bodyEl.setStyle("position", "relative");
37857 this.active = null;
37858 this.activateDelegate = this.activate.createDelegate(this);
37863 * Fires when the active tab changes
37864 * @param {Roo.TabPanel} this
37865 * @param {Roo.TabPanelItem} activePanel The new active tab
37869 * @event beforetabchange
37870 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37871 * @param {Roo.TabPanel} this
37872 * @param {Object} e Set cancel to true on this object to cancel the tab change
37873 * @param {Roo.TabPanelItem} tab The tab being changed to
37875 "beforetabchange" : true
37878 Roo.EventManager.onWindowResize(this.onResize, this);
37879 this.cpad = this.el.getPadding("lr");
37880 this.hiddenCount = 0;
37883 // toolbar on the tabbar support...
37884 if (this.toolbar) {
37885 alert("no toolbar support yet");
37886 this.toolbar = false;
37888 var tcfg = this.toolbar;
37889 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37890 this.toolbar = new Roo.Toolbar(tcfg);
37891 if (Roo.isSafari) {
37892 var tbl = tcfg.container.child('table', true);
37893 tbl.setAttribute('width', '100%');
37901 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37904 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37906 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37908 tabPosition : "top",
37910 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37912 currentTabWidth : 0,
37914 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37918 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37922 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37924 preferredTabWidth : 175,
37926 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37928 resizeTabs : false,
37930 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37932 monitorResize : true,
37934 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37939 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37940 * @param {String} id The id of the div to use <b>or create</b>
37941 * @param {String} text The text for the tab
37942 * @param {String} content (optional) Content to put in the TabPanelItem body
37943 * @param {Boolean} closable (optional) True to create a close icon on the tab
37944 * @return {Roo.TabPanelItem} The created TabPanelItem
37946 addTab : function(id, text, content, closable, tpl)
37948 var item = new Roo.bootstrap.panel.TabItem({
37952 closable : closable,
37955 this.addTabItem(item);
37957 item.setContent(content);
37963 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37964 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37965 * @return {Roo.TabPanelItem}
37967 getTab : function(id){
37968 return this.items[id];
37972 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37973 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37975 hideTab : function(id){
37976 var t = this.items[id];
37979 this.hiddenCount++;
37980 this.autoSizeTabs();
37985 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37986 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37988 unhideTab : function(id){
37989 var t = this.items[id];
37991 t.setHidden(false);
37992 this.hiddenCount--;
37993 this.autoSizeTabs();
37998 * Adds an existing {@link Roo.TabPanelItem}.
37999 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38001 addTabItem : function(item){
38002 this.items[item.id] = item;
38003 this.items.push(item);
38004 // if(this.resizeTabs){
38005 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38006 // this.autoSizeTabs();
38008 // item.autoSize();
38013 * Removes a {@link Roo.TabPanelItem}.
38014 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38016 removeTab : function(id){
38017 var items = this.items;
38018 var tab = items[id];
38019 if(!tab) { return; }
38020 var index = items.indexOf(tab);
38021 if(this.active == tab && items.length > 1){
38022 var newTab = this.getNextAvailable(index);
38027 this.stripEl.dom.removeChild(tab.pnode.dom);
38028 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38029 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38031 items.splice(index, 1);
38032 delete this.items[tab.id];
38033 tab.fireEvent("close", tab);
38034 tab.purgeListeners();
38035 this.autoSizeTabs();
38038 getNextAvailable : function(start){
38039 var items = this.items;
38041 // look for a next tab that will slide over to
38042 // replace the one being removed
38043 while(index < items.length){
38044 var item = items[++index];
38045 if(item && !item.isHidden()){
38049 // if one isn't found select the previous tab (on the left)
38052 var item = items[--index];
38053 if(item && !item.isHidden()){
38061 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38062 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38064 disableTab : function(id){
38065 var tab = this.items[id];
38066 if(tab && this.active != tab){
38072 * Enables a {@link Roo.TabPanelItem} that is disabled.
38073 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38075 enableTab : function(id){
38076 var tab = this.items[id];
38081 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38082 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38083 * @return {Roo.TabPanelItem} The TabPanelItem.
38085 activate : function(id){
38086 var tab = this.items[id];
38090 if(tab == this.active || tab.disabled){
38094 this.fireEvent("beforetabchange", this, e, tab);
38095 if(e.cancel !== true && !tab.disabled){
38097 this.active.hide();
38099 this.active = this.items[id];
38100 this.active.show();
38101 this.fireEvent("tabchange", this, this.active);
38107 * Gets the active {@link Roo.TabPanelItem}.
38108 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38110 getActiveTab : function(){
38111 return this.active;
38115 * Updates the tab body element to fit the height of the container element
38116 * for overflow scrolling
38117 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38119 syncHeight : function(targetHeight){
38120 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38121 var bm = this.bodyEl.getMargins();
38122 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38123 this.bodyEl.setHeight(newHeight);
38127 onResize : function(){
38128 if(this.monitorResize){
38129 this.autoSizeTabs();
38134 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38136 beginUpdate : function(){
38137 this.updating = true;
38141 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38143 endUpdate : function(){
38144 this.updating = false;
38145 this.autoSizeTabs();
38149 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38151 autoSizeTabs : function(){
38152 var count = this.items.length;
38153 var vcount = count - this.hiddenCount;
38154 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38157 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38158 var availWidth = Math.floor(w / vcount);
38159 var b = this.stripBody;
38160 if(b.getWidth() > w){
38161 var tabs = this.items;
38162 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38163 if(availWidth < this.minTabWidth){
38164 /*if(!this.sleft){ // incomplete scrolling code
38165 this.createScrollButtons();
38168 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38171 if(this.currentTabWidth < this.preferredTabWidth){
38172 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38178 * Returns the number of tabs in this TabPanel.
38181 getCount : function(){
38182 return this.items.length;
38186 * Resizes all the tabs to the passed width
38187 * @param {Number} The new width
38189 setTabWidth : function(width){
38190 this.currentTabWidth = width;
38191 for(var i = 0, len = this.items.length; i < len; i++) {
38192 if(!this.items[i].isHidden()) {
38193 this.items[i].setWidth(width);
38199 * Destroys this TabPanel
38200 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38202 destroy : function(removeEl){
38203 Roo.EventManager.removeResizeListener(this.onResize, this);
38204 for(var i = 0, len = this.items.length; i < len; i++){
38205 this.items[i].purgeListeners();
38207 if(removeEl === true){
38208 this.el.update("");
38213 createStrip : function(container)
38215 var strip = document.createElement("nav");
38216 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38217 container.appendChild(strip);
38221 createStripList : function(strip)
38223 // div wrapper for retard IE
38224 // returns the "tr" element.
38225 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38226 //'<div class="x-tabs-strip-wrap">'+
38227 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38228 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38229 return strip.firstChild; //.firstChild.firstChild.firstChild;
38231 createBody : function(container)
38233 var body = document.createElement("div");
38234 Roo.id(body, "tab-body");
38235 //Roo.fly(body).addClass("x-tabs-body");
38236 Roo.fly(body).addClass("tab-content");
38237 container.appendChild(body);
38240 createItemBody :function(bodyEl, id){
38241 var body = Roo.getDom(id);
38243 body = document.createElement("div");
38246 //Roo.fly(body).addClass("x-tabs-item-body");
38247 Roo.fly(body).addClass("tab-pane");
38248 bodyEl.insertBefore(body, bodyEl.firstChild);
38252 createStripElements : function(stripEl, text, closable, tpl)
38254 var td = document.createElement("li"); // was td..
38257 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38260 stripEl.appendChild(td);
38262 td.className = "x-tabs-closable";
38263 if(!this.closeTpl){
38264 this.closeTpl = new Roo.Template(
38265 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38266 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38267 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38270 var el = this.closeTpl.overwrite(td, {"text": text});
38271 var close = el.getElementsByTagName("div")[0];
38272 var inner = el.getElementsByTagName("em")[0];
38273 return {"el": el, "close": close, "inner": inner};
38276 // not sure what this is..
38277 // if(!this.tabTpl){
38278 //this.tabTpl = new Roo.Template(
38279 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38280 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38282 // this.tabTpl = new Roo.Template(
38283 // '<a href="#">' +
38284 // '<span unselectable="on"' +
38285 // (this.disableTooltips ? '' : ' title="{text}"') +
38286 // ' >{text}</span></a>'
38292 var template = tpl || this.tabTpl || false;
38296 template = new Roo.Template(
38298 '<span unselectable="on"' +
38299 (this.disableTooltips ? '' : ' title="{text}"') +
38300 ' >{text}</span></a>'
38304 switch (typeof(template)) {
38308 template = new Roo.Template(template);
38314 var el = template.overwrite(td, {"text": text});
38316 var inner = el.getElementsByTagName("span")[0];
38318 return {"el": el, "inner": inner};
38326 * @class Roo.TabPanelItem
38327 * @extends Roo.util.Observable
38328 * Represents an individual item (tab plus body) in a TabPanel.
38329 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38330 * @param {String} id The id of this TabPanelItem
38331 * @param {String} text The text for the tab of this TabPanelItem
38332 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38334 Roo.bootstrap.panel.TabItem = function(config){
38336 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38337 * @type Roo.TabPanel
38339 this.tabPanel = config.panel;
38341 * The id for this TabPanelItem
38344 this.id = config.id;
38346 this.disabled = false;
38348 this.text = config.text;
38350 this.loaded = false;
38351 this.closable = config.closable;
38354 * The body element for this TabPanelItem.
38355 * @type Roo.Element
38357 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38358 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38359 this.bodyEl.setStyle("display", "block");
38360 this.bodyEl.setStyle("zoom", "1");
38361 //this.hideAction();
38363 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38365 this.el = Roo.get(els.el);
38366 this.inner = Roo.get(els.inner, true);
38367 this.textEl = Roo.get(this.el.dom.firstChild, true);
38368 this.pnode = Roo.get(els.el.parentNode, true);
38369 // this.el.on("mousedown", this.onTabMouseDown, this);
38370 this.el.on("click", this.onTabClick, this);
38372 if(config.closable){
38373 var c = Roo.get(els.close, true);
38374 c.dom.title = this.closeText;
38375 c.addClassOnOver("close-over");
38376 c.on("click", this.closeClick, this);
38382 * Fires when this tab becomes the active tab.
38383 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38384 * @param {Roo.TabPanelItem} this
38388 * @event beforeclose
38389 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38390 * @param {Roo.TabPanelItem} this
38391 * @param {Object} e Set cancel to true on this object to cancel the close.
38393 "beforeclose": true,
38396 * Fires when this tab is closed.
38397 * @param {Roo.TabPanelItem} this
38401 * @event deactivate
38402 * Fires when this tab is no longer the active tab.
38403 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38404 * @param {Roo.TabPanelItem} this
38406 "deactivate" : true
38408 this.hidden = false;
38410 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38413 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38415 purgeListeners : function(){
38416 Roo.util.Observable.prototype.purgeListeners.call(this);
38417 this.el.removeAllListeners();
38420 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38423 this.pnode.addClass("active");
38426 this.tabPanel.stripWrap.repaint();
38428 this.fireEvent("activate", this.tabPanel, this);
38432 * Returns true if this tab is the active tab.
38433 * @return {Boolean}
38435 isActive : function(){
38436 return this.tabPanel.getActiveTab() == this;
38440 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38443 this.pnode.removeClass("active");
38445 this.fireEvent("deactivate", this.tabPanel, this);
38448 hideAction : function(){
38449 this.bodyEl.hide();
38450 this.bodyEl.setStyle("position", "absolute");
38451 this.bodyEl.setLeft("-20000px");
38452 this.bodyEl.setTop("-20000px");
38455 showAction : function(){
38456 this.bodyEl.setStyle("position", "relative");
38457 this.bodyEl.setTop("");
38458 this.bodyEl.setLeft("");
38459 this.bodyEl.show();
38463 * Set the tooltip for the tab.
38464 * @param {String} tooltip The tab's tooltip
38466 setTooltip : function(text){
38467 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38468 this.textEl.dom.qtip = text;
38469 this.textEl.dom.removeAttribute('title');
38471 this.textEl.dom.title = text;
38475 onTabClick : function(e){
38476 e.preventDefault();
38477 this.tabPanel.activate(this.id);
38480 onTabMouseDown : function(e){
38481 e.preventDefault();
38482 this.tabPanel.activate(this.id);
38485 getWidth : function(){
38486 return this.inner.getWidth();
38489 setWidth : function(width){
38490 var iwidth = width - this.pnode.getPadding("lr");
38491 this.inner.setWidth(iwidth);
38492 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38493 this.pnode.setWidth(width);
38497 * Show or hide the tab
38498 * @param {Boolean} hidden True to hide or false to show.
38500 setHidden : function(hidden){
38501 this.hidden = hidden;
38502 this.pnode.setStyle("display", hidden ? "none" : "");
38506 * Returns true if this tab is "hidden"
38507 * @return {Boolean}
38509 isHidden : function(){
38510 return this.hidden;
38514 * Returns the text for this tab
38517 getText : function(){
38521 autoSize : function(){
38522 //this.el.beginMeasure();
38523 this.textEl.setWidth(1);
38525 * #2804 [new] Tabs in Roojs
38526 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38528 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38529 //this.el.endMeasure();
38533 * Sets the text for the tab (Note: this also sets the tooltip text)
38534 * @param {String} text The tab's text and tooltip
38536 setText : function(text){
38538 this.textEl.update(text);
38539 this.setTooltip(text);
38540 //if(!this.tabPanel.resizeTabs){
38541 // this.autoSize();
38545 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38547 activate : function(){
38548 this.tabPanel.activate(this.id);
38552 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38554 disable : function(){
38555 if(this.tabPanel.active != this){
38556 this.disabled = true;
38557 this.pnode.addClass("disabled");
38562 * Enables this TabPanelItem if it was previously disabled.
38564 enable : function(){
38565 this.disabled = false;
38566 this.pnode.removeClass("disabled");
38570 * Sets the content for this TabPanelItem.
38571 * @param {String} content The content
38572 * @param {Boolean} loadScripts true to look for and load scripts
38574 setContent : function(content, loadScripts){
38575 this.bodyEl.update(content, loadScripts);
38579 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38580 * @return {Roo.UpdateManager} The UpdateManager
38582 getUpdateManager : function(){
38583 return this.bodyEl.getUpdateManager();
38587 * Set a URL to be used to load the content for this TabPanelItem.
38588 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38589 * @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)
38590 * @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)
38591 * @return {Roo.UpdateManager} The UpdateManager
38593 setUrl : function(url, params, loadOnce){
38594 if(this.refreshDelegate){
38595 this.un('activate', this.refreshDelegate);
38597 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38598 this.on("activate", this.refreshDelegate);
38599 return this.bodyEl.getUpdateManager();
38603 _handleRefresh : function(url, params, loadOnce){
38604 if(!loadOnce || !this.loaded){
38605 var updater = this.bodyEl.getUpdateManager();
38606 updater.update(url, params, this._setLoaded.createDelegate(this));
38611 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38612 * Will fail silently if the setUrl method has not been called.
38613 * This does not activate the panel, just updates its content.
38615 refresh : function(){
38616 if(this.refreshDelegate){
38617 this.loaded = false;
38618 this.refreshDelegate();
38623 _setLoaded : function(){
38624 this.loaded = true;
38628 closeClick : function(e){
38631 this.fireEvent("beforeclose", this, o);
38632 if(o.cancel !== true){
38633 this.tabPanel.removeTab(this.id);
38637 * The text displayed in the tooltip for the close icon.
38640 closeText : "Close this tab"
38643 * This script refer to:
38644 * Title: International Telephone Input
38645 * Author: Jack O'Connor
38646 * Code version: v12.1.12
38647 * Availability: https://github.com/jackocnr/intl-tel-input.git
38650 Roo.bootstrap.PhoneInputData = function() {
38653 "Afghanistan (افغانستان)",
38658 "Albania (Shqipëri)",
38663 "Algeria (الجزائر)",
38688 "Antigua and Barbuda",
38698 "Armenia (Հայաստան)",
38714 "Austria (Österreich)",
38719 "Azerbaijan (Azərbaycan)",
38729 "Bahrain (البحرين)",
38734 "Bangladesh (বাংলাদেশ)",
38744 "Belarus (Беларусь)",
38749 "Belgium (België)",
38779 "Bosnia and Herzegovina (Босна и Херцеговина)",
38794 "British Indian Ocean Territory",
38799 "British Virgin Islands",
38809 "Bulgaria (България)",
38819 "Burundi (Uburundi)",
38824 "Cambodia (កម្ពុជា)",
38829 "Cameroon (Cameroun)",
38838 ["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"]
38841 "Cape Verde (Kabu Verdi)",
38846 "Caribbean Netherlands",
38857 "Central African Republic (République centrafricaine)",
38877 "Christmas Island",
38883 "Cocos (Keeling) Islands",
38894 "Comoros (جزر القمر)",
38899 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38904 "Congo (Republic) (Congo-Brazzaville)",
38924 "Croatia (Hrvatska)",
38945 "Czech Republic (Česká republika)",
38950 "Denmark (Danmark)",
38965 "Dominican Republic (República Dominicana)",
38969 ["809", "829", "849"]
38987 "Equatorial Guinea (Guinea Ecuatorial)",
39007 "Falkland Islands (Islas Malvinas)",
39012 "Faroe Islands (Føroyar)",
39033 "French Guiana (Guyane française)",
39038 "French Polynesia (Polynésie française)",
39053 "Georgia (საქართველო)",
39058 "Germany (Deutschland)",
39078 "Greenland (Kalaallit Nunaat)",
39115 "Guinea-Bissau (Guiné Bissau)",
39140 "Hungary (Magyarország)",
39145 "Iceland (Ísland)",
39165 "Iraq (العراق)",
39181 "Israel (ישראל)",
39208 "Jordan (الأردن)",
39213 "Kazakhstan (Казахстан)",
39234 "Kuwait (الكويت)",
39239 "Kyrgyzstan (Кыргызстан)",
39249 "Latvia (Latvija)",
39254 "Lebanon (لبنان)",
39269 "Libya (ليبيا)",
39279 "Lithuania (Lietuva)",
39294 "Macedonia (FYROM) (Македонија)",
39299 "Madagascar (Madagasikara)",
39329 "Marshall Islands",
39339 "Mauritania (موريتانيا)",
39344 "Mauritius (Moris)",
39365 "Moldova (Republica Moldova)",
39375 "Mongolia (Монгол)",
39380 "Montenegro (Crna Gora)",
39390 "Morocco (المغرب)",
39396 "Mozambique (Moçambique)",
39401 "Myanmar (Burma) (မြန်မာ)",
39406 "Namibia (Namibië)",
39421 "Netherlands (Nederland)",
39426 "New Caledonia (Nouvelle-Calédonie)",
39461 "North Korea (조선 민주주의 인민 공화국)",
39466 "Northern Mariana Islands",
39482 "Pakistan (پاکستان)",
39492 "Palestine (فلسطين)",
39502 "Papua New Guinea",
39544 "Réunion (La Réunion)",
39550 "Romania (România)",
39566 "Saint Barthélemy",
39577 "Saint Kitts and Nevis",
39587 "Saint Martin (Saint-Martin (partie française))",
39593 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39598 "Saint Vincent and the Grenadines",
39613 "São Tomé and Príncipe (São Tomé e Príncipe)",
39618 "Saudi Arabia (المملكة العربية السعودية)",
39623 "Senegal (Sénégal)",
39653 "Slovakia (Slovensko)",
39658 "Slovenia (Slovenija)",
39668 "Somalia (Soomaaliya)",
39678 "South Korea (대한민국)",
39683 "South Sudan (جنوب السودان)",
39693 "Sri Lanka (ශ්රී ලංකාව)",
39698 "Sudan (السودان)",
39708 "Svalbard and Jan Mayen",
39719 "Sweden (Sverige)",
39724 "Switzerland (Schweiz)",
39729 "Syria (سوريا)",
39774 "Trinidad and Tobago",
39779 "Tunisia (تونس)",
39784 "Turkey (Türkiye)",
39794 "Turks and Caicos Islands",
39804 "U.S. Virgin Islands",
39814 "Ukraine (Україна)",
39819 "United Arab Emirates (الإمارات العربية المتحدة)",
39841 "Uzbekistan (Oʻzbekiston)",
39851 "Vatican City (Città del Vaticano)",
39862 "Vietnam (Việt Nam)",
39867 "Wallis and Futuna (Wallis-et-Futuna)",
39872 "Western Sahara (الصحراء الغربية)",
39878 "Yemen (اليمن)",
39902 * This script refer to:
39903 * Title: International Telephone Input
39904 * Author: Jack O'Connor
39905 * Code version: v12.1.12
39906 * Availability: https://github.com/jackocnr/intl-tel-input.git
39910 * @class Roo.bootstrap.PhoneInput
39911 * @extends Roo.bootstrap.TriggerField
39912 * An input with International dial-code selection
39914 * @cfg {String} defaultDialCode default '+852'
39915 * @cfg {Array} preferedCountries default []
39918 * Create a new PhoneInput.
39919 * @param {Object} config Configuration options
39922 Roo.bootstrap.PhoneInput = function(config) {
39923 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39926 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39928 listWidth: undefined,
39930 selectedClass: 'active',
39932 invalidClass : "has-warning",
39934 validClass: 'has-success',
39936 allowed: '0123456789',
39941 * @cfg {String} defaultDialCode The default dial code when initializing the input
39943 defaultDialCode: '+852',
39946 * @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
39948 preferedCountries: false,
39950 getAutoCreate : function()
39952 var data = Roo.bootstrap.PhoneInputData();
39953 var align = this.labelAlign || this.parentLabelAlign();
39956 this.allCountries = [];
39957 this.dialCodeMapping = [];
39959 for (var i = 0; i < data.length; i++) {
39961 this.allCountries[i] = {
39965 priority: c[3] || 0,
39966 areaCodes: c[4] || null
39968 this.dialCodeMapping[c[2]] = {
39971 priority: c[3] || 0,
39972 areaCodes: c[4] || null
39984 // type: 'number', -- do not use number - we get the flaky up/down arrows.
39985 maxlength: this.max_length,
39986 cls : 'form-control tel-input',
39987 autocomplete: 'new-password'
39990 var hiddenInput = {
39993 cls: 'hidden-tel-input'
39997 hiddenInput.name = this.name;
40000 if (this.disabled) {
40001 input.disabled = true;
40004 var flag_container = {
40021 cls: this.hasFeedback ? 'has-feedback' : '',
40027 cls: 'dial-code-holder',
40034 cls: 'roo-select2-container input-group',
40041 if (this.fieldLabel.length) {
40044 tooltip: 'This field is required'
40050 cls: 'control-label',
40056 html: this.fieldLabel
40059 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40065 if(this.indicatorpos == 'right') {
40066 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40073 if(align == 'left') {
40081 if(this.labelWidth > 12){
40082 label.style = "width: " + this.labelWidth + 'px';
40084 if(this.labelWidth < 13 && this.labelmd == 0){
40085 this.labelmd = this.labelWidth;
40087 if(this.labellg > 0){
40088 label.cls += ' col-lg-' + this.labellg;
40089 input.cls += ' col-lg-' + (12 - this.labellg);
40091 if(this.labelmd > 0){
40092 label.cls += ' col-md-' + this.labelmd;
40093 container.cls += ' col-md-' + (12 - this.labelmd);
40095 if(this.labelsm > 0){
40096 label.cls += ' col-sm-' + this.labelsm;
40097 container.cls += ' col-sm-' + (12 - this.labelsm);
40099 if(this.labelxs > 0){
40100 label.cls += ' col-xs-' + this.labelxs;
40101 container.cls += ' col-xs-' + (12 - this.labelxs);
40111 var settings = this;
40113 ['xs','sm','md','lg'].map(function(size){
40114 if (settings[size]) {
40115 cfg.cls += ' col-' + size + '-' + settings[size];
40119 this.store = new Roo.data.Store({
40120 proxy : new Roo.data.MemoryProxy({}),
40121 reader : new Roo.data.JsonReader({
40132 'name' : 'dialCode',
40136 'name' : 'priority',
40140 'name' : 'areaCodes',
40147 if(!this.preferedCountries) {
40148 this.preferedCountries = [
40155 var p = this.preferedCountries.reverse();
40158 for (var i = 0; i < p.length; i++) {
40159 for (var j = 0; j < this.allCountries.length; j++) {
40160 if(this.allCountries[j].iso2 == p[i]) {
40161 var t = this.allCountries[j];
40162 this.allCountries.splice(j,1);
40163 this.allCountries.unshift(t);
40169 this.store.proxy.data = {
40171 data: this.allCountries
40177 initEvents : function()
40180 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40182 this.indicator = this.indicatorEl();
40183 this.flag = this.flagEl();
40184 this.dialCodeHolder = this.dialCodeHolderEl();
40186 this.trigger = this.el.select('div.flag-box',true).first();
40187 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40192 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40193 _this.list.setWidth(lw);
40196 this.list.on('mouseover', this.onViewOver, this);
40197 this.list.on('mousemove', this.onViewMove, this);
40198 this.inputEl().on("keyup", this.onKeyUp, this);
40199 this.inputEl().on("keypress", this.onKeyPress, this);
40201 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40203 this.view = new Roo.View(this.list, this.tpl, {
40204 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40207 this.view.on('click', this.onViewClick, this);
40208 this.setValue(this.defaultDialCode);
40211 onTriggerClick : function(e)
40213 Roo.log('trigger click');
40218 if(this.isExpanded()){
40220 this.hasFocus = false;
40222 this.store.load({});
40223 this.hasFocus = true;
40228 isExpanded : function()
40230 return this.list.isVisible();
40233 collapse : function()
40235 if(!this.isExpanded()){
40239 Roo.get(document).un('mousedown', this.collapseIf, this);
40240 Roo.get(document).un('mousewheel', this.collapseIf, this);
40241 this.fireEvent('collapse', this);
40245 expand : function()
40249 if(this.isExpanded() || !this.hasFocus){
40253 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40254 this.list.setWidth(lw);
40257 this.restrictHeight();
40259 Roo.get(document).on('mousedown', this.collapseIf, this);
40260 Roo.get(document).on('mousewheel', this.collapseIf, this);
40262 this.fireEvent('expand', this);
40265 restrictHeight : function()
40267 this.list.alignTo(this.inputEl(), this.listAlign);
40268 this.list.alignTo(this.inputEl(), this.listAlign);
40271 onViewOver : function(e, t)
40273 if(this.inKeyMode){
40276 var item = this.view.findItemFromChild(t);
40279 var index = this.view.indexOf(item);
40280 this.select(index, false);
40285 onViewClick : function(view, doFocus, el, e)
40287 var index = this.view.getSelectedIndexes()[0];
40289 var r = this.store.getAt(index);
40292 this.onSelect(r, index);
40294 if(doFocus !== false && !this.blockFocus){
40295 this.inputEl().focus();
40299 onViewMove : function(e, t)
40301 this.inKeyMode = false;
40304 select : function(index, scrollIntoView)
40306 this.selectedIndex = index;
40307 this.view.select(index);
40308 if(scrollIntoView !== false){
40309 var el = this.view.getNode(index);
40311 this.list.scrollChildIntoView(el, false);
40316 createList : function()
40318 this.list = Roo.get(document.body).createChild({
40320 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40321 style: 'display:none'
40324 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40327 collapseIf : function(e)
40329 var in_combo = e.within(this.el);
40330 var in_list = e.within(this.list);
40331 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40333 if (in_combo || in_list || is_list) {
40339 onSelect : function(record, index)
40341 if(this.fireEvent('beforeselect', this, record, index) !== false){
40343 this.setFlagClass(record.data.iso2);
40344 this.setDialCode(record.data.dialCode);
40345 this.hasFocus = false;
40347 this.fireEvent('select', this, record, index);
40351 flagEl : function()
40353 var flag = this.el.select('div.flag',true).first();
40360 dialCodeHolderEl : function()
40362 var d = this.el.select('input.dial-code-holder',true).first();
40369 setDialCode : function(v)
40371 this.dialCodeHolder.dom.value = '+'+v;
40374 setFlagClass : function(n)
40376 this.flag.dom.className = 'flag '+n;
40379 getValue : function()
40381 var v = this.inputEl().getValue();
40382 if(this.dialCodeHolder) {
40383 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40388 setValue : function(v)
40390 var d = this.getDialCode(v);
40392 //invalid dial code
40393 if(v.length == 0 || !d || d.length == 0) {
40395 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40396 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40402 this.setFlagClass(this.dialCodeMapping[d].iso2);
40403 this.setDialCode(d);
40404 this.inputEl().dom.value = v.replace('+'+d,'');
40405 this.hiddenEl().dom.value = this.getValue();
40410 getDialCode : function(v)
40414 if (v.length == 0) {
40415 return this.dialCodeHolder.dom.value;
40419 if (v.charAt(0) != "+") {
40422 var numericChars = "";
40423 for (var i = 1; i < v.length; i++) {
40424 var c = v.charAt(i);
40427 if (this.dialCodeMapping[numericChars]) {
40428 dialCode = v.substr(1, i);
40430 if (numericChars.length == 4) {
40440 this.setValue(this.defaultDialCode);
40444 hiddenEl : function()
40446 return this.el.select('input.hidden-tel-input',true).first();
40449 // after setting val
40450 onKeyUp : function(e){
40451 this.setValue(this.getValue());
40454 onKeyPress : function(e){
40455 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40462 * @class Roo.bootstrap.MoneyField
40463 * @extends Roo.bootstrap.ComboBox
40464 * Bootstrap MoneyField class
40467 * Create a new MoneyField.
40468 * @param {Object} config Configuration options
40471 Roo.bootstrap.MoneyField = function(config) {
40473 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40477 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40480 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40482 allowDecimals : true,
40484 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40486 decimalSeparator : ".",
40488 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40490 decimalPrecision : 0,
40492 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40494 allowNegative : true,
40496 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40500 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40502 minValue : Number.NEGATIVE_INFINITY,
40504 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40506 maxValue : Number.MAX_VALUE,
40508 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40510 minText : "The minimum value for this field is {0}",
40512 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40514 maxText : "The maximum value for this field is {0}",
40516 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40517 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40519 nanText : "{0} is not a valid number",
40521 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40525 * @cfg {String} defaults currency of the MoneyField
40526 * value should be in lkey
40528 defaultCurrency : false,
40530 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40532 thousandsDelimiter : false,
40534 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40545 getAutoCreate : function()
40547 var align = this.labelAlign || this.parentLabelAlign();
40559 cls : 'form-control roo-money-amount-input',
40560 autocomplete: 'new-password'
40563 var hiddenInput = {
40567 cls: 'hidden-number-input'
40570 if(this.max_length) {
40571 input.maxlength = this.max_length;
40575 hiddenInput.name = this.name;
40578 if (this.disabled) {
40579 input.disabled = true;
40582 var clg = 12 - this.inputlg;
40583 var cmd = 12 - this.inputmd;
40584 var csm = 12 - this.inputsm;
40585 var cxs = 12 - this.inputxs;
40589 cls : 'row roo-money-field',
40593 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40597 cls: 'roo-select2-container input-group',
40601 cls : 'form-control roo-money-currency-input',
40602 autocomplete: 'new-password',
40604 name : this.currencyName
40608 cls : 'input-group-addon',
40622 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40626 cls: this.hasFeedback ? 'has-feedback' : '',
40637 if (this.fieldLabel.length) {
40640 tooltip: 'This field is required'
40646 cls: 'control-label',
40652 html: this.fieldLabel
40655 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40661 if(this.indicatorpos == 'right') {
40662 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40669 if(align == 'left') {
40677 if(this.labelWidth > 12){
40678 label.style = "width: " + this.labelWidth + 'px';
40680 if(this.labelWidth < 13 && this.labelmd == 0){
40681 this.labelmd = this.labelWidth;
40683 if(this.labellg > 0){
40684 label.cls += ' col-lg-' + this.labellg;
40685 input.cls += ' col-lg-' + (12 - this.labellg);
40687 if(this.labelmd > 0){
40688 label.cls += ' col-md-' + this.labelmd;
40689 container.cls += ' col-md-' + (12 - this.labelmd);
40691 if(this.labelsm > 0){
40692 label.cls += ' col-sm-' + this.labelsm;
40693 container.cls += ' col-sm-' + (12 - this.labelsm);
40695 if(this.labelxs > 0){
40696 label.cls += ' col-xs-' + this.labelxs;
40697 container.cls += ' col-xs-' + (12 - this.labelxs);
40708 var settings = this;
40710 ['xs','sm','md','lg'].map(function(size){
40711 if (settings[size]) {
40712 cfg.cls += ' col-' + size + '-' + settings[size];
40719 initEvents : function()
40721 this.indicator = this.indicatorEl();
40723 this.initCurrencyEvent();
40725 this.initNumberEvent();
40728 initCurrencyEvent : function()
40731 throw "can not find store for combo";
40734 this.store = Roo.factory(this.store, Roo.data);
40735 this.store.parent = this;
40739 this.triggerEl = this.el.select('.input-group-addon', true).first();
40741 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40746 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40747 _this.list.setWidth(lw);
40750 this.list.on('mouseover', this.onViewOver, this);
40751 this.list.on('mousemove', this.onViewMove, this);
40752 this.list.on('scroll', this.onViewScroll, this);
40755 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40758 this.view = new Roo.View(this.list, this.tpl, {
40759 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40762 this.view.on('click', this.onViewClick, this);
40764 this.store.on('beforeload', this.onBeforeLoad, this);
40765 this.store.on('load', this.onLoad, this);
40766 this.store.on('loadexception', this.onLoadException, this);
40768 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40769 "up" : function(e){
40770 this.inKeyMode = true;
40774 "down" : function(e){
40775 if(!this.isExpanded()){
40776 this.onTriggerClick();
40778 this.inKeyMode = true;
40783 "enter" : function(e){
40786 if(this.fireEvent("specialkey", this, e)){
40787 this.onViewClick(false);
40793 "esc" : function(e){
40797 "tab" : function(e){
40800 if(this.fireEvent("specialkey", this, e)){
40801 this.onViewClick(false);
40809 doRelay : function(foo, bar, hname){
40810 if(hname == 'down' || this.scope.isExpanded()){
40811 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40819 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40823 initNumberEvent : function(e)
40825 this.inputEl().on("keydown" , this.fireKey, this);
40826 this.inputEl().on("focus", this.onFocus, this);
40827 this.inputEl().on("blur", this.onBlur, this);
40829 this.inputEl().relayEvent('keyup', this);
40831 if(this.indicator){
40832 this.indicator.addClass('invisible');
40835 this.originalValue = this.getValue();
40837 if(this.validationEvent == 'keyup'){
40838 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40839 this.inputEl().on('keyup', this.filterValidation, this);
40841 else if(this.validationEvent !== false){
40842 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40845 if(this.selectOnFocus){
40846 this.on("focus", this.preFocus, this);
40849 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40850 this.inputEl().on("keypress", this.filterKeys, this);
40852 this.inputEl().relayEvent('keypress', this);
40855 var allowed = "0123456789";
40857 if(this.allowDecimals){
40858 allowed += this.decimalSeparator;
40861 if(this.allowNegative){
40865 if(this.thousandsDelimiter) {
40869 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40871 var keyPress = function(e){
40873 var k = e.getKey();
40875 var c = e.getCharCode();
40878 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40879 allowed.indexOf(String.fromCharCode(c)) === -1
40885 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40889 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40894 this.inputEl().on("keypress", keyPress, this);
40898 onTriggerClick : function(e)
40905 this.loadNext = false;
40907 if(this.isExpanded()){
40912 this.hasFocus = true;
40914 if(this.triggerAction == 'all') {
40915 this.doQuery(this.allQuery, true);
40919 this.doQuery(this.getRawValue());
40922 getCurrency : function()
40924 var v = this.currencyEl().getValue();
40929 restrictHeight : function()
40931 this.list.alignTo(this.currencyEl(), this.listAlign);
40932 this.list.alignTo(this.currencyEl(), this.listAlign);
40935 onViewClick : function(view, doFocus, el, e)
40937 var index = this.view.getSelectedIndexes()[0];
40939 var r = this.store.getAt(index);
40942 this.onSelect(r, index);
40946 onSelect : function(record, index){
40948 if(this.fireEvent('beforeselect', this, record, index) !== false){
40950 this.setFromCurrencyData(index > -1 ? record.data : false);
40954 this.fireEvent('select', this, record, index);
40958 setFromCurrencyData : function(o)
40962 this.lastCurrency = o;
40964 if (this.currencyField) {
40965 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40967 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40970 this.lastSelectionText = currency;
40972 //setting default currency
40973 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40974 this.setCurrency(this.defaultCurrency);
40978 this.setCurrency(currency);
40981 setFromData : function(o)
40985 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40987 this.setFromCurrencyData(c);
40992 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40994 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40997 this.setValue(value);
41001 setCurrency : function(v)
41003 this.currencyValue = v;
41006 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41011 setValue : function(v)
41013 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41019 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41021 this.inputEl().dom.value = (v == '') ? '' :
41022 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41024 if(!this.allowZero && v === '0') {
41025 this.hiddenEl().dom.value = '';
41026 this.inputEl().dom.value = '';
41033 getRawValue : function()
41035 var v = this.inputEl().getValue();
41040 getValue : function()
41042 return this.fixPrecision(this.parseValue(this.getRawValue()));
41045 parseValue : function(value)
41047 if(this.thousandsDelimiter) {
41049 r = new RegExp(",", "g");
41050 value = value.replace(r, "");
41053 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41054 return isNaN(value) ? '' : value;
41058 fixPrecision : function(value)
41060 if(this.thousandsDelimiter) {
41062 r = new RegExp(",", "g");
41063 value = value.replace(r, "");
41066 var nan = isNaN(value);
41068 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41069 return nan ? '' : value;
41071 return parseFloat(value).toFixed(this.decimalPrecision);
41074 decimalPrecisionFcn : function(v)
41076 return Math.floor(v);
41079 validateValue : function(value)
41081 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41085 var num = this.parseValue(value);
41088 this.markInvalid(String.format(this.nanText, value));
41092 if(num < this.minValue){
41093 this.markInvalid(String.format(this.minText, this.minValue));
41097 if(num > this.maxValue){
41098 this.markInvalid(String.format(this.maxText, this.maxValue));
41105 validate : function()
41107 if(this.disabled || this.allowBlank){
41112 var currency = this.getCurrency();
41114 if(this.validateValue(this.getRawValue()) && currency.length){
41119 this.markInvalid();
41123 getName: function()
41128 beforeBlur : function()
41134 var v = this.parseValue(this.getRawValue());
41141 onBlur : function()
41145 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41146 //this.el.removeClass(this.focusClass);
41149 this.hasFocus = false;
41151 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41155 var v = this.getValue();
41157 if(String(v) !== String(this.startValue)){
41158 this.fireEvent('change', this, v, this.startValue);
41161 this.fireEvent("blur", this);
41164 inputEl : function()
41166 return this.el.select('.roo-money-amount-input', true).first();
41169 currencyEl : function()
41171 return this.el.select('.roo-money-currency-input', true).first();
41174 hiddenEl : function()
41176 return this.el.select('input.hidden-number-input',true).first();