2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass('hidden');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
585 * @cfg {String} size ( lg | sm | xs)
586 * @cfg {String} tag ( a | input | submit)
587 * @cfg {String} href empty or href
588 * @cfg {Boolean} disabled default false;
589 * @cfg {Boolean} isClose default false;
590 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
591 * @cfg {String} badge text for badge
592 * @cfg {String} theme (default|glow)
593 * @cfg {Boolean} inverse dark themed version
594 * @cfg {Boolean} toggle is it a slidy toggle button
595 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
596 * @cfg {String} ontext text for on slidy toggle state
597 * @cfg {String} offtext text for off slidy toggle state
598 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
599 * @cfg {Boolean} removeClass remove the standard class..
600 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
603 * Create a new button
604 * @param {Object} config The config object
608 Roo.bootstrap.Button = function(config){
609 Roo.bootstrap.Button.superclass.constructor.call(this, config);
610 this.weightClass = ["btn-default",
622 * When a butotn is pressed
623 * @param {Roo.bootstrap.Button} btn
624 * @param {Roo.EventObject} e
629 * After the button has been toggles
630 * @param {Roo.bootstrap.Button} btn
631 * @param {Roo.EventObject} e
632 * @param {boolean} pressed (also available as button.pressed)
638 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
656 preventDefault: true,
664 getAutoCreate : function(){
672 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
673 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
678 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
680 if (this.toggle == true) {
683 cls: 'slider-frame roo-button',
688 'data-off-text':'OFF',
689 cls: 'slider-button',
695 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
696 cfg.cls += ' '+this.weight;
705 cfg["aria-hidden"] = true;
707 cfg.html = "×";
713 if (this.theme==='default') {
714 cfg.cls = 'btn roo-button';
716 //if (this.parentType != 'Navbar') {
717 this.weight = this.weight.length ? this.weight : 'default';
719 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
721 cfg.cls += ' btn-' + this.weight;
723 } else if (this.theme==='glow') {
726 cfg.cls = 'btn-glow roo-button';
728 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
730 cfg.cls += ' ' + this.weight;
736 this.cls += ' inverse';
740 if (this.active || this.pressed === true) {
741 cfg.cls += ' active';
745 cfg.disabled = 'disabled';
749 Roo.log('changing to ul' );
751 this.glyphicon = 'caret';
754 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
756 //gsRoo.log(this.parentType);
757 if (this.parentType === 'Navbar' && !this.parent().bar) {
758 Roo.log('changing to li?');
767 href : this.href || '#'
770 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
771 cfg.cls += ' dropdown';
778 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
780 if (this.glyphicon) {
781 cfg.html = ' ' + cfg.html;
786 cls: 'glyphicon glyphicon-' + this.glyphicon
796 // cfg.cls='btn roo-button';
800 var value = cfg.html;
805 cls: 'glyphicon glyphicon-' + this.glyphicon,
824 cfg.cls += ' dropdown';
825 cfg.html = typeof(cfg.html) != 'undefined' ?
826 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
829 if (cfg.tag !== 'a' && this.href !== '') {
830 throw "Tag must be a to set href.";
831 } else if (this.href.length > 0) {
832 cfg.href = this.href;
835 if(this.removeClass){
840 cfg.target = this.target;
845 initEvents: function() {
846 // Roo.log('init events?');
847 // Roo.log(this.el.dom);
850 if (typeof (this.menu) != 'undefined') {
851 this.menu.parentType = this.xtype;
852 this.menu.triggerEl = this.el;
853 this.addxtype(Roo.apply({}, this.menu));
857 if (this.el.hasClass('roo-button')) {
858 this.el.on('click', this.onClick, this);
860 this.el.select('.roo-button').on('click', this.onClick, this);
863 if(this.removeClass){
864 this.el.on('click', this.onClick, this);
867 this.el.enableDisplayMode();
870 onClick : function(e)
876 Roo.log('button on click ');
877 if(this.preventDefault){
881 if (this.pressed === true || this.pressed === false) {
882 this.toggleActive(e);
886 this.fireEvent('click', this, e);
890 * Enables this button
894 this.disabled = false;
895 this.el.removeClass('disabled');
899 * Disable this button
903 this.disabled = true;
904 this.el.addClass('disabled');
907 * sets the active state on/off,
908 * @param {Boolean} state (optional) Force a particular state
910 setActive : function(v) {
912 this.el[v ? 'addClass' : 'removeClass']('active');
916 * toggles the current active state
918 toggleActive : function(e)
920 this.setActive(!this.pressed);
921 this.fireEvent('toggle', this, e, !this.pressed);
924 * get the current active state
925 * @return {boolean} true if it's active
927 isActive : function()
929 return this.el.hasClass('active');
932 * set the text of the first selected button
934 setText : function(str)
936 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
939 * get the text of the first selected button
943 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
946 setWeight : function(str)
948 this.el.removeClass(this.weightClass);
949 this.el.addClass('btn-' + str);
963 * @class Roo.bootstrap.Column
964 * @extends Roo.bootstrap.Component
965 * Bootstrap Column class
966 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
967 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
968 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
969 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
970 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
971 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
972 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
973 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
976 * @cfg {Boolean} hidden (true|false) hide the element
977 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
978 * @cfg {String} fa (ban|check|...) font awesome icon
979 * @cfg {Number} fasize (1|2|....) font awsome size
981 * @cfg {String} icon (info-sign|check|...) glyphicon name
983 * @cfg {String} html content of column.
986 * Create a new Column
987 * @param {Object} config The config object
990 Roo.bootstrap.Column = function(config){
991 Roo.bootstrap.Column.superclass.constructor.call(this, config);
994 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1012 getAutoCreate : function(){
1013 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1021 ['xs','sm','md','lg'].map(function(size){
1022 //Roo.log( size + ':' + settings[size]);
1024 if (settings[size+'off'] !== false) {
1025 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1028 if (settings[size] === false) {
1032 if (!settings[size]) { // 0 = hidden
1033 cfg.cls += ' hidden-' + size;
1036 cfg.cls += ' col-' + size + '-' + settings[size];
1041 cfg.cls += ' hidden';
1044 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1045 cfg.cls +=' alert alert-' + this.alert;
1049 if (this.html.length) {
1050 cfg.html = this.html;
1054 if (this.fasize > 1) {
1055 fasize = ' fa-' + this.fasize + 'x';
1057 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1062 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1081 * @class Roo.bootstrap.Container
1082 * @extends Roo.bootstrap.Component
1083 * Bootstrap Container class
1084 * @cfg {Boolean} jumbotron is it a jumbotron element
1085 * @cfg {String} html content of element
1086 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1087 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1088 * @cfg {String} header content of header (for panel)
1089 * @cfg {String} footer content of footer (for panel)
1090 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1091 * @cfg {String} tag (header|aside|section) type of HTML tag.
1092 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1093 * @cfg {String} fa font awesome icon
1094 * @cfg {String} icon (info-sign|check|...) glyphicon name
1095 * @cfg {Boolean} hidden (true|false) hide the element
1096 * @cfg {Boolean} expandable (true|false) default false
1097 * @cfg {Boolean} expanded (true|false) default true
1098 * @cfg {String} rheader contet on the right of header
1099 * @cfg {Boolean} clickable (true|false) default false
1103 * Create a new Container
1104 * @param {Object} config The config object
1107 Roo.bootstrap.Container = function(config){
1108 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1114 * After the panel has been expand
1116 * @param {Roo.bootstrap.Container} this
1121 * After the panel has been collapsed
1123 * @param {Roo.bootstrap.Container} this
1128 * When a element is chick
1129 * @param {Roo.bootstrap.Container} this
1130 * @param {Roo.EventObject} e
1136 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1154 getChildContainer : function() {
1160 if (this.panel.length) {
1161 return this.el.select('.panel-body',true).first();
1168 getAutoCreate : function(){
1171 tag : this.tag || 'div',
1175 if (this.jumbotron) {
1176 cfg.cls = 'jumbotron';
1181 // - this is applied by the parent..
1183 // cfg.cls = this.cls + '';
1186 if (this.sticky.length) {
1188 var bd = Roo.get(document.body);
1189 if (!bd.hasClass('bootstrap-sticky')) {
1190 bd.addClass('bootstrap-sticky');
1191 Roo.select('html',true).setStyle('height', '100%');
1194 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1198 if (this.well.length) {
1199 switch (this.well) {
1202 cfg.cls +=' well well-' +this.well;
1211 cfg.cls += ' hidden';
1215 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1216 cfg.cls +=' alert alert-' + this.alert;
1221 if (this.panel.length) {
1222 cfg.cls += ' panel panel-' + this.panel;
1224 if (this.header.length) {
1228 if(this.expandable){
1230 cfg.cls = cfg.cls + ' expandable';
1234 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1242 cls : 'panel-title',
1243 html : (this.expandable ? ' ' : '') + this.header
1247 cls: 'panel-header-right',
1253 cls : 'panel-heading',
1254 style : this.expandable ? 'cursor: pointer' : '',
1262 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1267 if (this.footer.length) {
1269 cls : 'panel-footer',
1278 body.html = this.html || cfg.html;
1279 // prefix with the icons..
1281 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1284 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1289 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1290 cfg.cls = 'container';
1296 initEvents: function()
1298 if(this.expandable){
1299 var headerEl = this.headerEl();
1302 headerEl.on('click', this.onToggleClick, this);
1307 this.el.on('click', this.onClick, this);
1312 onToggleClick : function()
1314 var headerEl = this.headerEl();
1330 if(this.fireEvent('expand', this)) {
1332 this.expanded = true;
1334 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1336 this.el.select('.panel-body',true).first().removeClass('hide');
1338 var toggleEl = this.toggleEl();
1344 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1349 collapse : function()
1351 if(this.fireEvent('collapse', this)) {
1353 this.expanded = false;
1355 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1356 this.el.select('.panel-body',true).first().addClass('hide');
1358 var toggleEl = this.toggleEl();
1364 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1368 toggleEl : function()
1370 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1374 return this.el.select('.panel-heading .fa',true).first();
1377 headerEl : function()
1379 if(!this.el || !this.panel.length || !this.header.length){
1383 return this.el.select('.panel-heading',true).first()
1388 if(!this.el || !this.panel.length){
1392 return this.el.select('.panel-body',true).first()
1395 titleEl : function()
1397 if(!this.el || !this.panel.length || !this.header.length){
1401 return this.el.select('.panel-title',true).first();
1404 setTitle : function(v)
1406 var titleEl = this.titleEl();
1412 titleEl.dom.innerHTML = v;
1415 getTitle : function()
1418 var titleEl = this.titleEl();
1424 return titleEl.dom.innerHTML;
1427 setRightTitle : function(v)
1429 var t = this.el.select('.panel-header-right',true).first();
1435 t.dom.innerHTML = v;
1438 onClick : function(e)
1442 this.fireEvent('click', this, e);
1455 * @class Roo.bootstrap.Img
1456 * @extends Roo.bootstrap.Component
1457 * Bootstrap Img class
1458 * @cfg {Boolean} imgResponsive false | true
1459 * @cfg {String} border rounded | circle | thumbnail
1460 * @cfg {String} src image source
1461 * @cfg {String} alt image alternative text
1462 * @cfg {String} href a tag href
1463 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1464 * @cfg {String} xsUrl xs image source
1465 * @cfg {String} smUrl sm image source
1466 * @cfg {String} mdUrl md image source
1467 * @cfg {String} lgUrl lg image source
1470 * Create a new Input
1471 * @param {Object} config The config object
1474 Roo.bootstrap.Img = function(config){
1475 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1481 * The img click event for the img.
1482 * @param {Roo.EventObject} e
1488 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1490 imgResponsive: true,
1500 getAutoCreate : function()
1502 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1503 return this.createSingleImg();
1508 cls: 'roo-image-responsive-group',
1513 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1515 if(!_this[size + 'Url']){
1521 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1522 html: _this.html || cfg.html,
1523 src: _this[size + 'Url']
1526 img.cls += ' roo-image-responsive-' + size;
1528 var s = ['xs', 'sm', 'md', 'lg'];
1530 s.splice(s.indexOf(size), 1);
1532 Roo.each(s, function(ss){
1533 img.cls += ' hidden-' + ss;
1536 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1537 cfg.cls += ' img-' + _this.border;
1541 cfg.alt = _this.alt;
1554 a.target = _this.target;
1558 cfg.cn.push((_this.href) ? a : img);
1565 createSingleImg : function()
1569 cls: (this.imgResponsive) ? 'img-responsive' : '',
1571 src : 'about:blank' // just incase src get's set to undefined?!?
1574 cfg.html = this.html || cfg.html;
1576 cfg.src = this.src || cfg.src;
1578 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1579 cfg.cls += ' img-' + this.border;
1596 a.target = this.target;
1601 return (this.href) ? a : cfg;
1604 initEvents: function()
1607 this.el.on('click', this.onClick, this);
1612 onClick : function(e)
1614 Roo.log('img onclick');
1615 this.fireEvent('click', this, e);
1618 * Sets the url of the image - used to update it
1619 * @param {String} url the url of the image
1622 setSrc : function(url)
1626 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1627 this.el.dom.src = url;
1631 this.el.select('img', true).first().dom.src = url;
1647 * @class Roo.bootstrap.Link
1648 * @extends Roo.bootstrap.Component
1649 * Bootstrap Link Class
1650 * @cfg {String} alt image alternative text
1651 * @cfg {String} href a tag href
1652 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1653 * @cfg {String} html the content of the link.
1654 * @cfg {String} anchor name for the anchor link
1655 * @cfg {String} fa - favicon
1657 * @cfg {Boolean} preventDefault (true | false) default false
1661 * Create a new Input
1662 * @param {Object} config The config object
1665 Roo.bootstrap.Link = function(config){
1666 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1672 * The img click event for the img.
1673 * @param {Roo.EventObject} e
1679 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1683 preventDefault: false,
1689 getAutoCreate : function()
1691 var html = this.html || '';
1693 if (this.fa !== false) {
1694 html = '<i class="fa fa-' + this.fa + '"></i>';
1699 // anchor's do not require html/href...
1700 if (this.anchor === false) {
1702 cfg.href = this.href || '#';
1704 cfg.name = this.anchor;
1705 if (this.html !== false || this.fa !== false) {
1708 if (this.href !== false) {
1709 cfg.href = this.href;
1713 if(this.alt !== false){
1718 if(this.target !== false) {
1719 cfg.target = this.target;
1725 initEvents: function() {
1727 if(!this.href || this.preventDefault){
1728 this.el.on('click', this.onClick, this);
1732 onClick : function(e)
1734 if(this.preventDefault){
1737 //Roo.log('img onclick');
1738 this.fireEvent('click', this, e);
1751 * @class Roo.bootstrap.Header
1752 * @extends Roo.bootstrap.Component
1753 * Bootstrap Header class
1754 * @cfg {String} html content of header
1755 * @cfg {Number} level (1|2|3|4|5|6) default 1
1758 * Create a new Header
1759 * @param {Object} config The config object
1763 Roo.bootstrap.Header = function(config){
1764 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1767 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1775 getAutoCreate : function(){
1780 tag: 'h' + (1 *this.level),
1781 html: this.html || ''
1793 * Ext JS Library 1.1.1
1794 * Copyright(c) 2006-2007, Ext JS, LLC.
1796 * Originally Released Under LGPL - original licence link has changed is not relivant.
1799 * <script type="text/javascript">
1803 * @class Roo.bootstrap.MenuMgr
1804 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1807 Roo.bootstrap.MenuMgr = function(){
1808 var menus, active, groups = {}, attached = false, lastShow = new Date();
1810 // private - called when first menu is created
1813 active = new Roo.util.MixedCollection();
1814 Roo.get(document).addKeyListener(27, function(){
1815 if(active.length > 0){
1823 if(active && active.length > 0){
1824 var c = active.clone();
1834 if(active.length < 1){
1835 Roo.get(document).un("mouseup", onMouseDown);
1843 var last = active.last();
1844 lastShow = new Date();
1847 Roo.get(document).on("mouseup", onMouseDown);
1852 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1853 m.parentMenu.activeChild = m;
1854 }else if(last && last.isVisible()){
1855 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1860 function onBeforeHide(m){
1862 m.activeChild.hide();
1864 if(m.autoHideTimer){
1865 clearTimeout(m.autoHideTimer);
1866 delete m.autoHideTimer;
1871 function onBeforeShow(m){
1872 var pm = m.parentMenu;
1873 if(!pm && !m.allowOtherMenus){
1875 }else if(pm && pm.activeChild && active != m){
1876 pm.activeChild.hide();
1880 // private this should really trigger on mouseup..
1881 function onMouseDown(e){
1882 Roo.log("on Mouse Up");
1884 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1885 Roo.log("MenuManager hideAll");
1894 function onBeforeCheck(mi, state){
1896 var g = groups[mi.group];
1897 for(var i = 0, l = g.length; i < l; i++){
1899 g[i].setChecked(false);
1908 * Hides all menus that are currently visible
1910 hideAll : function(){
1915 register : function(menu){
1919 menus[menu.id] = menu;
1920 menu.on("beforehide", onBeforeHide);
1921 menu.on("hide", onHide);
1922 menu.on("beforeshow", onBeforeShow);
1923 menu.on("show", onShow);
1925 if(g && menu.events["checkchange"]){
1929 groups[g].push(menu);
1930 menu.on("checkchange", onCheck);
1935 * Returns a {@link Roo.menu.Menu} object
1936 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1937 * be used to generate and return a new Menu instance.
1939 get : function(menu){
1940 if(typeof menu == "string"){ // menu id
1942 }else if(menu.events){ // menu instance
1945 /*else if(typeof menu.length == 'number'){ // array of menu items?
1946 return new Roo.bootstrap.Menu({items:menu});
1947 }else{ // otherwise, must be a config
1948 return new Roo.bootstrap.Menu(menu);
1955 unregister : function(menu){
1956 delete menus[menu.id];
1957 menu.un("beforehide", onBeforeHide);
1958 menu.un("hide", onHide);
1959 menu.un("beforeshow", onBeforeShow);
1960 menu.un("show", onShow);
1962 if(g && menu.events["checkchange"]){
1963 groups[g].remove(menu);
1964 menu.un("checkchange", onCheck);
1969 registerCheckable : function(menuItem){
1970 var g = menuItem.group;
1975 groups[g].push(menuItem);
1976 menuItem.on("beforecheckchange", onBeforeCheck);
1981 unregisterCheckable : function(menuItem){
1982 var g = menuItem.group;
1984 groups[g].remove(menuItem);
1985 menuItem.un("beforecheckchange", onBeforeCheck);
1997 * @class Roo.bootstrap.Menu
1998 * @extends Roo.bootstrap.Component
1999 * Bootstrap Menu class - container for MenuItems
2000 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2001 * @cfg {bool} hidden if the menu should be hidden when rendered.
2002 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2003 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2007 * @param {Object} config The config object
2011 Roo.bootstrap.Menu = function(config){
2012 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2013 if (this.registerMenu && this.type != 'treeview') {
2014 Roo.bootstrap.MenuMgr.register(this);
2021 * Fires before this menu is displayed
2022 * @param {Roo.menu.Menu} this
2027 * Fires before this menu is hidden
2028 * @param {Roo.menu.Menu} this
2033 * Fires after this menu is displayed
2034 * @param {Roo.menu.Menu} this
2039 * Fires after this menu is hidden
2040 * @param {Roo.menu.Menu} this
2045 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2046 * @param {Roo.menu.Menu} this
2047 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2048 * @param {Roo.EventObject} e
2053 * Fires when the mouse is hovering over this menu
2054 * @param {Roo.menu.Menu} this
2055 * @param {Roo.EventObject} e
2056 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2061 * Fires when the mouse exits this menu
2062 * @param {Roo.menu.Menu} this
2063 * @param {Roo.EventObject} e
2064 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2069 * Fires when a menu item contained in this menu is clicked
2070 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2071 * @param {Roo.EventObject} e
2075 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2078 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2082 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2085 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2087 registerMenu : true,
2089 menuItems :false, // stores the menu items..
2099 getChildContainer : function() {
2103 getAutoCreate : function(){
2105 //if (['right'].indexOf(this.align)!==-1) {
2106 // cfg.cn[1].cls += ' pull-right'
2112 cls : 'dropdown-menu' ,
2113 style : 'z-index:1000'
2117 if (this.type === 'submenu') {
2118 cfg.cls = 'submenu active';
2120 if (this.type === 'treeview') {
2121 cfg.cls = 'treeview-menu';
2126 initEvents : function() {
2128 // Roo.log("ADD event");
2129 // Roo.log(this.triggerEl.dom);
2131 this.triggerEl.on('click', this.onTriggerClick, this);
2133 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2136 if (this.triggerEl.hasClass('nav-item')) {
2137 // dropdown toggle on the 'a' in BS4?
2138 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2140 this.triggerEl.addClass('dropdown-toggle');
2143 this.el.on('touchstart' , this.onTouch, this);
2145 this.el.on('click' , this.onClick, this);
2147 this.el.on("mouseover", this.onMouseOver, this);
2148 this.el.on("mouseout", this.onMouseOut, this);
2152 findTargetItem : function(e)
2154 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2158 //Roo.log(t); Roo.log(t.id);
2160 //Roo.log(this.menuitems);
2161 return this.menuitems.get(t.id);
2163 //return this.items.get(t.menuItemId);
2169 onTouch : function(e)
2171 Roo.log("menu.onTouch");
2172 //e.stopEvent(); this make the user popdown broken
2176 onClick : function(e)
2178 Roo.log("menu.onClick");
2180 var t = this.findTargetItem(e);
2181 if(!t || t.isContainer){
2186 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2187 if(t == this.activeItem && t.shouldDeactivate(e)){
2188 this.activeItem.deactivate();
2189 delete this.activeItem;
2193 this.setActiveItem(t, true);
2201 Roo.log('pass click event');
2205 this.fireEvent("click", this, t, e);
2209 if(!t.href.length || t.href == '#'){
2210 (function() { _this.hide(); }).defer(100);
2215 onMouseOver : function(e){
2216 var t = this.findTargetItem(e);
2219 // if(t.canActivate && !t.disabled){
2220 // this.setActiveItem(t, true);
2224 this.fireEvent("mouseover", this, e, t);
2226 isVisible : function(){
2227 return !this.hidden;
2229 onMouseOut : function(e){
2230 var t = this.findTargetItem(e);
2233 // if(t == this.activeItem && t.shouldDeactivate(e)){
2234 // this.activeItem.deactivate();
2235 // delete this.activeItem;
2238 this.fireEvent("mouseout", this, e, t);
2243 * Displays this menu relative to another element
2244 * @param {String/HTMLElement/Roo.Element} element The element to align to
2245 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2246 * the element (defaults to this.defaultAlign)
2247 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2249 show : function(el, pos, parentMenu){
2250 this.parentMenu = parentMenu;
2254 this.fireEvent("beforeshow", this);
2255 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2258 * Displays this menu at a specific xy position
2259 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2260 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2262 showAt : function(xy, parentMenu, /* private: */_e){
2263 this.parentMenu = parentMenu;
2268 this.fireEvent("beforeshow", this);
2269 //xy = this.el.adjustForConstraints(xy);
2273 this.hideMenuItems();
2274 this.hidden = false;
2275 this.triggerEl.addClass('open');
2276 this.el.addClass('show');
2278 // reassign x when hitting right
2279 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2280 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2283 // reassign y when hitting bottom
2284 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2285 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2288 // but the list may align on trigger left or trigger top... should it be a properity?
2290 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2295 this.fireEvent("show", this);
2301 this.doFocus.defer(50, this);
2305 doFocus : function(){
2307 this.focusEl.focus();
2312 * Hides this menu and optionally all parent menus
2313 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2315 hide : function(deep)
2318 this.hideMenuItems();
2319 if(this.el && this.isVisible()){
2320 this.fireEvent("beforehide", this);
2321 if(this.activeItem){
2322 this.activeItem.deactivate();
2323 this.activeItem = null;
2325 this.triggerEl.removeClass('open');;
2326 this.el.removeClass('show');
2328 this.fireEvent("hide", this);
2330 if(deep === true && this.parentMenu){
2331 this.parentMenu.hide(true);
2335 onTriggerClick : function(e)
2337 Roo.log('trigger click');
2339 var target = e.getTarget();
2341 Roo.log(target.nodeName.toLowerCase());
2343 if(target.nodeName.toLowerCase() === 'i'){
2349 onTriggerPress : function(e)
2351 Roo.log('trigger press');
2352 //Roo.log(e.getTarget());
2353 // Roo.log(this.triggerEl.dom);
2355 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2356 var pel = Roo.get(e.getTarget());
2357 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2358 Roo.log('is treeview or dropdown?');
2362 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2366 if (this.isVisible()) {
2371 this.show(this.triggerEl, false, false);
2374 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2381 hideMenuItems : function()
2383 Roo.log("hide Menu Items");
2387 //$(backdrop).remove()
2388 this.el.select('.open',true).each(function(aa) {
2390 aa.removeClass('open');
2391 //var parent = getParent($(this))
2392 //var relatedTarget = { relatedTarget: this }
2394 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2395 //if (e.isDefaultPrevented()) return
2396 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2399 addxtypeChild : function (tree, cntr) {
2400 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2402 this.menuitems.add(comp);
2414 this.getEl().dom.innerHTML = '';
2415 this.menuitems.clear();
2429 * @class Roo.bootstrap.MenuItem
2430 * @extends Roo.bootstrap.Component
2431 * Bootstrap MenuItem class
2432 * @cfg {String} html the menu label
2433 * @cfg {String} href the link
2434 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2435 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2436 * @cfg {Boolean} active used on sidebars to highlight active itesm
2437 * @cfg {String} fa favicon to show on left of menu item.
2438 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2442 * Create a new MenuItem
2443 * @param {Object} config The config object
2447 Roo.bootstrap.MenuItem = function(config){
2448 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2453 * The raw click event for the entire grid.
2454 * @param {Roo.bootstrap.MenuItem} this
2455 * @param {Roo.EventObject} e
2461 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2465 preventDefault: false,
2466 isContainer : false,
2470 getAutoCreate : function(){
2472 if(this.isContainer){
2475 cls: 'dropdown-menu-item dropdown-item'
2489 if (this.fa !== false) {
2492 cls : 'fa fa-' + this.fa
2501 cls: 'dropdown-menu-item dropdown-item',
2504 if (this.parent().type == 'treeview') {
2505 cfg.cls = 'treeview-menu';
2508 cfg.cls += ' active';
2513 anc.href = this.href || cfg.cn[0].href ;
2514 ctag.html = this.html || cfg.cn[0].html ;
2518 initEvents: function()
2520 if (this.parent().type == 'treeview') {
2521 this.el.select('a').on('click', this.onClick, this);
2525 this.menu.parentType = this.xtype;
2526 this.menu.triggerEl = this.el;
2527 this.menu = this.addxtype(Roo.apply({}, this.menu));
2531 onClick : function(e)
2533 Roo.log('item on click ');
2535 if(this.preventDefault){
2538 //this.parent().hideMenuItems();
2540 this.fireEvent('click', this, e);
2559 * @class Roo.bootstrap.MenuSeparator
2560 * @extends Roo.bootstrap.Component
2561 * Bootstrap MenuSeparator class
2564 * Create a new MenuItem
2565 * @param {Object} config The config object
2569 Roo.bootstrap.MenuSeparator = function(config){
2570 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2573 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2575 getAutoCreate : function(){
2594 * @class Roo.bootstrap.Modal
2595 * @extends Roo.bootstrap.Component
2596 * Bootstrap Modal class
2597 * @cfg {String} title Title of dialog
2598 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2599 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2600 * @cfg {Boolean} specificTitle default false
2601 * @cfg {Array} buttons Array of buttons or standard button set..
2602 * @cfg {String} buttonPosition (left|right|center) default right
2603 * @cfg {Boolean} animate default true
2604 * @cfg {Boolean} allow_close default true
2605 * @cfg {Boolean} fitwindow default false
2606 * @cfg {String} size (sm|lg) default empty
2607 * @cfg {Number} max_width set the max width of modal
2611 * Create a new Modal Dialog
2612 * @param {Object} config The config object
2615 Roo.bootstrap.Modal = function(config){
2616 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2621 * The raw btnclick event for the button
2622 * @param {Roo.EventObject} e
2627 * Fire when dialog resize
2628 * @param {Roo.bootstrap.Modal} this
2629 * @param {Roo.EventObject} e
2633 this.buttons = this.buttons || [];
2636 this.tmpl = Roo.factory(this.tmpl);
2641 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2643 title : 'test dialog',
2653 specificTitle: false,
2655 buttonPosition: 'right',
2678 onRender : function(ct, position)
2680 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2683 var cfg = Roo.apply({}, this.getAutoCreate());
2686 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2688 //if (!cfg.name.length) {
2692 cfg.cls += ' ' + this.cls;
2695 cfg.style = this.style;
2697 this.el = Roo.get(document.body).createChild(cfg, position);
2699 //var type = this.el.dom.type;
2702 if(this.tabIndex !== undefined){
2703 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2706 this.dialogEl = this.el.select('.modal-dialog',true).first();
2707 this.bodyEl = this.el.select('.modal-body',true).first();
2708 this.closeEl = this.el.select('.modal-header .close', true).first();
2709 this.headerEl = this.el.select('.modal-header',true).first();
2710 this.titleEl = this.el.select('.modal-title',true).first();
2711 this.footerEl = this.el.select('.modal-footer',true).first();
2713 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2715 //this.el.addClass("x-dlg-modal");
2717 if (this.buttons.length) {
2718 Roo.each(this.buttons, function(bb) {
2719 var b = Roo.apply({}, bb);
2720 b.xns = b.xns || Roo.bootstrap;
2721 b.xtype = b.xtype || 'Button';
2722 if (typeof(b.listeners) == 'undefined') {
2723 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2726 var btn = Roo.factory(b);
2728 btn.render(this.el.select('.modal-footer div').first());
2732 // render the children.
2735 if(typeof(this.items) != 'undefined'){
2736 var items = this.items;
2739 for(var i =0;i < items.length;i++) {
2740 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2744 this.items = nitems;
2746 // where are these used - they used to be body/close/footer
2750 //this.el.addClass([this.fieldClass, this.cls]);
2754 getAutoCreate : function()
2758 html : this.html || ''
2763 cls : 'modal-title',
2767 if(this.specificTitle){
2773 if (this.allow_close) {
2785 if(this.size.length){
2786 size = 'modal-' + this.size;
2793 cls: "modal-dialog " + size,
2796 cls : "modal-content",
2799 cls : 'modal-header',
2804 cls : 'modal-footer',
2808 cls: 'btn-' + this.buttonPosition
2825 modal.cls += ' fade';
2831 getChildContainer : function() {
2836 getButtonContainer : function() {
2837 return this.el.select('.modal-footer div',true).first();
2840 initEvents : function()
2842 if (this.allow_close) {
2843 this.closeEl.on('click', this.hide, this);
2845 Roo.EventManager.onWindowResize(this.resize, this, true);
2852 this.maskEl.setSize(
2853 Roo.lib.Dom.getViewWidth(true),
2854 Roo.lib.Dom.getViewHeight(true)
2857 if (this.fitwindow) {
2859 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2860 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2865 if(this.max_width !== 0) {
2867 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2870 this.setSize(w, this.height);
2874 if(this.max_height) {
2875 this.setSize(w,Math.min(
2877 Roo.lib.Dom.getViewportHeight(true) - 60
2883 if(!this.fit_content) {
2884 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2888 this.setSize(w, Math.min(
2890 this.headerEl.getHeight() +
2891 this.footerEl.getHeight() +
2892 this.getChildHeight(this.bodyEl.dom.childNodes),
2893 Roo.lib.Dom.getViewportHeight(true) - 60)
2899 setSize : function(w,h)
2910 if (!this.rendered) {
2914 //this.el.setStyle('display', 'block');
2915 this.el.removeClass('hideing');
2916 this.el.addClass('show');
2918 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2921 this.el.addClass('in');
2924 this.el.addClass('in');
2927 // not sure how we can show data in here..
2929 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2932 Roo.get(document.body).addClass("x-body-masked");
2934 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2935 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2936 this.maskEl.addClass('show');
2940 this.fireEvent('show', this);
2942 // set zindex here - otherwise it appears to be ignored...
2943 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2946 this.items.forEach( function(e) {
2947 e.layout ? e.layout() : false;
2955 if(this.fireEvent("beforehide", this) !== false){
2956 this.maskEl.removeClass('show');
2957 Roo.get(document.body).removeClass("x-body-masked");
2958 this.el.removeClass('in');
2959 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2961 if(this.animate){ // why
2962 this.el.addClass('hideing');
2964 if (!this.el.hasClass('hideing')) {
2965 return; // it's been shown again...
2967 this.el.removeClass('show');
2968 this.el.removeClass('hideing');
2972 this.el.removeClass('show');
2974 this.fireEvent('hide', this);
2977 isVisible : function()
2980 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2984 addButton : function(str, cb)
2988 var b = Roo.apply({}, { html : str } );
2989 b.xns = b.xns || Roo.bootstrap;
2990 b.xtype = b.xtype || 'Button';
2991 if (typeof(b.listeners) == 'undefined') {
2992 b.listeners = { click : cb.createDelegate(this) };
2995 var btn = Roo.factory(b);
2997 btn.render(this.el.select('.modal-footer div').first());
3003 setDefaultButton : function(btn)
3005 //this.el.select('.modal-footer').()
3009 resizeTo: function(w,h)
3013 this.dialogEl.setWidth(w);
3014 if (this.diff === false) {
3015 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3018 this.bodyEl.setHeight(h - this.diff);
3020 this.fireEvent('resize', this);
3023 setContentSize : function(w, h)
3027 onButtonClick: function(btn,e)
3030 this.fireEvent('btnclick', btn.name, e);
3033 * Set the title of the Dialog
3034 * @param {String} str new Title
3036 setTitle: function(str) {
3037 this.titleEl.dom.innerHTML = str;
3040 * Set the body of the Dialog
3041 * @param {String} str new Title
3043 setBody: function(str) {
3044 this.bodyEl.dom.innerHTML = str;
3047 * Set the body of the Dialog using the template
3048 * @param {Obj} data - apply this data to the template and replace the body contents.
3050 applyBody: function(obj)
3053 Roo.log("Error - using apply Body without a template");
3056 this.tmpl.overwrite(this.bodyEl, obj);
3059 getChildHeight : function(child_nodes)
3063 child_nodes.length == 0
3068 var child_height = 0;
3070 for(var i = 0; i < child_nodes.length; i++) {
3073 * for modal with tabs...
3074 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3076 var layout_childs = child_nodes[i].childNodes;
3078 for(var j = 0; j < layout_childs.length; j++) {
3080 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3082 var layout_body_childs = layout_childs[j].childNodes;
3084 for(var k = 0; k < layout_body_childs.length; k++) {
3086 if(layout_body_childs[k].classList.contains('navbar')) {
3087 child_height += layout_body_childs[k].offsetHeight;
3091 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3093 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3095 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3097 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3098 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3113 child_height += child_nodes[i].offsetHeight;
3114 // Roo.log(child_nodes[i].offsetHeight);
3117 return child_height;
3123 Roo.apply(Roo.bootstrap.Modal, {
3125 * Button config that displays a single OK button
3134 * Button config that displays Yes and No buttons
3150 * Button config that displays OK and Cancel buttons
3165 * Button config that displays Yes, No and Cancel buttons
3189 * messagebox - can be used as a replace
3193 * @class Roo.MessageBox
3194 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3198 Roo.Msg.alert('Status', 'Changes saved successfully.');
3200 // Prompt for user data:
3201 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3203 // process text value...
3207 // Show a dialog using config options:
3209 title:'Save Changes?',
3210 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3211 buttons: Roo.Msg.YESNOCANCEL,
3218 Roo.bootstrap.MessageBox = function(){
3219 var dlg, opt, mask, waitTimer;
3220 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3221 var buttons, activeTextEl, bwidth;
3225 var handleButton = function(button){
3227 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3231 var handleHide = function(){
3233 dlg.el.removeClass(opt.cls);
3236 // Roo.TaskMgr.stop(waitTimer);
3237 // waitTimer = null;
3242 var updateButtons = function(b){
3245 buttons["ok"].hide();
3246 buttons["cancel"].hide();
3247 buttons["yes"].hide();
3248 buttons["no"].hide();
3249 //dlg.footer.dom.style.display = 'none';
3252 dlg.footerEl.dom.style.display = '';
3253 for(var k in buttons){
3254 if(typeof buttons[k] != "function"){
3257 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3258 width += buttons[k].el.getWidth()+15;
3268 var handleEsc = function(d, k, e){
3269 if(opt && opt.closable !== false){
3279 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3280 * @return {Roo.BasicDialog} The BasicDialog element
3282 getDialog : function(){
3284 dlg = new Roo.bootstrap.Modal( {
3287 //constraintoviewport:false,
3289 //collapsible : false,
3294 //buttonAlign:"center",
3295 closeClick : function(){
3296 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3299 handleButton("cancel");
3304 dlg.on("hide", handleHide);
3306 //dlg.addKeyListener(27, handleEsc);
3308 this.buttons = buttons;
3309 var bt = this.buttonText;
3310 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3311 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3312 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3313 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3315 bodyEl = dlg.bodyEl.createChild({
3317 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3318 '<textarea class="roo-mb-textarea"></textarea>' +
3319 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3321 msgEl = bodyEl.dom.firstChild;
3322 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3323 textboxEl.enableDisplayMode();
3324 textboxEl.addKeyListener([10,13], function(){
3325 if(dlg.isVisible() && opt && opt.buttons){
3328 }else if(opt.buttons.yes){
3329 handleButton("yes");
3333 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3334 textareaEl.enableDisplayMode();
3335 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3336 progressEl.enableDisplayMode();
3338 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3339 var pf = progressEl.dom.firstChild;
3341 pp = Roo.get(pf.firstChild);
3342 pp.setHeight(pf.offsetHeight);
3350 * Updates the message box body text
3351 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3352 * the XHTML-compliant non-breaking space character '&#160;')
3353 * @return {Roo.MessageBox} This message box
3355 updateText : function(text)
3357 if(!dlg.isVisible() && !opt.width){
3358 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3359 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3361 msgEl.innerHTML = text || ' ';
3363 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3364 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3366 Math.min(opt.width || cw , this.maxWidth),
3367 Math.max(opt.minWidth || this.minWidth, bwidth)
3370 activeTextEl.setWidth(w);
3372 if(dlg.isVisible()){
3373 dlg.fixedcenter = false;
3375 // to big, make it scroll. = But as usual stupid IE does not support
3378 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3379 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3380 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3382 bodyEl.dom.style.height = '';
3383 bodyEl.dom.style.overflowY = '';
3386 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3388 bodyEl.dom.style.overflowX = '';
3391 dlg.setContentSize(w, bodyEl.getHeight());
3392 if(dlg.isVisible()){
3393 dlg.fixedcenter = true;
3399 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3400 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3401 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3402 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3403 * @return {Roo.MessageBox} This message box
3405 updateProgress : function(value, text){
3407 this.updateText(text);
3410 if (pp) { // weird bug on my firefox - for some reason this is not defined
3411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3412 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3418 * Returns true if the message box is currently displayed
3419 * @return {Boolean} True if the message box is visible, else false
3421 isVisible : function(){
3422 return dlg && dlg.isVisible();
3426 * Hides the message box if it is displayed
3429 if(this.isVisible()){
3435 * Displays a new message box, or reinitializes an existing message box, based on the config options
3436 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3437 * The following config object properties are supported:
3439 Property Type Description
3440 ---------- --------------- ------------------------------------------------------------------------------------
3441 animEl String/Element An id or Element from which the message box should animate as it opens and
3442 closes (defaults to undefined)
3443 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3444 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3445 closable Boolean False to hide the top-right close button (defaults to true). Note that
3446 progress and wait dialogs will ignore this property and always hide the
3447 close button as they can only be closed programmatically.
3448 cls String A custom CSS class to apply to the message box element
3449 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3450 displayed (defaults to 75)
3451 fn Function A callback function to execute after closing the dialog. The arguments to the
3452 function will be btn (the name of the button that was clicked, if applicable,
3453 e.g. "ok"), and text (the value of the active text field, if applicable).
3454 Progress and wait dialogs will ignore this option since they do not respond to
3455 user actions and can only be closed programmatically, so any required function
3456 should be called by the same code after it closes the dialog.
3457 icon String A CSS class that provides a background image to be used as an icon for
3458 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3459 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3460 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3461 modal Boolean False to allow user interaction with the page while the message box is
3462 displayed (defaults to true)
3463 msg String A string that will replace the existing message box body text (defaults
3464 to the XHTML-compliant non-breaking space character ' ')
3465 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3466 progress Boolean True to display a progress bar (defaults to false)
3467 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3468 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3469 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3470 title String The title text
3471 value String The string value to set into the active textbox element if displayed
3472 wait Boolean True to display a progress bar (defaults to false)
3473 width Number The width of the dialog in pixels
3480 msg: 'Please enter your address:',
3482 buttons: Roo.MessageBox.OKCANCEL,
3485 animEl: 'addAddressBtn'
3488 * @param {Object} config Configuration options
3489 * @return {Roo.MessageBox} This message box
3491 show : function(options)
3494 // this causes nightmares if you show one dialog after another
3495 // especially on callbacks..
3497 if(this.isVisible()){
3500 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3501 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3502 Roo.log("New Dialog Message:" + options.msg )
3503 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3504 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3507 var d = this.getDialog();
3509 d.setTitle(opt.title || " ");
3510 d.closeEl.setDisplayed(opt.closable !== false);
3511 activeTextEl = textboxEl;
3512 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3517 textareaEl.setHeight(typeof opt.multiline == "number" ?
3518 opt.multiline : this.defaultTextHeight);
3519 activeTextEl = textareaEl;
3528 progressEl.setDisplayed(opt.progress === true);
3529 this.updateProgress(0);
3530 activeTextEl.dom.value = opt.value || "";
3532 dlg.setDefaultButton(activeTextEl);
3534 var bs = opt.buttons;
3538 }else if(bs && bs.yes){
3539 db = buttons["yes"];
3541 dlg.setDefaultButton(db);
3543 bwidth = updateButtons(opt.buttons);
3544 this.updateText(opt.msg);
3546 d.el.addClass(opt.cls);
3548 d.proxyDrag = opt.proxyDrag === true;
3549 d.modal = opt.modal !== false;
3550 d.mask = opt.modal !== false ? mask : false;
3552 // force it to the end of the z-index stack so it gets a cursor in FF
3553 document.body.appendChild(dlg.el.dom);
3554 d.animateTarget = null;
3555 d.show(options.animEl);
3561 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3562 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3563 * and closing the message box when the process is complete.
3564 * @param {String} title The title bar text
3565 * @param {String} msg The message box body text
3566 * @return {Roo.MessageBox} This message box
3568 progress : function(title, msg){
3575 minWidth: this.minProgressWidth,
3582 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3583 * If a callback function is passed it will be called after the user clicks the button, and the
3584 * id of the button that was clicked will be passed as the only parameter to the callback
3585 * (could also be the top-right close button).
3586 * @param {String} title The title bar text
3587 * @param {String} msg The message box body text
3588 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3589 * @param {Object} scope (optional) The scope of the callback function
3590 * @return {Roo.MessageBox} This message box
3592 alert : function(title, msg, fn, scope)
3607 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3608 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3609 * You are responsible for closing the message box when the process is complete.
3610 * @param {String} msg The message box body text
3611 * @param {String} title (optional) The title bar text
3612 * @return {Roo.MessageBox} This message box
3614 wait : function(msg, title){
3625 waitTimer = Roo.TaskMgr.start({
3627 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3635 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3636 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3637 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3638 * @param {String} title The title bar text
3639 * @param {String} msg The message box body text
3640 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3641 * @param {Object} scope (optional) The scope of the callback function
3642 * @return {Roo.MessageBox} This message box
3644 confirm : function(title, msg, fn, scope){
3648 buttons: this.YESNO,
3657 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3658 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3659 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3660 * (could also be the top-right close button) and the text that was entered will be passed as the two
3661 * parameters to the callback.
3662 * @param {String} title The title bar text
3663 * @param {String} msg The message box body text
3664 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3665 * @param {Object} scope (optional) The scope of the callback function
3666 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3667 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3668 * @return {Roo.MessageBox} This message box
3670 prompt : function(title, msg, fn, scope, multiline){
3674 buttons: this.OKCANCEL,
3679 multiline: multiline,
3686 * Button config that displays a single OK button
3691 * Button config that displays Yes and No buttons
3694 YESNO : {yes:true, no:true},
3696 * Button config that displays OK and Cancel buttons
3699 OKCANCEL : {ok:true, cancel:true},
3701 * Button config that displays Yes, No and Cancel buttons
3704 YESNOCANCEL : {yes:true, no:true, cancel:true},
3707 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3710 defaultTextHeight : 75,
3712 * The maximum width in pixels of the message box (defaults to 600)
3717 * The minimum width in pixels of the message box (defaults to 100)
3722 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3723 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3726 minProgressWidth : 250,
3728 * An object containing the default button text strings that can be overriden for localized language support.
3729 * Supported properties are: ok, cancel, yes and no.
3730 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3743 * Shorthand for {@link Roo.MessageBox}
3745 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3746 Roo.Msg = Roo.Msg || Roo.MessageBox;
3755 * @class Roo.bootstrap.Navbar
3756 * @extends Roo.bootstrap.Component
3757 * Bootstrap Navbar class
3760 * Create a new Navbar
3761 * @param {Object} config The config object
3765 Roo.bootstrap.Navbar = function(config){
3766 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3770 * @event beforetoggle
3771 * Fire before toggle the menu
3772 * @param {Roo.EventObject} e
3774 "beforetoggle" : true
3778 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3787 getAutoCreate : function(){
3790 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3794 initEvents :function ()
3796 //Roo.log(this.el.select('.navbar-toggle',true));
3797 this.el.select('.navbar-toggle',true).on('click', function() {
3798 if(this.fireEvent('beforetoggle', this) !== false){
3799 this.el.select('.navbar-collapse',true).toggleClass('in');
3809 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3811 var size = this.el.getSize();
3812 this.maskEl.setSize(size.width, size.height);
3813 this.maskEl.enableDisplayMode("block");
3822 getChildContainer : function()
3824 if (this.el.select('.collapse').getCount()) {
3825 return this.el.select('.collapse',true).first();
3858 * @class Roo.bootstrap.NavSimplebar
3859 * @extends Roo.bootstrap.Navbar
3860 * Bootstrap Sidebar class
3862 * @cfg {Boolean} inverse is inverted color
3864 * @cfg {String} type (nav | pills | tabs)
3865 * @cfg {Boolean} arrangement stacked | justified
3866 * @cfg {String} align (left | right) alignment
3868 * @cfg {Boolean} main (true|false) main nav bar? default false
3869 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3871 * @cfg {String} tag (header|footer|nav|div) default is nav
3877 * Create a new Sidebar
3878 * @param {Object} config The config object
3882 Roo.bootstrap.NavSimplebar = function(config){
3883 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3886 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3902 getAutoCreate : function(){
3906 tag : this.tag || 'div',
3919 this.type = this.type || 'nav';
3920 if (['tabs','pills'].indexOf(this.type)!==-1) {
3921 cfg.cn[0].cls += ' nav-' + this.type
3925 if (this.type!=='nav') {
3926 Roo.log('nav type must be nav/tabs/pills')
3928 cfg.cn[0].cls += ' navbar-nav'
3934 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3935 cfg.cn[0].cls += ' nav-' + this.arrangement;
3939 if (this.align === 'right') {
3940 cfg.cn[0].cls += ' navbar-right';
3944 cfg.cls += ' navbar-inverse';
3968 * navbar-expand-md fixed-top
3972 * @class Roo.bootstrap.NavHeaderbar
3973 * @extends Roo.bootstrap.NavSimplebar
3974 * Bootstrap Sidebar class
3976 * @cfg {String} brand what is brand
3977 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3978 * @cfg {String} brand_href href of the brand
3979 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3980 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3981 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3982 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3985 * Create a new Sidebar
3986 * @param {Object} config The config object
3990 Roo.bootstrap.NavHeaderbar = function(config){
3991 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3995 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4002 desktopCenter : false,
4005 getAutoCreate : function(){
4008 tag: this.nav || 'nav',
4009 cls: 'navbar navbar-expand-md',
4015 if (this.desktopCenter) {
4016 cn.push({cls : 'container', cn : []});
4023 cls: 'navbar-header',
4028 cls: 'navbar-toggle navbar-toggler',
4029 'data-toggle': 'collapse',
4034 html: 'Toggle navigation'
4038 cls: 'icon-bar navbar-toggler-icon'
4056 cls: 'collapse navbar-collapse',
4060 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4062 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4063 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4065 // tag can override this..
4067 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4070 if (this.brand !== '') {
4073 href: this.brand_href ? this.brand_href : '#',
4074 cls: 'navbar-brand',
4082 cfg.cls += ' main-nav';
4090 getHeaderChildContainer : function()
4092 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4093 return this.el.select('.navbar-header',true).first();
4096 return this.getChildContainer();
4100 initEvents : function()
4102 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4104 if (this.autohide) {
4109 Roo.get(document).on('scroll',function(e) {
4110 var ns = Roo.get(document).getScroll().top;
4111 var os = prevScroll;
4115 ft.removeClass('slideDown');
4116 ft.addClass('slideUp');
4119 ft.removeClass('slideUp');
4120 ft.addClass('slideDown');
4141 * @class Roo.bootstrap.NavSidebar
4142 * @extends Roo.bootstrap.Navbar
4143 * Bootstrap Sidebar class
4146 * Create a new Sidebar
4147 * @param {Object} config The config object
4151 Roo.bootstrap.NavSidebar = function(config){
4152 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4155 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4157 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4159 getAutoCreate : function(){
4164 cls: 'sidebar sidebar-nav'
4186 * @class Roo.bootstrap.NavGroup
4187 * @extends Roo.bootstrap.Component
4188 * Bootstrap NavGroup class
4189 * @cfg {String} align (left|right)
4190 * @cfg {Boolean} inverse
4191 * @cfg {String} type (nav|pills|tab) default nav
4192 * @cfg {String} navId - reference Id for navbar.
4196 * Create a new nav group
4197 * @param {Object} config The config object
4200 Roo.bootstrap.NavGroup = function(config){
4201 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4204 Roo.bootstrap.NavGroup.register(this);
4208 * Fires when the active item changes
4209 * @param {Roo.bootstrap.NavGroup} this
4210 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4211 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4218 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4229 getAutoCreate : function()
4231 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4238 if (['tabs','pills'].indexOf(this.type)!==-1) {
4239 cfg.cls += ' nav-' + this.type
4241 if (this.type!=='nav') {
4242 Roo.log('nav type must be nav/tabs/pills')
4244 cfg.cls += ' navbar-nav mr-auto'
4247 if (this.parent() && this.parent().sidebar) {
4250 cls: 'dashboard-menu sidebar-menu'
4256 if (this.form === true) {
4262 if (this.align === 'right') {
4263 cfg.cls += ' navbar-right';
4265 cfg.cls += ' navbar-left';
4269 if (this.align === 'right') {
4270 cfg.cls += ' navbar-right';
4274 cfg.cls += ' navbar-inverse';
4282 * sets the active Navigation item
4283 * @param {Roo.bootstrap.NavItem} the new current navitem
4285 setActiveItem : function(item)
4288 Roo.each(this.navItems, function(v){
4293 v.setActive(false, true);
4300 item.setActive(true, true);
4301 this.fireEvent('changed', this, item, prev);
4306 * gets the active Navigation item
4307 * @return {Roo.bootstrap.NavItem} the current navitem
4309 getActive : function()
4313 Roo.each(this.navItems, function(v){
4324 indexOfNav : function()
4328 Roo.each(this.navItems, function(v,i){
4339 * adds a Navigation item
4340 * @param {Roo.bootstrap.NavItem} the navitem to add
4342 addItem : function(cfg)
4344 var cn = new Roo.bootstrap.NavItem(cfg);
4346 cn.parentId = this.id;
4347 cn.onRender(this.el, null);
4351 * register a Navigation item
4352 * @param {Roo.bootstrap.NavItem} the navitem to add
4354 register : function(item)
4356 this.navItems.push( item);
4357 item.navId = this.navId;
4362 * clear all the Navigation item
4365 clearAll : function()
4368 this.el.dom.innerHTML = '';
4371 getNavItem: function(tabId)
4374 Roo.each(this.navItems, function(e) {
4375 if (e.tabId == tabId) {
4385 setActiveNext : function()
4387 var i = this.indexOfNav(this.getActive());
4388 if (i > this.navItems.length) {
4391 this.setActiveItem(this.navItems[i+1]);
4393 setActivePrev : function()
4395 var i = this.indexOfNav(this.getActive());
4399 this.setActiveItem(this.navItems[i-1]);
4401 clearWasActive : function(except) {
4402 Roo.each(this.navItems, function(e) {
4403 if (e.tabId != except.tabId && e.was_active) {
4404 e.was_active = false;
4411 getWasActive : function ()
4414 Roo.each(this.navItems, function(e) {
4429 Roo.apply(Roo.bootstrap.NavGroup, {
4433 * register a Navigation Group
4434 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4436 register : function(navgrp)
4438 this.groups[navgrp.navId] = navgrp;
4442 * fetch a Navigation Group based on the navigation ID
4443 * @param {string} the navgroup to add
4444 * @returns {Roo.bootstrap.NavGroup} the navgroup
4446 get: function(navId) {
4447 if (typeof(this.groups[navId]) == 'undefined') {
4449 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4451 return this.groups[navId] ;
4466 * @class Roo.bootstrap.NavItem
4467 * @extends Roo.bootstrap.Component
4468 * Bootstrap Navbar.NavItem class
4469 * @cfg {String} href link to
4470 * @cfg {String} html content of button
4471 * @cfg {String} badge text inside badge
4472 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4473 * @cfg {String} glyphicon name of glyphicon
4474 * @cfg {String} icon name of font awesome icon
4475 * @cfg {Boolean} active Is item active
4476 * @cfg {Boolean} disabled Is item disabled
4478 * @cfg {Boolean} preventDefault (true | false) default false
4479 * @cfg {String} tabId the tab that this item activates.
4480 * @cfg {String} tagtype (a|span) render as a href or span?
4481 * @cfg {Boolean} animateRef (true|false) link to element default false
4484 * Create a new Navbar Item
4485 * @param {Object} config The config object
4487 Roo.bootstrap.NavItem = function(config){
4488 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4493 * The raw click event for the entire grid.
4494 * @param {Roo.EventObject} e
4499 * Fires when the active item active state changes
4500 * @param {Roo.bootstrap.NavItem} this
4501 * @param {boolean} state the new state
4507 * Fires when scroll to element
4508 * @param {Roo.bootstrap.NavItem} this
4509 * @param {Object} options
4510 * @param {Roo.EventObject} e
4518 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4526 preventDefault : false,
4533 getAutoCreate : function(){
4542 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4544 if (this.disabled) {
4545 cfg.cls += ' disabled';
4548 if (this.href || this.html || this.glyphicon || this.icon) {
4552 href : this.href || "#",
4553 html: this.html || ''
4556 if (this.tagtype == 'a') {
4557 cfg.cn[0].cls = 'nav-link';
4560 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4563 if(this.glyphicon) {
4564 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4569 cfg.cn[0].html += " <span class='caret'></span>";
4573 if (this.badge !== '') {
4575 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4583 initEvents: function()
4585 if (typeof (this.menu) != 'undefined') {
4586 this.menu.parentType = this.xtype;
4587 this.menu.triggerEl = this.el;
4588 this.menu = this.addxtype(Roo.apply({}, this.menu));
4591 this.el.select('a',true).on('click', this.onClick, this);
4593 if(this.tagtype == 'span'){
4594 this.el.select('span',true).on('click', this.onClick, this);
4597 // at this point parent should be available..
4598 this.parent().register(this);
4601 onClick : function(e)
4603 if (e.getTarget('.dropdown-menu-item')) {
4604 // did you click on a menu itemm.... - then don't trigger onclick..
4609 this.preventDefault ||
4612 Roo.log("NavItem - prevent Default?");
4616 if (this.disabled) {
4620 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4621 if (tg && tg.transition) {
4622 Roo.log("waiting for the transitionend");
4628 //Roo.log("fire event clicked");
4629 if(this.fireEvent('click', this, e) === false){
4633 if(this.tagtype == 'span'){
4637 //Roo.log(this.href);
4638 var ael = this.el.select('a',true).first();
4641 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4642 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4643 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4644 return; // ignore... - it's a 'hash' to another page.
4646 Roo.log("NavItem - prevent Default?");
4648 this.scrollToElement(e);
4652 var p = this.parent();
4654 if (['tabs','pills'].indexOf(p.type)!==-1) {
4655 if (typeof(p.setActiveItem) !== 'undefined') {
4656 p.setActiveItem(this);
4660 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4661 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4662 // remove the collapsed menu expand...
4663 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4667 isActive: function () {
4670 setActive : function(state, fire, is_was_active)
4672 if (this.active && !state && this.navId) {
4673 this.was_active = true;
4674 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4676 nv.clearWasActive(this);
4680 this.active = state;
4683 this.el.removeClass('active');
4684 } else if (!this.el.hasClass('active')) {
4685 this.el.addClass('active');
4688 this.fireEvent('changed', this, state);
4691 // show a panel if it's registered and related..
4693 if (!this.navId || !this.tabId || !state || is_was_active) {
4697 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4701 var pan = tg.getPanelByName(this.tabId);
4705 // if we can not flip to new panel - go back to old nav highlight..
4706 if (false == tg.showPanel(pan)) {
4707 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4709 var onav = nv.getWasActive();
4711 onav.setActive(true, false, true);
4720 // this should not be here...
4721 setDisabled : function(state)
4723 this.disabled = state;
4725 this.el.removeClass('disabled');
4726 } else if (!this.el.hasClass('disabled')) {
4727 this.el.addClass('disabled');
4733 * Fetch the element to display the tooltip on.
4734 * @return {Roo.Element} defaults to this.el
4736 tooltipEl : function()
4738 return this.el.select('' + this.tagtype + '', true).first();
4741 scrollToElement : function(e)
4743 var c = document.body;
4746 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4748 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4749 c = document.documentElement;
4752 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4758 var o = target.calcOffsetsTo(c);
4765 this.fireEvent('scrollto', this, options, e);
4767 Roo.get(c).scrollTo('top', options.value, true);
4780 * <span> icon </span>
4781 * <span> text </span>
4782 * <span>badge </span>
4786 * @class Roo.bootstrap.NavSidebarItem
4787 * @extends Roo.bootstrap.NavItem
4788 * Bootstrap Navbar.NavSidebarItem class
4789 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4790 * {Boolean} open is the menu open
4791 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4792 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4793 * {String} buttonSize (sm|md|lg)the extra classes for the button
4794 * {Boolean} showArrow show arrow next to the text (default true)
4796 * Create a new Navbar Button
4797 * @param {Object} config The config object
4799 Roo.bootstrap.NavSidebarItem = function(config){
4800 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4805 * The raw click event for the entire grid.
4806 * @param {Roo.EventObject} e
4811 * Fires when the active item active state changes
4812 * @param {Roo.bootstrap.NavSidebarItem} this
4813 * @param {boolean} state the new state
4821 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4823 badgeWeight : 'default',
4829 buttonWeight : 'default',
4835 getAutoCreate : function(){
4840 href : this.href || '#',
4846 if(this.buttonView){
4849 href : this.href || '#',
4850 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4863 cfg.cls += ' active';
4866 if (this.disabled) {
4867 cfg.cls += ' disabled';
4870 cfg.cls += ' open x-open';
4873 if (this.glyphicon || this.icon) {
4874 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4875 a.cn.push({ tag : 'i', cls : c }) ;
4878 if(!this.buttonView){
4881 html : this.html || ''
4888 if (this.badge !== '') {
4889 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4895 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4898 a.cls += ' dropdown-toggle treeview' ;
4904 initEvents : function()
4906 if (typeof (this.menu) != 'undefined') {
4907 this.menu.parentType = this.xtype;
4908 this.menu.triggerEl = this.el;
4909 this.menu = this.addxtype(Roo.apply({}, this.menu));
4912 this.el.on('click', this.onClick, this);
4914 if(this.badge !== ''){
4915 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4920 onClick : function(e)
4927 if(this.preventDefault){
4931 this.fireEvent('click', this);
4934 disable : function()
4936 this.setDisabled(true);
4941 this.setDisabled(false);
4944 setDisabled : function(state)
4946 if(this.disabled == state){
4950 this.disabled = state;
4953 this.el.addClass('disabled');
4957 this.el.removeClass('disabled');
4962 setActive : function(state)
4964 if(this.active == state){
4968 this.active = state;
4971 this.el.addClass('active');
4975 this.el.removeClass('active');
4980 isActive: function ()
4985 setBadge : function(str)
4991 this.badgeEl.dom.innerHTML = str;
5008 * @class Roo.bootstrap.Row
5009 * @extends Roo.bootstrap.Component
5010 * Bootstrap Row class (contains columns...)
5014 * @param {Object} config The config object
5017 Roo.bootstrap.Row = function(config){
5018 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5021 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5023 getAutoCreate : function(){
5042 * @class Roo.bootstrap.Element
5043 * @extends Roo.bootstrap.Component
5044 * Bootstrap Element class
5045 * @cfg {String} html contents of the element
5046 * @cfg {String} tag tag of the element
5047 * @cfg {String} cls class of the element
5048 * @cfg {Boolean} preventDefault (true|false) default false
5049 * @cfg {Boolean} clickable (true|false) default false
5052 * Create a new Element
5053 * @param {Object} config The config object
5056 Roo.bootstrap.Element = function(config){
5057 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5063 * When a element is chick
5064 * @param {Roo.bootstrap.Element} this
5065 * @param {Roo.EventObject} e
5071 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5076 preventDefault: false,
5079 getAutoCreate : function(){
5083 // cls: this.cls, double assign in parent class Component.js :: onRender
5090 initEvents: function()
5092 Roo.bootstrap.Element.superclass.initEvents.call(this);
5095 this.el.on('click', this.onClick, this);
5100 onClick : function(e)
5102 if(this.preventDefault){
5106 this.fireEvent('click', this, e);
5109 getValue : function()
5111 return this.el.dom.innerHTML;
5114 setValue : function(value)
5116 this.el.dom.innerHTML = value;
5131 * @class Roo.bootstrap.Pagination
5132 * @extends Roo.bootstrap.Component
5133 * Bootstrap Pagination class
5134 * @cfg {String} size xs | sm | md | lg
5135 * @cfg {Boolean} inverse false | true
5138 * Create a new Pagination
5139 * @param {Object} config The config object
5142 Roo.bootstrap.Pagination = function(config){
5143 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5146 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5152 getAutoCreate : function(){
5158 cfg.cls += ' inverse';
5164 cfg.cls += " " + this.cls;
5182 * @class Roo.bootstrap.PaginationItem
5183 * @extends Roo.bootstrap.Component
5184 * Bootstrap PaginationItem class
5185 * @cfg {String} html text
5186 * @cfg {String} href the link
5187 * @cfg {Boolean} preventDefault (true | false) default true
5188 * @cfg {Boolean} active (true | false) default false
5189 * @cfg {Boolean} disabled default false
5193 * Create a new PaginationItem
5194 * @param {Object} config The config object
5198 Roo.bootstrap.PaginationItem = function(config){
5199 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5204 * The raw click event for the entire grid.
5205 * @param {Roo.EventObject} e
5211 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5215 preventDefault: true,
5220 getAutoCreate : function(){
5226 href : this.href ? this.href : '#',
5227 html : this.html ? this.html : ''
5237 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5241 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5247 initEvents: function() {
5249 this.el.on('click', this.onClick, this);
5252 onClick : function(e)
5254 Roo.log('PaginationItem on click ');
5255 if(this.preventDefault){
5263 this.fireEvent('click', this, e);
5279 * @class Roo.bootstrap.Slider
5280 * @extends Roo.bootstrap.Component
5281 * Bootstrap Slider class
5284 * Create a new Slider
5285 * @param {Object} config The config object
5288 Roo.bootstrap.Slider = function(config){
5289 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5292 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5294 getAutoCreate : function(){
5298 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5302 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5314 * Ext JS Library 1.1.1
5315 * Copyright(c) 2006-2007, Ext JS, LLC.
5317 * Originally Released Under LGPL - original licence link has changed is not relivant.
5320 * <script type="text/javascript">
5325 * @class Roo.grid.ColumnModel
5326 * @extends Roo.util.Observable
5327 * This is the default implementation of a ColumnModel used by the Grid. It defines
5328 * the columns in the grid.
5331 var colModel = new Roo.grid.ColumnModel([
5332 {header: "Ticker", width: 60, sortable: true, locked: true},
5333 {header: "Company Name", width: 150, sortable: true},
5334 {header: "Market Cap.", width: 100, sortable: true},
5335 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5336 {header: "Employees", width: 100, sortable: true, resizable: false}
5341 * The config options listed for this class are options which may appear in each
5342 * individual column definition.
5343 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5345 * @param {Object} config An Array of column config objects. See this class's
5346 * config objects for details.
5348 Roo.grid.ColumnModel = function(config){
5350 * The config passed into the constructor
5352 this.config = config;
5355 // if no id, create one
5356 // if the column does not have a dataIndex mapping,
5357 // map it to the order it is in the config
5358 for(var i = 0, len = config.length; i < len; i++){
5360 if(typeof c.dataIndex == "undefined"){
5363 if(typeof c.renderer == "string"){
5364 c.renderer = Roo.util.Format[c.renderer];
5366 if(typeof c.id == "undefined"){
5369 if(c.editor && c.editor.xtype){
5370 c.editor = Roo.factory(c.editor, Roo.grid);
5372 if(c.editor && c.editor.isFormField){
5373 c.editor = new Roo.grid.GridEditor(c.editor);
5375 this.lookup[c.id] = c;
5379 * The width of columns which have no width specified (defaults to 100)
5382 this.defaultWidth = 100;
5385 * Default sortable of columns which have no sortable specified (defaults to false)
5388 this.defaultSortable = false;
5392 * @event widthchange
5393 * Fires when the width of a column changes.
5394 * @param {ColumnModel} this
5395 * @param {Number} columnIndex The column index
5396 * @param {Number} newWidth The new width
5398 "widthchange": true,
5400 * @event headerchange
5401 * Fires when the text of a header changes.
5402 * @param {ColumnModel} this
5403 * @param {Number} columnIndex The column index
5404 * @param {Number} newText The new header text
5406 "headerchange": true,
5408 * @event hiddenchange
5409 * Fires when a column is hidden or "unhidden".
5410 * @param {ColumnModel} this
5411 * @param {Number} columnIndex The column index
5412 * @param {Boolean} hidden true if hidden, false otherwise
5414 "hiddenchange": true,
5416 * @event columnmoved
5417 * Fires when a column is moved.
5418 * @param {ColumnModel} this
5419 * @param {Number} oldIndex
5420 * @param {Number} newIndex
5422 "columnmoved" : true,
5424 * @event columlockchange
5425 * Fires when a column's locked state is changed
5426 * @param {ColumnModel} this
5427 * @param {Number} colIndex
5428 * @param {Boolean} locked true if locked
5430 "columnlockchange" : true
5432 Roo.grid.ColumnModel.superclass.constructor.call(this);
5434 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5436 * @cfg {String} header The header text to display in the Grid view.
5439 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5440 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5441 * specified, the column's index is used as an index into the Record's data Array.
5444 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5445 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5448 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5449 * Defaults to the value of the {@link #defaultSortable} property.
5450 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5453 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5456 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5459 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5462 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5465 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5466 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5467 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5468 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5471 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5474 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5477 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5480 * @cfg {String} cursor (Optional)
5483 * @cfg {String} tooltip (Optional)
5486 * @cfg {Number} xs (Optional)
5489 * @cfg {Number} sm (Optional)
5492 * @cfg {Number} md (Optional)
5495 * @cfg {Number} lg (Optional)
5498 * Returns the id of the column at the specified index.
5499 * @param {Number} index The column index
5500 * @return {String} the id
5502 getColumnId : function(index){
5503 return this.config[index].id;
5507 * Returns the column for a specified id.
5508 * @param {String} id The column id
5509 * @return {Object} the column
5511 getColumnById : function(id){
5512 return this.lookup[id];
5517 * Returns the column for a specified dataIndex.
5518 * @param {String} dataIndex The column dataIndex
5519 * @return {Object|Boolean} the column or false if not found
5521 getColumnByDataIndex: function(dataIndex){
5522 var index = this.findColumnIndex(dataIndex);
5523 return index > -1 ? this.config[index] : false;
5527 * Returns the index for a specified column id.
5528 * @param {String} id The column id
5529 * @return {Number} the index, or -1 if not found
5531 getIndexById : function(id){
5532 for(var i = 0, len = this.config.length; i < len; i++){
5533 if(this.config[i].id == id){
5541 * Returns the index for a specified column dataIndex.
5542 * @param {String} dataIndex The column dataIndex
5543 * @return {Number} the index, or -1 if not found
5546 findColumnIndex : function(dataIndex){
5547 for(var i = 0, len = this.config.length; i < len; i++){
5548 if(this.config[i].dataIndex == dataIndex){
5556 moveColumn : function(oldIndex, newIndex){
5557 var c = this.config[oldIndex];
5558 this.config.splice(oldIndex, 1);
5559 this.config.splice(newIndex, 0, c);
5560 this.dataMap = null;
5561 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5564 isLocked : function(colIndex){
5565 return this.config[colIndex].locked === true;
5568 setLocked : function(colIndex, value, suppressEvent){
5569 if(this.isLocked(colIndex) == value){
5572 this.config[colIndex].locked = value;
5574 this.fireEvent("columnlockchange", this, colIndex, value);
5578 getTotalLockedWidth : function(){
5580 for(var i = 0; i < this.config.length; i++){
5581 if(this.isLocked(i) && !this.isHidden(i)){
5582 this.totalWidth += this.getColumnWidth(i);
5588 getLockedCount : function(){
5589 for(var i = 0, len = this.config.length; i < len; i++){
5590 if(!this.isLocked(i)){
5595 return this.config.length;
5599 * Returns the number of columns.
5602 getColumnCount : function(visibleOnly){
5603 if(visibleOnly === true){
5605 for(var i = 0, len = this.config.length; i < len; i++){
5606 if(!this.isHidden(i)){
5612 return this.config.length;
5616 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5617 * @param {Function} fn
5618 * @param {Object} scope (optional)
5619 * @return {Array} result
5621 getColumnsBy : function(fn, scope){
5623 for(var i = 0, len = this.config.length; i < len; i++){
5624 var c = this.config[i];
5625 if(fn.call(scope||this, c, i) === true){
5633 * Returns true if the specified column is sortable.
5634 * @param {Number} col The column index
5637 isSortable : function(col){
5638 if(typeof this.config[col].sortable == "undefined"){
5639 return this.defaultSortable;
5641 return this.config[col].sortable;
5645 * Returns the rendering (formatting) function defined for the column.
5646 * @param {Number} col The column index.
5647 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5649 getRenderer : function(col){
5650 if(!this.config[col].renderer){
5651 return Roo.grid.ColumnModel.defaultRenderer;
5653 return this.config[col].renderer;
5657 * Sets the rendering (formatting) function for a column.
5658 * @param {Number} col The column index
5659 * @param {Function} fn The function to use to process the cell's raw data
5660 * to return HTML markup for the grid view. The render function is called with
5661 * the following parameters:<ul>
5662 * <li>Data value.</li>
5663 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5664 * <li>css A CSS style string to apply to the table cell.</li>
5665 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5666 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5667 * <li>Row index</li>
5668 * <li>Column index</li>
5669 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5671 setRenderer : function(col, fn){
5672 this.config[col].renderer = fn;
5676 * Returns the width for the specified column.
5677 * @param {Number} col The column index
5680 getColumnWidth : function(col){
5681 return this.config[col].width * 1 || this.defaultWidth;
5685 * Sets the width for a column.
5686 * @param {Number} col The column index
5687 * @param {Number} width The new width
5689 setColumnWidth : function(col, width, suppressEvent){
5690 this.config[col].width = width;
5691 this.totalWidth = null;
5693 this.fireEvent("widthchange", this, col, width);
5698 * Returns the total width of all columns.
5699 * @param {Boolean} includeHidden True to include hidden column widths
5702 getTotalWidth : function(includeHidden){
5703 if(!this.totalWidth){
5704 this.totalWidth = 0;
5705 for(var i = 0, len = this.config.length; i < len; i++){
5706 if(includeHidden || !this.isHidden(i)){
5707 this.totalWidth += this.getColumnWidth(i);
5711 return this.totalWidth;
5715 * Returns the header for the specified column.
5716 * @param {Number} col The column index
5719 getColumnHeader : function(col){
5720 return this.config[col].header;
5724 * Sets the header for a column.
5725 * @param {Number} col The column index
5726 * @param {String} header The new header
5728 setColumnHeader : function(col, header){
5729 this.config[col].header = header;
5730 this.fireEvent("headerchange", this, col, header);
5734 * Returns the tooltip for the specified column.
5735 * @param {Number} col The column index
5738 getColumnTooltip : function(col){
5739 return this.config[col].tooltip;
5742 * Sets the tooltip for a column.
5743 * @param {Number} col The column index
5744 * @param {String} tooltip The new tooltip
5746 setColumnTooltip : function(col, tooltip){
5747 this.config[col].tooltip = tooltip;
5751 * Returns the dataIndex for the specified column.
5752 * @param {Number} col The column index
5755 getDataIndex : function(col){
5756 return this.config[col].dataIndex;
5760 * Sets the dataIndex for a column.
5761 * @param {Number} col The column index
5762 * @param {Number} dataIndex The new dataIndex
5764 setDataIndex : function(col, dataIndex){
5765 this.config[col].dataIndex = dataIndex;
5771 * Returns true if the cell is editable.
5772 * @param {Number} colIndex The column index
5773 * @param {Number} rowIndex The row index - this is nto actually used..?
5776 isCellEditable : function(colIndex, rowIndex){
5777 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5781 * Returns the editor defined for the cell/column.
5782 * return false or null to disable editing.
5783 * @param {Number} colIndex The column index
5784 * @param {Number} rowIndex The row index
5787 getCellEditor : function(colIndex, rowIndex){
5788 return this.config[colIndex].editor;
5792 * Sets if a column is editable.
5793 * @param {Number} col The column index
5794 * @param {Boolean} editable True if the column is editable
5796 setEditable : function(col, editable){
5797 this.config[col].editable = editable;
5802 * Returns true if the column is hidden.
5803 * @param {Number} colIndex The column index
5806 isHidden : function(colIndex){
5807 return this.config[colIndex].hidden;
5812 * Returns true if the column width cannot be changed
5814 isFixed : function(colIndex){
5815 return this.config[colIndex].fixed;
5819 * Returns true if the column can be resized
5822 isResizable : function(colIndex){
5823 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5826 * Sets if a column is hidden.
5827 * @param {Number} colIndex The column index
5828 * @param {Boolean} hidden True if the column is hidden
5830 setHidden : function(colIndex, hidden){
5831 this.config[colIndex].hidden = hidden;
5832 this.totalWidth = null;
5833 this.fireEvent("hiddenchange", this, colIndex, hidden);
5837 * Sets the editor for a column.
5838 * @param {Number} col The column index
5839 * @param {Object} editor The editor object
5841 setEditor : function(col, editor){
5842 this.config[col].editor = editor;
5846 Roo.grid.ColumnModel.defaultRenderer = function(value)
5848 if(typeof value == "object") {
5851 if(typeof value == "string" && value.length < 1){
5855 return String.format("{0}", value);
5858 // Alias for backwards compatibility
5859 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5862 * Ext JS Library 1.1.1
5863 * Copyright(c) 2006-2007, Ext JS, LLC.
5865 * Originally Released Under LGPL - original licence link has changed is not relivant.
5868 * <script type="text/javascript">
5872 * @class Roo.LoadMask
5873 * A simple utility class for generically masking elements while loading data. If the element being masked has
5874 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5875 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5876 * element's UpdateManager load indicator and will be destroyed after the initial load.
5878 * Create a new LoadMask
5879 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5880 * @param {Object} config The config object
5882 Roo.LoadMask = function(el, config){
5883 this.el = Roo.get(el);
5884 Roo.apply(this, config);
5886 this.store.on('beforeload', this.onBeforeLoad, this);
5887 this.store.on('load', this.onLoad, this);
5888 this.store.on('loadexception', this.onLoadException, this);
5889 this.removeMask = false;
5891 var um = this.el.getUpdateManager();
5892 um.showLoadIndicator = false; // disable the default indicator
5893 um.on('beforeupdate', this.onBeforeLoad, this);
5894 um.on('update', this.onLoad, this);
5895 um.on('failure', this.onLoad, this);
5896 this.removeMask = true;
5900 Roo.LoadMask.prototype = {
5902 * @cfg {Boolean} removeMask
5903 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5904 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5908 * The text to display in a centered loading message box (defaults to 'Loading...')
5912 * @cfg {String} msgCls
5913 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5915 msgCls : 'x-mask-loading',
5918 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5924 * Disables the mask to prevent it from being displayed
5926 disable : function(){
5927 this.disabled = true;
5931 * Enables the mask so that it can be displayed
5933 enable : function(){
5934 this.disabled = false;
5937 onLoadException : function()
5941 if (typeof(arguments[3]) != 'undefined') {
5942 Roo.MessageBox.alert("Error loading",arguments[3]);
5946 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5947 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5954 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5959 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5963 onBeforeLoad : function(){
5965 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5970 destroy : function(){
5972 this.store.un('beforeload', this.onBeforeLoad, this);
5973 this.store.un('load', this.onLoad, this);
5974 this.store.un('loadexception', this.onLoadException, this);
5976 var um = this.el.getUpdateManager();
5977 um.un('beforeupdate', this.onBeforeLoad, this);
5978 um.un('update', this.onLoad, this);
5979 um.un('failure', this.onLoad, this);
5990 * @class Roo.bootstrap.Table
5991 * @extends Roo.bootstrap.Component
5992 * Bootstrap Table class
5993 * @cfg {String} cls table class
5994 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5995 * @cfg {String} bgcolor Specifies the background color for a table
5996 * @cfg {Number} border Specifies whether the table cells should have borders or not
5997 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5998 * @cfg {Number} cellspacing Specifies the space between cells
5999 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6000 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6001 * @cfg {String} sortable Specifies that the table should be sortable
6002 * @cfg {String} summary Specifies a summary of the content of a table
6003 * @cfg {Number} width Specifies the width of a table
6004 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6006 * @cfg {boolean} striped Should the rows be alternative striped
6007 * @cfg {boolean} bordered Add borders to the table
6008 * @cfg {boolean} hover Add hover highlighting
6009 * @cfg {boolean} condensed Format condensed
6010 * @cfg {boolean} responsive Format condensed
6011 * @cfg {Boolean} loadMask (true|false) default false
6012 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6013 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6014 * @cfg {Boolean} rowSelection (true|false) default false
6015 * @cfg {Boolean} cellSelection (true|false) default false
6016 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6017 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6018 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6019 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6023 * Create a new Table
6024 * @param {Object} config The config object
6027 Roo.bootstrap.Table = function(config){
6028 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6033 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6034 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6035 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6036 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6038 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6040 this.sm.grid = this;
6041 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6042 this.sm = this.selModel;
6043 this.sm.xmodule = this.xmodule || false;
6046 if (this.cm && typeof(this.cm.config) == 'undefined') {
6047 this.colModel = new Roo.grid.ColumnModel(this.cm);
6048 this.cm = this.colModel;
6049 this.cm.xmodule = this.xmodule || false;
6052 this.store= Roo.factory(this.store, Roo.data);
6053 this.ds = this.store;
6054 this.ds.xmodule = this.xmodule || false;
6057 if (this.footer && this.store) {
6058 this.footer.dataSource = this.ds;
6059 this.footer = Roo.factory(this.footer);
6066 * Fires when a cell is clicked
6067 * @param {Roo.bootstrap.Table} this
6068 * @param {Roo.Element} el
6069 * @param {Number} rowIndex
6070 * @param {Number} columnIndex
6071 * @param {Roo.EventObject} e
6075 * @event celldblclick
6076 * Fires when a cell is double clicked
6077 * @param {Roo.bootstrap.Table} this
6078 * @param {Roo.Element} el
6079 * @param {Number} rowIndex
6080 * @param {Number} columnIndex
6081 * @param {Roo.EventObject} e
6083 "celldblclick" : true,
6086 * Fires when a row is clicked
6087 * @param {Roo.bootstrap.Table} this
6088 * @param {Roo.Element} el
6089 * @param {Number} rowIndex
6090 * @param {Roo.EventObject} e
6094 * @event rowdblclick
6095 * Fires when a row is double clicked
6096 * @param {Roo.bootstrap.Table} this
6097 * @param {Roo.Element} el
6098 * @param {Number} rowIndex
6099 * @param {Roo.EventObject} e
6101 "rowdblclick" : true,
6104 * Fires when a mouseover occur
6105 * @param {Roo.bootstrap.Table} this
6106 * @param {Roo.Element} el
6107 * @param {Number} rowIndex
6108 * @param {Number} columnIndex
6109 * @param {Roo.EventObject} e
6114 * Fires when a mouseout occur
6115 * @param {Roo.bootstrap.Table} this
6116 * @param {Roo.Element} el
6117 * @param {Number} rowIndex
6118 * @param {Number} columnIndex
6119 * @param {Roo.EventObject} e
6124 * Fires when a row is rendered, so you can change add a style to it.
6125 * @param {Roo.bootstrap.Table} this
6126 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6130 * @event rowsrendered
6131 * Fires when all the rows have been rendered
6132 * @param {Roo.bootstrap.Table} this
6134 'rowsrendered' : true,
6136 * @event contextmenu
6137 * The raw contextmenu event for the entire grid.
6138 * @param {Roo.EventObject} e
6140 "contextmenu" : true,
6142 * @event rowcontextmenu
6143 * Fires when a row is right clicked
6144 * @param {Roo.bootstrap.Table} this
6145 * @param {Number} rowIndex
6146 * @param {Roo.EventObject} e
6148 "rowcontextmenu" : true,
6150 * @event cellcontextmenu
6151 * Fires when a cell is right clicked
6152 * @param {Roo.bootstrap.Table} this
6153 * @param {Number} rowIndex
6154 * @param {Number} cellIndex
6155 * @param {Roo.EventObject} e
6157 "cellcontextmenu" : true,
6159 * @event headercontextmenu
6160 * Fires when a header is right clicked
6161 * @param {Roo.bootstrap.Table} this
6162 * @param {Number} columnIndex
6163 * @param {Roo.EventObject} e
6165 "headercontextmenu" : true
6169 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6195 rowSelection : false,
6196 cellSelection : false,
6199 // Roo.Element - the tbody
6201 // Roo.Element - thead element
6204 container: false, // used by gridpanel...
6210 auto_hide_footer : false,
6212 getAutoCreate : function()
6214 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6221 if (this.scrollBody) {
6222 cfg.cls += ' table-body-fixed';
6225 cfg.cls += ' table-striped';
6229 cfg.cls += ' table-hover';
6231 if (this.bordered) {
6232 cfg.cls += ' table-bordered';
6234 if (this.condensed) {
6235 cfg.cls += ' table-condensed';
6237 if (this.responsive) {
6238 cfg.cls += ' table-responsive';
6242 cfg.cls+= ' ' +this.cls;
6245 // this lot should be simplifed...
6258 ].forEach(function(k) {
6266 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6269 if(this.store || this.cm){
6270 if(this.headerShow){
6271 cfg.cn.push(this.renderHeader());
6274 cfg.cn.push(this.renderBody());
6276 if(this.footerShow){
6277 cfg.cn.push(this.renderFooter());
6279 // where does this come from?
6280 //cfg.cls+= ' TableGrid';
6283 return { cn : [ cfg ] };
6286 initEvents : function()
6288 if(!this.store || !this.cm){
6291 if (this.selModel) {
6292 this.selModel.initEvents();
6296 //Roo.log('initEvents with ds!!!!');
6298 this.mainBody = this.el.select('tbody', true).first();
6299 this.mainHead = this.el.select('thead', true).first();
6300 this.mainFoot = this.el.select('tfoot', true).first();
6306 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6307 e.on('click', _this.sort, _this);
6310 this.mainBody.on("click", this.onClick, this);
6311 this.mainBody.on("dblclick", this.onDblClick, this);
6313 // why is this done????? = it breaks dialogs??
6314 //this.parent().el.setStyle('position', 'relative');
6318 this.footer.parentId = this.id;
6319 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6322 this.el.select('tfoot tr td').first().addClass('hide');
6327 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6330 this.store.on('load', this.onLoad, this);
6331 this.store.on('beforeload', this.onBeforeLoad, this);
6332 this.store.on('update', this.onUpdate, this);
6333 this.store.on('add', this.onAdd, this);
6334 this.store.on("clear", this.clear, this);
6336 this.el.on("contextmenu", this.onContextMenu, this);
6338 this.mainBody.on('scroll', this.onBodyScroll, this);
6340 this.cm.on("headerchange", this.onHeaderChange, this);
6342 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6346 onContextMenu : function(e, t)
6348 this.processEvent("contextmenu", e);
6351 processEvent : function(name, e)
6353 if (name != 'touchstart' ) {
6354 this.fireEvent(name, e);
6357 var t = e.getTarget();
6359 var cell = Roo.get(t);
6365 if(cell.findParent('tfoot', false, true)){
6369 if(cell.findParent('thead', false, true)){
6371 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6372 cell = Roo.get(t).findParent('th', false, true);
6374 Roo.log("failed to find th in thead?");
6375 Roo.log(e.getTarget());
6380 var cellIndex = cell.dom.cellIndex;
6382 var ename = name == 'touchstart' ? 'click' : name;
6383 this.fireEvent("header" + ename, this, cellIndex, e);
6388 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6389 cell = Roo.get(t).findParent('td', false, true);
6391 Roo.log("failed to find th in tbody?");
6392 Roo.log(e.getTarget());
6397 var row = cell.findParent('tr', false, true);
6398 var cellIndex = cell.dom.cellIndex;
6399 var rowIndex = row.dom.rowIndex - 1;
6403 this.fireEvent("row" + name, this, rowIndex, e);
6407 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6413 onMouseover : function(e, el)
6415 var cell = Roo.get(el);
6421 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6422 cell = cell.findParent('td', false, true);
6425 var row = cell.findParent('tr', false, true);
6426 var cellIndex = cell.dom.cellIndex;
6427 var rowIndex = row.dom.rowIndex - 1; // start from 0
6429 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6433 onMouseout : function(e, el)
6435 var cell = Roo.get(el);
6441 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6442 cell = cell.findParent('td', false, true);
6445 var row = cell.findParent('tr', false, true);
6446 var cellIndex = cell.dom.cellIndex;
6447 var rowIndex = row.dom.rowIndex - 1; // start from 0
6449 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6453 onClick : function(e, el)
6455 var cell = Roo.get(el);
6457 if(!cell || (!this.cellSelection && !this.rowSelection)){
6461 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6462 cell = cell.findParent('td', false, true);
6465 if(!cell || typeof(cell) == 'undefined'){
6469 var row = cell.findParent('tr', false, true);
6471 if(!row || typeof(row) == 'undefined'){
6475 var cellIndex = cell.dom.cellIndex;
6476 var rowIndex = this.getRowIndex(row);
6478 // why??? - should these not be based on SelectionModel?
6479 if(this.cellSelection){
6480 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6483 if(this.rowSelection){
6484 this.fireEvent('rowclick', this, row, rowIndex, e);
6490 onDblClick : function(e,el)
6492 var cell = Roo.get(el);
6494 if(!cell || (!this.cellSelection && !this.rowSelection)){
6498 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6499 cell = cell.findParent('td', false, true);
6502 if(!cell || typeof(cell) == 'undefined'){
6506 var row = cell.findParent('tr', false, true);
6508 if(!row || typeof(row) == 'undefined'){
6512 var cellIndex = cell.dom.cellIndex;
6513 var rowIndex = this.getRowIndex(row);
6515 if(this.cellSelection){
6516 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6519 if(this.rowSelection){
6520 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6524 sort : function(e,el)
6526 var col = Roo.get(el);
6528 if(!col.hasClass('sortable')){
6532 var sort = col.attr('sort');
6535 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6539 this.store.sortInfo = {field : sort, direction : dir};
6542 Roo.log("calling footer first");
6543 this.footer.onClick('first');
6546 this.store.load({ params : { start : 0 } });
6550 renderHeader : function()
6558 this.totalWidth = 0;
6560 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6562 var config = cm.config[i];
6566 cls : 'x-hcol-' + i,
6568 html: cm.getColumnHeader(i)
6573 if(typeof(config.sortable) != 'undefined' && config.sortable){
6575 c.html = '<i class="glyphicon"></i>' + c.html;
6578 if(typeof(config.lgHeader) != 'undefined'){
6579 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6582 if(typeof(config.mdHeader) != 'undefined'){
6583 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6586 if(typeof(config.smHeader) != 'undefined'){
6587 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6590 if(typeof(config.xsHeader) != 'undefined'){
6591 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6598 if(typeof(config.tooltip) != 'undefined'){
6599 c.tooltip = config.tooltip;
6602 if(typeof(config.colspan) != 'undefined'){
6603 c.colspan = config.colspan;
6606 if(typeof(config.hidden) != 'undefined' && config.hidden){
6607 c.style += ' display:none;';
6610 if(typeof(config.dataIndex) != 'undefined'){
6611 c.sort = config.dataIndex;
6616 if(typeof(config.align) != 'undefined' && config.align.length){
6617 c.style += ' text-align:' + config.align + ';';
6620 if(typeof(config.width) != 'undefined'){
6621 c.style += ' width:' + config.width + 'px;';
6622 this.totalWidth += config.width;
6624 this.totalWidth += 100; // assume minimum of 100 per column?
6627 if(typeof(config.cls) != 'undefined'){
6628 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6631 ['xs','sm','md','lg'].map(function(size){
6633 if(typeof(config[size]) == 'undefined'){
6637 if (!config[size]) { // 0 = hidden
6638 c.cls += ' hidden-' + size;
6642 c.cls += ' col-' + size + '-' + config[size];
6652 renderBody : function()
6662 colspan : this.cm.getColumnCount()
6672 renderFooter : function()
6682 colspan : this.cm.getColumnCount()
6696 // Roo.log('ds onload');
6701 var ds = this.store;
6703 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6704 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6705 if (_this.store.sortInfo) {
6707 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6708 e.select('i', true).addClass(['glyphicon-arrow-up']);
6711 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6712 e.select('i', true).addClass(['glyphicon-arrow-down']);
6717 var tbody = this.mainBody;
6719 if(ds.getCount() > 0){
6720 ds.data.each(function(d,rowIndex){
6721 var row = this.renderRow(cm, ds, rowIndex);
6723 tbody.createChild(row);
6727 if(row.cellObjects.length){
6728 Roo.each(row.cellObjects, function(r){
6729 _this.renderCellObject(r);
6736 var tfoot = this.el.select('tfoot', true).first();
6738 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6740 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6742 var total = this.ds.getTotalCount();
6744 if(this.footer.pageSize < total){
6745 this.mainFoot.show();
6749 Roo.each(this.el.select('tbody td', true).elements, function(e){
6750 e.on('mouseover', _this.onMouseover, _this);
6753 Roo.each(this.el.select('tbody td', true).elements, function(e){
6754 e.on('mouseout', _this.onMouseout, _this);
6756 this.fireEvent('rowsrendered', this);
6762 onUpdate : function(ds,record)
6764 this.refreshRow(record);
6768 onRemove : function(ds, record, index, isUpdate){
6769 if(isUpdate !== true){
6770 this.fireEvent("beforerowremoved", this, index, record);
6772 var bt = this.mainBody.dom;
6774 var rows = this.el.select('tbody > tr', true).elements;
6776 if(typeof(rows[index]) != 'undefined'){
6777 bt.removeChild(rows[index].dom);
6780 // if(bt.rows[index]){
6781 // bt.removeChild(bt.rows[index]);
6784 if(isUpdate !== true){
6785 //this.stripeRows(index);
6786 //this.syncRowHeights(index, index);
6788 this.fireEvent("rowremoved", this, index, record);
6792 onAdd : function(ds, records, rowIndex)
6794 //Roo.log('on Add called');
6795 // - note this does not handle multiple adding very well..
6796 var bt = this.mainBody.dom;
6797 for (var i =0 ; i < records.length;i++) {
6798 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6799 //Roo.log(records[i]);
6800 //Roo.log(this.store.getAt(rowIndex+i));
6801 this.insertRow(this.store, rowIndex + i, false);
6808 refreshRow : function(record){
6809 var ds = this.store, index;
6810 if(typeof record == 'number'){
6812 record = ds.getAt(index);
6814 index = ds.indexOf(record);
6816 this.insertRow(ds, index, true);
6818 this.onRemove(ds, record, index+1, true);
6820 //this.syncRowHeights(index, index);
6822 this.fireEvent("rowupdated", this, index, record);
6825 insertRow : function(dm, rowIndex, isUpdate){
6828 this.fireEvent("beforerowsinserted", this, rowIndex);
6830 //var s = this.getScrollState();
6831 var row = this.renderRow(this.cm, this.store, rowIndex);
6832 // insert before rowIndex..
6833 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6837 if(row.cellObjects.length){
6838 Roo.each(row.cellObjects, function(r){
6839 _this.renderCellObject(r);
6844 this.fireEvent("rowsinserted", this, rowIndex);
6845 //this.syncRowHeights(firstRow, lastRow);
6846 //this.stripeRows(firstRow);
6853 getRowDom : function(rowIndex)
6855 var rows = this.el.select('tbody > tr', true).elements;
6857 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6860 // returns the object tree for a tr..
6863 renderRow : function(cm, ds, rowIndex)
6865 var d = ds.getAt(rowIndex);
6869 cls : 'x-row-' + rowIndex,
6873 var cellObjects = [];
6875 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6876 var config = cm.config[i];
6878 var renderer = cm.getRenderer(i);
6882 if(typeof(renderer) !== 'undefined'){
6883 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6885 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6886 // and are rendered into the cells after the row is rendered - using the id for the element.
6888 if(typeof(value) === 'object'){
6898 rowIndex : rowIndex,
6903 this.fireEvent('rowclass', this, rowcfg);
6907 cls : rowcfg.rowClass + ' x-col-' + i,
6909 html: (typeof(value) === 'object') ? '' : value
6916 if(typeof(config.colspan) != 'undefined'){
6917 td.colspan = config.colspan;
6920 if(typeof(config.hidden) != 'undefined' && config.hidden){
6921 td.style += ' display:none;';
6924 if(typeof(config.align) != 'undefined' && config.align.length){
6925 td.style += ' text-align:' + config.align + ';';
6927 if(typeof(config.valign) != 'undefined' && config.valign.length){
6928 td.style += ' vertical-align:' + config.valign + ';';
6931 if(typeof(config.width) != 'undefined'){
6932 td.style += ' width:' + config.width + 'px;';
6935 if(typeof(config.cursor) != 'undefined'){
6936 td.style += ' cursor:' + config.cursor + ';';
6939 if(typeof(config.cls) != 'undefined'){
6940 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6943 ['xs','sm','md','lg'].map(function(size){
6945 if(typeof(config[size]) == 'undefined'){
6949 if (!config[size]) { // 0 = hidden
6950 td.cls += ' hidden-' + size;
6954 td.cls += ' col-' + size + '-' + config[size];
6962 row.cellObjects = cellObjects;
6970 onBeforeLoad : function()
6979 this.el.select('tbody', true).first().dom.innerHTML = '';
6982 * Show or hide a row.
6983 * @param {Number} rowIndex to show or hide
6984 * @param {Boolean} state hide
6986 setRowVisibility : function(rowIndex, state)
6988 var bt = this.mainBody.dom;
6990 var rows = this.el.select('tbody > tr', true).elements;
6992 if(typeof(rows[rowIndex]) == 'undefined'){
6995 rows[rowIndex].dom.style.display = state ? '' : 'none';
6999 getSelectionModel : function(){
7001 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7003 return this.selModel;
7006 * Render the Roo.bootstrap object from renderder
7008 renderCellObject : function(r)
7012 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7014 var t = r.cfg.render(r.container);
7017 Roo.each(r.cfg.cn, function(c){
7019 container: t.getChildContainer(),
7022 _this.renderCellObject(child);
7027 getRowIndex : function(row)
7031 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7042 * Returns the grid's underlying element = used by panel.Grid
7043 * @return {Element} The element
7045 getGridEl : function(){
7049 * Forces a resize - used by panel.Grid
7050 * @return {Element} The element
7052 autoSize : function()
7054 //var ctr = Roo.get(this.container.dom.parentElement);
7055 var ctr = Roo.get(this.el.dom);
7057 var thd = this.getGridEl().select('thead',true).first();
7058 var tbd = this.getGridEl().select('tbody', true).first();
7059 var tfd = this.getGridEl().select('tfoot', true).first();
7061 var cw = ctr.getWidth();
7065 tbd.setSize(ctr.getWidth(),
7066 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7068 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7071 cw = Math.max(cw, this.totalWidth);
7072 this.getGridEl().select('tr',true).setWidth(cw);
7073 // resize 'expandable coloumn?
7075 return; // we doe not have a view in this design..
7078 onBodyScroll: function()
7080 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7082 this.mainHead.setStyle({
7083 'position' : 'relative',
7084 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7090 var scrollHeight = this.mainBody.dom.scrollHeight;
7092 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7094 var height = this.mainBody.getHeight();
7096 if(scrollHeight - height == scrollTop) {
7098 var total = this.ds.getTotalCount();
7100 if(this.footer.cursor + this.footer.pageSize < total){
7102 this.footer.ds.load({
7104 start : this.footer.cursor + this.footer.pageSize,
7105 limit : this.footer.pageSize
7115 onHeaderChange : function()
7117 var header = this.renderHeader();
7118 var table = this.el.select('table', true).first();
7120 this.mainHead.remove();
7121 this.mainHead = table.createChild(header, this.mainBody, false);
7124 onHiddenChange : function(colModel, colIndex, hidden)
7126 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7127 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7129 this.CSS.updateRule(thSelector, "display", "");
7130 this.CSS.updateRule(tdSelector, "display", "");
7133 this.CSS.updateRule(thSelector, "display", "none");
7134 this.CSS.updateRule(tdSelector, "display", "none");
7137 this.onHeaderChange();
7141 setColumnWidth: function(col_index, width)
7143 // width = "md-2 xs-2..."
7144 if(!this.colModel.config[col_index]) {
7148 var w = width.split(" ");
7150 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7152 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7155 for(var j = 0; j < w.length; j++) {
7161 var size_cls = w[j].split("-");
7163 if(!Number.isInteger(size_cls[1] * 1)) {
7167 if(!this.colModel.config[col_index][size_cls[0]]) {
7171 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7175 h_row[0].classList.replace(
7176 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7177 "col-"+size_cls[0]+"-"+size_cls[1]
7180 for(var i = 0; i < rows.length; i++) {
7182 var size_cls = w[j].split("-");
7184 if(!Number.isInteger(size_cls[1] * 1)) {
7188 if(!this.colModel.config[col_index][size_cls[0]]) {
7192 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7196 rows[i].classList.replace(
7197 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7198 "col-"+size_cls[0]+"-"+size_cls[1]
7202 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7217 * @class Roo.bootstrap.TableCell
7218 * @extends Roo.bootstrap.Component
7219 * Bootstrap TableCell class
7220 * @cfg {String} html cell contain text
7221 * @cfg {String} cls cell class
7222 * @cfg {String} tag cell tag (td|th) default td
7223 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7224 * @cfg {String} align Aligns the content in a cell
7225 * @cfg {String} axis Categorizes cells
7226 * @cfg {String} bgcolor Specifies the background color of a cell
7227 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7228 * @cfg {Number} colspan Specifies the number of columns a cell should span
7229 * @cfg {String} headers Specifies one or more header cells a cell is related to
7230 * @cfg {Number} height Sets the height of a cell
7231 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7232 * @cfg {Number} rowspan Sets the number of rows a cell should span
7233 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7234 * @cfg {String} valign Vertical aligns the content in a cell
7235 * @cfg {Number} width Specifies the width of a cell
7238 * Create a new TableCell
7239 * @param {Object} config The config object
7242 Roo.bootstrap.TableCell = function(config){
7243 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7246 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7266 getAutoCreate : function(){
7267 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7287 cfg.align=this.align
7293 cfg.bgcolor=this.bgcolor
7296 cfg.charoff=this.charoff
7299 cfg.colspan=this.colspan
7302 cfg.headers=this.headers
7305 cfg.height=this.height
7308 cfg.nowrap=this.nowrap
7311 cfg.rowspan=this.rowspan
7314 cfg.scope=this.scope
7317 cfg.valign=this.valign
7320 cfg.width=this.width
7339 * @class Roo.bootstrap.TableRow
7340 * @extends Roo.bootstrap.Component
7341 * Bootstrap TableRow class
7342 * @cfg {String} cls row class
7343 * @cfg {String} align Aligns the content in a table row
7344 * @cfg {String} bgcolor Specifies a background color for a table row
7345 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7346 * @cfg {String} valign Vertical aligns the content in a table row
7349 * Create a new TableRow
7350 * @param {Object} config The config object
7353 Roo.bootstrap.TableRow = function(config){
7354 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7357 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7365 getAutoCreate : function(){
7366 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7376 cfg.align = this.align;
7379 cfg.bgcolor = this.bgcolor;
7382 cfg.charoff = this.charoff;
7385 cfg.valign = this.valign;
7403 * @class Roo.bootstrap.TableBody
7404 * @extends Roo.bootstrap.Component
7405 * Bootstrap TableBody class
7406 * @cfg {String} cls element class
7407 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7408 * @cfg {String} align Aligns the content inside the element
7409 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7410 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7413 * Create a new TableBody
7414 * @param {Object} config The config object
7417 Roo.bootstrap.TableBody = function(config){
7418 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7421 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7429 getAutoCreate : function(){
7430 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7444 cfg.align = this.align;
7447 cfg.charoff = this.charoff;
7450 cfg.valign = this.valign;
7457 // initEvents : function()
7464 // this.store = Roo.factory(this.store, Roo.data);
7465 // this.store.on('load', this.onLoad, this);
7467 // this.store.load();
7471 // onLoad: function ()
7473 // this.fireEvent('load', this);
7483 * Ext JS Library 1.1.1
7484 * Copyright(c) 2006-2007, Ext JS, LLC.
7486 * Originally Released Under LGPL - original licence link has changed is not relivant.
7489 * <script type="text/javascript">
7492 // as we use this in bootstrap.
7493 Roo.namespace('Roo.form');
7495 * @class Roo.form.Action
7496 * Internal Class used to handle form actions
7498 * @param {Roo.form.BasicForm} el The form element or its id
7499 * @param {Object} config Configuration options
7504 // define the action interface
7505 Roo.form.Action = function(form, options){
7507 this.options = options || {};
7510 * Client Validation Failed
7513 Roo.form.Action.CLIENT_INVALID = 'client';
7515 * Server Validation Failed
7518 Roo.form.Action.SERVER_INVALID = 'server';
7520 * Connect to Server Failed
7523 Roo.form.Action.CONNECT_FAILURE = 'connect';
7525 * Reading Data from Server Failed
7528 Roo.form.Action.LOAD_FAILURE = 'load';
7530 Roo.form.Action.prototype = {
7532 failureType : undefined,
7533 response : undefined,
7537 run : function(options){
7542 success : function(response){
7547 handleResponse : function(response){
7551 // default connection failure
7552 failure : function(response){
7554 this.response = response;
7555 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7556 this.form.afterAction(this, false);
7559 processResponse : function(response){
7560 this.response = response;
7561 if(!response.responseText){
7564 this.result = this.handleResponse(response);
7568 // utility functions used internally
7569 getUrl : function(appendParams){
7570 var url = this.options.url || this.form.url || this.form.el.dom.action;
7572 var p = this.getParams();
7574 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7580 getMethod : function(){
7581 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7584 getParams : function(){
7585 var bp = this.form.baseParams;
7586 var p = this.options.params;
7588 if(typeof p == "object"){
7589 p = Roo.urlEncode(Roo.applyIf(p, bp));
7590 }else if(typeof p == 'string' && bp){
7591 p += '&' + Roo.urlEncode(bp);
7594 p = Roo.urlEncode(bp);
7599 createCallback : function(){
7601 success: this.success,
7602 failure: this.failure,
7604 timeout: (this.form.timeout*1000),
7605 upload: this.form.fileUpload ? this.success : undefined
7610 Roo.form.Action.Submit = function(form, options){
7611 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7614 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7617 haveProgress : false,
7618 uploadComplete : false,
7620 // uploadProgress indicator.
7621 uploadProgress : function()
7623 if (!this.form.progressUrl) {
7627 if (!this.haveProgress) {
7628 Roo.MessageBox.progress("Uploading", "Uploading");
7630 if (this.uploadComplete) {
7631 Roo.MessageBox.hide();
7635 this.haveProgress = true;
7637 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7639 var c = new Roo.data.Connection();
7641 url : this.form.progressUrl,
7646 success : function(req){
7647 //console.log(data);
7651 rdata = Roo.decode(req.responseText)
7653 Roo.log("Invalid data from server..");
7657 if (!rdata || !rdata.success) {
7659 Roo.MessageBox.alert(Roo.encode(rdata));
7662 var data = rdata.data;
7664 if (this.uploadComplete) {
7665 Roo.MessageBox.hide();
7670 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7671 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7674 this.uploadProgress.defer(2000,this);
7677 failure: function(data) {
7678 Roo.log('progress url failed ');
7689 // run get Values on the form, so it syncs any secondary forms.
7690 this.form.getValues();
7692 var o = this.options;
7693 var method = this.getMethod();
7694 var isPost = method == 'POST';
7695 if(o.clientValidation === false || this.form.isValid()){
7697 if (this.form.progressUrl) {
7698 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7699 (new Date() * 1) + '' + Math.random());
7704 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7705 form:this.form.el.dom,
7706 url:this.getUrl(!isPost),
7708 params:isPost ? this.getParams() : null,
7709 isUpload: this.form.fileUpload
7712 this.uploadProgress();
7714 }else if (o.clientValidation !== false){ // client validation failed
7715 this.failureType = Roo.form.Action.CLIENT_INVALID;
7716 this.form.afterAction(this, false);
7720 success : function(response)
7722 this.uploadComplete= true;
7723 if (this.haveProgress) {
7724 Roo.MessageBox.hide();
7728 var result = this.processResponse(response);
7729 if(result === true || result.success){
7730 this.form.afterAction(this, true);
7734 this.form.markInvalid(result.errors);
7735 this.failureType = Roo.form.Action.SERVER_INVALID;
7737 this.form.afterAction(this, false);
7739 failure : function(response)
7741 this.uploadComplete= true;
7742 if (this.haveProgress) {
7743 Roo.MessageBox.hide();
7746 this.response = response;
7747 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7748 this.form.afterAction(this, false);
7751 handleResponse : function(response){
7752 if(this.form.errorReader){
7753 var rs = this.form.errorReader.read(response);
7756 for(var i = 0, len = rs.records.length; i < len; i++) {
7757 var r = rs.records[i];
7761 if(errors.length < 1){
7765 success : rs.success,
7771 ret = Roo.decode(response.responseText);
7775 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7785 Roo.form.Action.Load = function(form, options){
7786 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7787 this.reader = this.form.reader;
7790 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7795 Roo.Ajax.request(Roo.apply(
7796 this.createCallback(), {
7797 method:this.getMethod(),
7798 url:this.getUrl(false),
7799 params:this.getParams()
7803 success : function(response){
7805 var result = this.processResponse(response);
7806 if(result === true || !result.success || !result.data){
7807 this.failureType = Roo.form.Action.LOAD_FAILURE;
7808 this.form.afterAction(this, false);
7811 this.form.clearInvalid();
7812 this.form.setValues(result.data);
7813 this.form.afterAction(this, true);
7816 handleResponse : function(response){
7817 if(this.form.reader){
7818 var rs = this.form.reader.read(response);
7819 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7821 success : rs.success,
7825 return Roo.decode(response.responseText);
7829 Roo.form.Action.ACTION_TYPES = {
7830 'load' : Roo.form.Action.Load,
7831 'submit' : Roo.form.Action.Submit
7840 * @class Roo.bootstrap.Form
7841 * @extends Roo.bootstrap.Component
7842 * Bootstrap Form class
7843 * @cfg {String} method GET | POST (default POST)
7844 * @cfg {String} labelAlign top | left (default top)
7845 * @cfg {String} align left | right - for navbars
7846 * @cfg {Boolean} loadMask load mask when submit (default true)
7851 * @param {Object} config The config object
7855 Roo.bootstrap.Form = function(config){
7857 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7859 Roo.bootstrap.Form.popover.apply();
7863 * @event clientvalidation
7864 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7865 * @param {Form} this
7866 * @param {Boolean} valid true if the form has passed client-side validation
7868 clientvalidation: true,
7870 * @event beforeaction
7871 * Fires before any action is performed. Return false to cancel the action.
7872 * @param {Form} this
7873 * @param {Action} action The action to be performed
7877 * @event actionfailed
7878 * Fires when an action fails.
7879 * @param {Form} this
7880 * @param {Action} action The action that failed
7882 actionfailed : true,
7884 * @event actioncomplete
7885 * Fires when an action is completed.
7886 * @param {Form} this
7887 * @param {Action} action The action that completed
7889 actioncomplete : true
7893 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7896 * @cfg {String} method
7897 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7902 * The URL to use for form actions if one isn't supplied in the action options.
7905 * @cfg {Boolean} fileUpload
7906 * Set to true if this form is a file upload.
7910 * @cfg {Object} baseParams
7911 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7915 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7919 * @cfg {Sting} align (left|right) for navbar forms
7924 activeAction : null,
7927 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7928 * element by passing it or its id or mask the form itself by passing in true.
7931 waitMsgTarget : false,
7936 * @cfg {Boolean} errorMask (true|false) default false
7941 * @cfg {Number} maskOffset Default 100
7946 * @cfg {Boolean} maskBody
7950 getAutoCreate : function(){
7954 method : this.method || 'POST',
7955 id : this.id || Roo.id(),
7958 if (this.parent().xtype.match(/^Nav/)) {
7959 cfg.cls = 'navbar-form navbar-' + this.align;
7963 if (this.labelAlign == 'left' ) {
7964 cfg.cls += ' form-horizontal';
7970 initEvents : function()
7972 this.el.on('submit', this.onSubmit, this);
7973 // this was added as random key presses on the form where triggering form submit.
7974 this.el.on('keypress', function(e) {
7975 if (e.getCharCode() != 13) {
7978 // we might need to allow it for textareas.. and some other items.
7979 // check e.getTarget().
7981 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7985 Roo.log("keypress blocked");
7993 onSubmit : function(e){
7998 * Returns true if client-side validation on the form is successful.
8001 isValid : function(){
8002 var items = this.getItems();
8006 items.each(function(f){
8012 Roo.log('invalid field: ' + f.name);
8016 if(!target && f.el.isVisible(true)){
8022 if(this.errorMask && !valid){
8023 Roo.bootstrap.Form.popover.mask(this, target);
8030 * Returns true if any fields in this form have changed since their original load.
8033 isDirty : function(){
8035 var items = this.getItems();
8036 items.each(function(f){
8046 * Performs a predefined action (submit or load) or custom actions you define on this form.
8047 * @param {String} actionName The name of the action type
8048 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8049 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8050 * accept other config options):
8052 Property Type Description
8053 ---------------- --------------- ----------------------------------------------------------------------------------
8054 url String The url for the action (defaults to the form's url)
8055 method String The form method to use (defaults to the form's method, or POST if not defined)
8056 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8057 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8058 validate the form on the client (defaults to false)
8060 * @return {BasicForm} this
8062 doAction : function(action, options){
8063 if(typeof action == 'string'){
8064 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8066 if(this.fireEvent('beforeaction', this, action) !== false){
8067 this.beforeAction(action);
8068 action.run.defer(100, action);
8074 beforeAction : function(action){
8075 var o = action.options;
8080 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8082 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8085 // not really supported yet.. ??
8087 //if(this.waitMsgTarget === true){
8088 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8089 //}else if(this.waitMsgTarget){
8090 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8091 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8093 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8099 afterAction : function(action, success){
8100 this.activeAction = null;
8101 var o = action.options;
8106 Roo.get(document.body).unmask();
8112 //if(this.waitMsgTarget === true){
8113 // this.el.unmask();
8114 //}else if(this.waitMsgTarget){
8115 // this.waitMsgTarget.unmask();
8117 // Roo.MessageBox.updateProgress(1);
8118 // Roo.MessageBox.hide();
8125 Roo.callback(o.success, o.scope, [this, action]);
8126 this.fireEvent('actioncomplete', this, action);
8130 // failure condition..
8131 // we have a scenario where updates need confirming.
8132 // eg. if a locking scenario exists..
8133 // we look for { errors : { needs_confirm : true }} in the response.
8135 (typeof(action.result) != 'undefined') &&
8136 (typeof(action.result.errors) != 'undefined') &&
8137 (typeof(action.result.errors.needs_confirm) != 'undefined')
8140 Roo.log("not supported yet");
8143 Roo.MessageBox.confirm(
8144 "Change requires confirmation",
8145 action.result.errorMsg,
8150 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8160 Roo.callback(o.failure, o.scope, [this, action]);
8161 // show an error message if no failed handler is set..
8162 if (!this.hasListener('actionfailed')) {
8163 Roo.log("need to add dialog support");
8165 Roo.MessageBox.alert("Error",
8166 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8167 action.result.errorMsg :
8168 "Saving Failed, please check your entries or try again"
8173 this.fireEvent('actionfailed', this, action);
8178 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8179 * @param {String} id The value to search for
8182 findField : function(id){
8183 var items = this.getItems();
8184 var field = items.get(id);
8186 items.each(function(f){
8187 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8194 return field || null;
8197 * Mark fields in this form invalid in bulk.
8198 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8199 * @return {BasicForm} this
8201 markInvalid : function(errors){
8202 if(errors instanceof Array){
8203 for(var i = 0, len = errors.length; i < len; i++){
8204 var fieldError = errors[i];
8205 var f = this.findField(fieldError.id);
8207 f.markInvalid(fieldError.msg);
8213 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8214 field.markInvalid(errors[id]);
8218 //Roo.each(this.childForms || [], function (f) {
8219 // f.markInvalid(errors);
8226 * Set values for fields in this form in bulk.
8227 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8228 * @return {BasicForm} this
8230 setValues : function(values){
8231 if(values instanceof Array){ // array of objects
8232 for(var i = 0, len = values.length; i < len; i++){
8234 var f = this.findField(v.id);
8236 f.setValue(v.value);
8237 if(this.trackResetOnLoad){
8238 f.originalValue = f.getValue();
8242 }else{ // object hash
8245 if(typeof values[id] != 'function' && (field = this.findField(id))){
8247 if (field.setFromData &&
8249 field.displayField &&
8250 // combos' with local stores can
8251 // be queried via setValue()
8252 // to set their value..
8253 (field.store && !field.store.isLocal)
8257 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8258 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8259 field.setFromData(sd);
8261 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8263 field.setFromData(values);
8266 field.setValue(values[id]);
8270 if(this.trackResetOnLoad){
8271 field.originalValue = field.getValue();
8277 //Roo.each(this.childForms || [], function (f) {
8278 // f.setValues(values);
8285 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8286 * they are returned as an array.
8287 * @param {Boolean} asString
8290 getValues : function(asString){
8291 //if (this.childForms) {
8292 // copy values from the child forms
8293 // Roo.each(this.childForms, function (f) {
8294 // this.setValues(f.getValues());
8300 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8301 if(asString === true){
8304 return Roo.urlDecode(fs);
8308 * Returns the fields in this form as an object with key/value pairs.
8309 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8312 getFieldValues : function(with_hidden)
8314 var items = this.getItems();
8316 items.each(function(f){
8322 var v = f.getValue();
8324 if (f.inputType =='radio') {
8325 if (typeof(ret[f.getName()]) == 'undefined') {
8326 ret[f.getName()] = ''; // empty..
8329 if (!f.el.dom.checked) {
8337 if(f.xtype == 'MoneyField'){
8338 ret[f.currencyName] = f.getCurrency();
8341 // not sure if this supported any more..
8342 if ((typeof(v) == 'object') && f.getRawValue) {
8343 v = f.getRawValue() ; // dates..
8345 // combo boxes where name != hiddenName...
8346 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8347 ret[f.name] = f.getRawValue();
8349 ret[f.getName()] = v;
8356 * Clears all invalid messages in this form.
8357 * @return {BasicForm} this
8359 clearInvalid : function(){
8360 var items = this.getItems();
8362 items.each(function(f){
8371 * @return {BasicForm} this
8374 var items = this.getItems();
8375 items.each(function(f){
8379 Roo.each(this.childForms || [], function (f) {
8387 getItems : function()
8389 var r=new Roo.util.MixedCollection(false, function(o){
8390 return o.id || (o.id = Roo.id());
8392 var iter = function(el) {
8399 Roo.each(el.items,function(e) {
8408 hideFields : function(items)
8410 Roo.each(items, function(i){
8412 var f = this.findField(i);
8423 showFields : function(items)
8425 Roo.each(items, function(i){
8427 var f = this.findField(i);
8440 Roo.apply(Roo.bootstrap.Form, {
8467 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8468 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8469 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8470 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8473 this.maskEl.top.enableDisplayMode("block");
8474 this.maskEl.left.enableDisplayMode("block");
8475 this.maskEl.bottom.enableDisplayMode("block");
8476 this.maskEl.right.enableDisplayMode("block");
8478 this.toolTip = new Roo.bootstrap.Tooltip({
8479 cls : 'roo-form-error-popover',
8481 'left' : ['r-l', [-2,0], 'right'],
8482 'right' : ['l-r', [2,0], 'left'],
8483 'bottom' : ['tl-bl', [0,2], 'top'],
8484 'top' : [ 'bl-tl', [0,-2], 'bottom']
8488 this.toolTip.render(Roo.get(document.body));
8490 this.toolTip.el.enableDisplayMode("block");
8492 Roo.get(document.body).on('click', function(){
8496 Roo.get(document.body).on('touchstart', function(){
8500 this.isApplied = true
8503 mask : function(form, target)
8507 this.target = target;
8509 if(!this.form.errorMask || !target.el){
8513 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8515 Roo.log(scrollable);
8517 var ot = this.target.el.calcOffsetsTo(scrollable);
8519 var scrollTo = ot[1] - this.form.maskOffset;
8521 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8523 scrollable.scrollTo('top', scrollTo);
8525 var box = this.target.el.getBox();
8527 var zIndex = Roo.bootstrap.Modal.zIndex++;
8530 this.maskEl.top.setStyle('position', 'absolute');
8531 this.maskEl.top.setStyle('z-index', zIndex);
8532 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8533 this.maskEl.top.setLeft(0);
8534 this.maskEl.top.setTop(0);
8535 this.maskEl.top.show();
8537 this.maskEl.left.setStyle('position', 'absolute');
8538 this.maskEl.left.setStyle('z-index', zIndex);
8539 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8540 this.maskEl.left.setLeft(0);
8541 this.maskEl.left.setTop(box.y - this.padding);
8542 this.maskEl.left.show();
8544 this.maskEl.bottom.setStyle('position', 'absolute');
8545 this.maskEl.bottom.setStyle('z-index', zIndex);
8546 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8547 this.maskEl.bottom.setLeft(0);
8548 this.maskEl.bottom.setTop(box.bottom + this.padding);
8549 this.maskEl.bottom.show();
8551 this.maskEl.right.setStyle('position', 'absolute');
8552 this.maskEl.right.setStyle('z-index', zIndex);
8553 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8554 this.maskEl.right.setLeft(box.right + this.padding);
8555 this.maskEl.right.setTop(box.y - this.padding);
8556 this.maskEl.right.show();
8558 this.toolTip.bindEl = this.target.el;
8560 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8562 var tip = this.target.blankText;
8564 if(this.target.getValue() !== '' ) {
8566 if (this.target.invalidText.length) {
8567 tip = this.target.invalidText;
8568 } else if (this.target.regexText.length){
8569 tip = this.target.regexText;
8573 this.toolTip.show(tip);
8575 this.intervalID = window.setInterval(function() {
8576 Roo.bootstrap.Form.popover.unmask();
8579 window.onwheel = function(){ return false;};
8581 (function(){ this.isMasked = true; }).defer(500, this);
8587 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8591 this.maskEl.top.setStyle('position', 'absolute');
8592 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8593 this.maskEl.top.hide();
8595 this.maskEl.left.setStyle('position', 'absolute');
8596 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8597 this.maskEl.left.hide();
8599 this.maskEl.bottom.setStyle('position', 'absolute');
8600 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8601 this.maskEl.bottom.hide();
8603 this.maskEl.right.setStyle('position', 'absolute');
8604 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8605 this.maskEl.right.hide();
8607 this.toolTip.hide();
8609 this.toolTip.el.hide();
8611 window.onwheel = function(){ return true;};
8613 if(this.intervalID){
8614 window.clearInterval(this.intervalID);
8615 this.intervalID = false;
8618 this.isMasked = false;
8628 * Ext JS Library 1.1.1
8629 * Copyright(c) 2006-2007, Ext JS, LLC.
8631 * Originally Released Under LGPL - original licence link has changed is not relivant.
8634 * <script type="text/javascript">
8637 * @class Roo.form.VTypes
8638 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8641 Roo.form.VTypes = function(){
8642 // closure these in so they are only created once.
8643 var alpha = /^[a-zA-Z_]+$/;
8644 var alphanum = /^[a-zA-Z0-9_]+$/;
8645 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8646 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8648 // All these messages and functions are configurable
8651 * The function used to validate email addresses
8652 * @param {String} value The email address
8654 'email' : function(v){
8655 return email.test(v);
8658 * The error text to display when the email validation function returns false
8661 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8663 * The keystroke filter mask to be applied on email input
8666 'emailMask' : /[a-z0-9_\.\-@]/i,
8669 * The function used to validate URLs
8670 * @param {String} value The URL
8672 'url' : function(v){
8676 * The error text to display when the url validation function returns false
8679 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8682 * The function used to validate alpha values
8683 * @param {String} value The value
8685 'alpha' : function(v){
8686 return alpha.test(v);
8689 * The error text to display when the alpha validation function returns false
8692 'alphaText' : 'This field should only contain letters and _',
8694 * The keystroke filter mask to be applied on alpha input
8697 'alphaMask' : /[a-z_]/i,
8700 * The function used to validate alphanumeric values
8701 * @param {String} value The value
8703 'alphanum' : function(v){
8704 return alphanum.test(v);
8707 * The error text to display when the alphanumeric validation function returns false
8710 'alphanumText' : 'This field should only contain letters, numbers and _',
8712 * The keystroke filter mask to be applied on alphanumeric input
8715 'alphanumMask' : /[a-z0-9_]/i
8725 * @class Roo.bootstrap.Input
8726 * @extends Roo.bootstrap.Component
8727 * Bootstrap Input class
8728 * @cfg {Boolean} disabled is it disabled
8729 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8730 * @cfg {String} name name of the input
8731 * @cfg {string} fieldLabel - the label associated
8732 * @cfg {string} placeholder - placeholder to put in text.
8733 * @cfg {string} before - input group add on before
8734 * @cfg {string} after - input group add on after
8735 * @cfg {string} size - (lg|sm) or leave empty..
8736 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8737 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8738 * @cfg {Number} md colspan out of 12 for computer-sized screens
8739 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8740 * @cfg {string} value default value of the input
8741 * @cfg {Number} labelWidth set the width of label
8742 * @cfg {Number} labellg set the width of label (1-12)
8743 * @cfg {Number} labelmd set the width of label (1-12)
8744 * @cfg {Number} labelsm set the width of label (1-12)
8745 * @cfg {Number} labelxs set the width of label (1-12)
8746 * @cfg {String} labelAlign (top|left)
8747 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8748 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8749 * @cfg {String} indicatorpos (left|right) default left
8750 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8751 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8753 * @cfg {String} align (left|center|right) Default left
8754 * @cfg {Boolean} forceFeedback (true|false) Default false
8757 * Create a new Input
8758 * @param {Object} config The config object
8761 Roo.bootstrap.Input = function(config){
8763 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8768 * Fires when this field receives input focus.
8769 * @param {Roo.form.Field} this
8774 * Fires when this field loses input focus.
8775 * @param {Roo.form.Field} this
8780 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8781 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8782 * @param {Roo.form.Field} this
8783 * @param {Roo.EventObject} e The event object
8788 * Fires just before the field blurs if the field value has changed.
8789 * @param {Roo.form.Field} this
8790 * @param {Mixed} newValue The new value
8791 * @param {Mixed} oldValue The original value
8796 * Fires after the field has been marked as invalid.
8797 * @param {Roo.form.Field} this
8798 * @param {String} msg The validation message
8803 * Fires after the field has been validated with no errors.
8804 * @param {Roo.form.Field} this
8809 * Fires after the key up
8810 * @param {Roo.form.Field} this
8811 * @param {Roo.EventObject} e The event Object
8817 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8819 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8820 automatic validation (defaults to "keyup").
8822 validationEvent : "keyup",
8824 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8826 validateOnBlur : true,
8828 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8830 validationDelay : 250,
8832 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8834 focusClass : "x-form-focus", // not needed???
8838 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8840 invalidClass : "has-warning",
8843 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8845 validClass : "has-success",
8848 * @cfg {Boolean} hasFeedback (true|false) default true
8853 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8855 invalidFeedbackClass : "glyphicon-warning-sign",
8858 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8860 validFeedbackClass : "glyphicon-ok",
8863 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8865 selectOnFocus : false,
8868 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8872 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8877 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8879 disableKeyFilter : false,
8882 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8886 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8890 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8892 blankText : "Please complete this mandatory field",
8895 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8899 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8901 maxLength : Number.MAX_VALUE,
8903 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8905 minLengthText : "The minimum length for this field is {0}",
8907 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8909 maxLengthText : "The maximum length for this field is {0}",
8913 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8914 * If available, this function will be called only after the basic validators all return true, and will be passed the
8915 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8919 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8920 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8921 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8925 * @cfg {String} regexText -- Depricated - use Invalid Text
8930 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8936 autocomplete: false,
8955 formatedValue : false,
8956 forceFeedback : false,
8958 indicatorpos : 'left',
8968 parentLabelAlign : function()
8971 while (parent.parent()) {
8972 parent = parent.parent();
8973 if (typeof(parent.labelAlign) !='undefined') {
8974 return parent.labelAlign;
8981 getAutoCreate : function()
8983 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8989 if(this.inputType != 'hidden'){
8990 cfg.cls = 'form-group' //input-group
8996 type : this.inputType,
8998 cls : 'form-control',
8999 placeholder : this.placeholder || '',
9000 autocomplete : this.autocomplete || 'new-password'
9003 if(this.capture.length){
9004 input.capture = this.capture;
9007 if(this.accept.length){
9008 input.accept = this.accept + "/*";
9012 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9015 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9016 input.maxLength = this.maxLength;
9019 if (this.disabled) {
9020 input.disabled=true;
9023 if (this.readOnly) {
9024 input.readonly=true;
9028 input.name = this.name;
9032 input.cls += ' input-' + this.size;
9036 ['xs','sm','md','lg'].map(function(size){
9037 if (settings[size]) {
9038 cfg.cls += ' col-' + size + '-' + settings[size];
9042 var inputblock = input;
9046 cls: 'glyphicon form-control-feedback'
9049 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9052 cls : 'has-feedback',
9060 if (this.before || this.after) {
9063 cls : 'input-group',
9067 if (this.before && typeof(this.before) == 'string') {
9069 inputblock.cn.push({
9071 cls : 'roo-input-before input-group-addon',
9075 if (this.before && typeof(this.before) == 'object') {
9076 this.before = Roo.factory(this.before);
9078 inputblock.cn.push({
9080 cls : 'roo-input-before input-group-' +
9081 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9085 inputblock.cn.push(input);
9087 if (this.after && typeof(this.after) == 'string') {
9088 inputblock.cn.push({
9090 cls : 'roo-input-after input-group-addon',
9094 if (this.after && typeof(this.after) == 'object') {
9095 this.after = Roo.factory(this.after);
9097 inputblock.cn.push({
9099 cls : 'roo-input-after input-group-' +
9100 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9104 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9105 inputblock.cls += ' has-feedback';
9106 inputblock.cn.push(feedback);
9110 if (align ==='left' && this.fieldLabel.length) {
9112 cfg.cls += ' roo-form-group-label-left';
9117 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9118 tooltip : 'This field is required'
9123 cls : 'control-label',
9124 html : this.fieldLabel
9135 var labelCfg = cfg.cn[1];
9136 var contentCfg = cfg.cn[2];
9138 if(this.indicatorpos == 'right'){
9143 cls : 'control-label',
9147 html : this.fieldLabel
9151 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9152 tooltip : 'This field is required'
9165 labelCfg = cfg.cn[0];
9166 contentCfg = cfg.cn[1];
9170 if(this.labelWidth > 12){
9171 labelCfg.style = "width: " + this.labelWidth + 'px';
9174 if(this.labelWidth < 13 && this.labelmd == 0){
9175 this.labelmd = this.labelWidth;
9178 if(this.labellg > 0){
9179 labelCfg.cls += ' col-lg-' + this.labellg;
9180 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9183 if(this.labelmd > 0){
9184 labelCfg.cls += ' col-md-' + this.labelmd;
9185 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9188 if(this.labelsm > 0){
9189 labelCfg.cls += ' col-sm-' + this.labelsm;
9190 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9193 if(this.labelxs > 0){
9194 labelCfg.cls += ' col-xs-' + this.labelxs;
9195 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9199 } else if ( this.fieldLabel.length) {
9204 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9205 tooltip : 'This field is required'
9209 //cls : 'input-group-addon',
9210 html : this.fieldLabel
9218 if(this.indicatorpos == 'right'){
9223 //cls : 'input-group-addon',
9224 html : this.fieldLabel
9229 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9230 tooltip : 'This field is required'
9250 if (this.parentType === 'Navbar' && this.parent().bar) {
9251 cfg.cls += ' navbar-form';
9254 if (this.parentType === 'NavGroup') {
9255 cfg.cls += ' navbar-form';
9263 * return the real input element.
9265 inputEl: function ()
9267 return this.el.select('input.form-control',true).first();
9270 tooltipEl : function()
9272 return this.inputEl();
9275 indicatorEl : function()
9277 var indicator = this.el.select('i.roo-required-indicator',true).first();
9287 setDisabled : function(v)
9289 var i = this.inputEl().dom;
9291 i.removeAttribute('disabled');
9295 i.setAttribute('disabled','true');
9297 initEvents : function()
9300 this.inputEl().on("keydown" , this.fireKey, this);
9301 this.inputEl().on("focus", this.onFocus, this);
9302 this.inputEl().on("blur", this.onBlur, this);
9304 this.inputEl().relayEvent('keyup', this);
9306 this.indicator = this.indicatorEl();
9309 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9312 // reference to original value for reset
9313 this.originalValue = this.getValue();
9314 //Roo.form.TextField.superclass.initEvents.call(this);
9315 if(this.validationEvent == 'keyup'){
9316 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9317 this.inputEl().on('keyup', this.filterValidation, this);
9319 else if(this.validationEvent !== false){
9320 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9323 if(this.selectOnFocus){
9324 this.on("focus", this.preFocus, this);
9327 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9328 this.inputEl().on("keypress", this.filterKeys, this);
9330 this.inputEl().relayEvent('keypress', this);
9333 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9334 this.el.on("click", this.autoSize, this);
9337 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9338 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9341 if (typeof(this.before) == 'object') {
9342 this.before.render(this.el.select('.roo-input-before',true).first());
9344 if (typeof(this.after) == 'object') {
9345 this.after.render(this.el.select('.roo-input-after',true).first());
9348 this.inputEl().on('change', this.onChange, this);
9351 filterValidation : function(e){
9352 if(!e.isNavKeyPress()){
9353 this.validationTask.delay(this.validationDelay);
9357 * Validates the field value
9358 * @return {Boolean} True if the value is valid, else false
9360 validate : function(){
9361 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9362 if(this.disabled || this.validateValue(this.getRawValue())){
9373 * Validates a value according to the field's validation rules and marks the field as invalid
9374 * if the validation fails
9375 * @param {Mixed} value The value to validate
9376 * @return {Boolean} True if the value is valid, else false
9378 validateValue : function(value)
9380 if(this.getVisibilityEl().hasClass('hidden')){
9384 if(value.length < 1) { // if it's blank
9385 if(this.allowBlank){
9391 if(value.length < this.minLength){
9394 if(value.length > this.maxLength){
9398 var vt = Roo.form.VTypes;
9399 if(!vt[this.vtype](value, this)){
9403 if(typeof this.validator == "function"){
9404 var msg = this.validator(value);
9408 if (typeof(msg) == 'string') {
9409 this.invalidText = msg;
9413 if(this.regex && !this.regex.test(value)){
9421 fireKey : function(e){
9422 //Roo.log('field ' + e.getKey());
9423 if(e.isNavKeyPress()){
9424 this.fireEvent("specialkey", this, e);
9427 focus : function (selectText){
9429 this.inputEl().focus();
9430 if(selectText === true){
9431 this.inputEl().dom.select();
9437 onFocus : function(){
9438 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9439 // this.el.addClass(this.focusClass);
9442 this.hasFocus = true;
9443 this.startValue = this.getValue();
9444 this.fireEvent("focus", this);
9448 beforeBlur : Roo.emptyFn,
9452 onBlur : function(){
9454 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9455 //this.el.removeClass(this.focusClass);
9457 this.hasFocus = false;
9458 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9461 var v = this.getValue();
9462 if(String(v) !== String(this.startValue)){
9463 this.fireEvent('change', this, v, this.startValue);
9465 this.fireEvent("blur", this);
9468 onChange : function(e)
9470 var v = this.getValue();
9471 if(String(v) !== String(this.startValue)){
9472 this.fireEvent('change', this, v, this.startValue);
9478 * Resets the current field value to the originally loaded value and clears any validation messages
9481 this.setValue(this.originalValue);
9485 * Returns the name of the field
9486 * @return {Mixed} name The name field
9488 getName: function(){
9492 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9493 * @return {Mixed} value The field value
9495 getValue : function(){
9497 var v = this.inputEl().getValue();
9502 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9503 * @return {Mixed} value The field value
9505 getRawValue : function(){
9506 var v = this.inputEl().getValue();
9512 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9513 * @param {Mixed} value The value to set
9515 setRawValue : function(v){
9516 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9519 selectText : function(start, end){
9520 var v = this.getRawValue();
9522 start = start === undefined ? 0 : start;
9523 end = end === undefined ? v.length : end;
9524 var d = this.inputEl().dom;
9525 if(d.setSelectionRange){
9526 d.setSelectionRange(start, end);
9527 }else if(d.createTextRange){
9528 var range = d.createTextRange();
9529 range.moveStart("character", start);
9530 range.moveEnd("character", v.length-end);
9537 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9538 * @param {Mixed} value The value to set
9540 setValue : function(v){
9543 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9549 processValue : function(value){
9550 if(this.stripCharsRe){
9551 var newValue = value.replace(this.stripCharsRe, '');
9552 if(newValue !== value){
9553 this.setRawValue(newValue);
9560 preFocus : function(){
9562 if(this.selectOnFocus){
9563 this.inputEl().dom.select();
9566 filterKeys : function(e){
9568 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9571 var c = e.getCharCode(), cc = String.fromCharCode(c);
9572 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9575 if(!this.maskRe.test(cc)){
9580 * Clear any invalid styles/messages for this field
9582 clearInvalid : function(){
9584 if(!this.el || this.preventMark){ // not rendered
9589 this.el.removeClass(this.invalidClass);
9591 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9593 var feedback = this.el.select('.form-control-feedback', true).first();
9596 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9602 this.indicator.removeClass('visible');
9603 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9606 this.fireEvent('valid', this);
9610 * Mark this field as valid
9612 markValid : function()
9614 if(!this.el || this.preventMark){ // not rendered...
9618 this.el.removeClass([this.invalidClass, this.validClass]);
9620 var feedback = this.el.select('.form-control-feedback', true).first();
9623 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9627 this.indicator.removeClass('visible');
9628 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9635 if(this.allowBlank && !this.getRawValue().length){
9639 this.el.addClass(this.validClass);
9641 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9643 var feedback = this.el.select('.form-control-feedback', true).first();
9646 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9647 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9652 this.fireEvent('valid', this);
9656 * Mark this field as invalid
9657 * @param {String} msg The validation message
9659 markInvalid : function(msg)
9661 if(!this.el || this.preventMark){ // not rendered
9665 this.el.removeClass([this.invalidClass, this.validClass]);
9667 var feedback = this.el.select('.form-control-feedback', true).first();
9670 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9677 if(this.allowBlank && !this.getRawValue().length){
9682 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9683 this.indicator.addClass('visible');
9686 this.el.addClass(this.invalidClass);
9688 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9690 var feedback = this.el.select('.form-control-feedback', true).first();
9693 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9695 if(this.getValue().length || this.forceFeedback){
9696 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9703 this.fireEvent('invalid', this, msg);
9706 SafariOnKeyDown : function(event)
9708 // this is a workaround for a password hang bug on chrome/ webkit.
9709 if (this.inputEl().dom.type != 'password') {
9713 var isSelectAll = false;
9715 if(this.inputEl().dom.selectionEnd > 0){
9716 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9718 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9719 event.preventDefault();
9724 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9726 event.preventDefault();
9727 // this is very hacky as keydown always get's upper case.
9729 var cc = String.fromCharCode(event.getCharCode());
9730 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9734 adjustWidth : function(tag, w){
9735 tag = tag.toLowerCase();
9736 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9737 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9741 if(tag == 'textarea'){
9744 }else if(Roo.isOpera){
9748 if(tag == 'textarea'){
9756 setFieldLabel : function(v)
9763 var ar = this.el.select('label > span',true);
9765 if (ar.elements.length) {
9766 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9767 this.fieldLabel = v;
9771 var br = this.el.select('label',true);
9773 if(br.elements.length) {
9774 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9775 this.fieldLabel = v;
9779 Roo.log('Cannot Found any of label > span || label in input');
9783 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9784 this.fieldLabel = v;
9799 * @class Roo.bootstrap.TextArea
9800 * @extends Roo.bootstrap.Input
9801 * Bootstrap TextArea class
9802 * @cfg {Number} cols Specifies the visible width of a text area
9803 * @cfg {Number} rows Specifies the visible number of lines in a text area
9804 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9805 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9806 * @cfg {string} html text
9809 * Create a new TextArea
9810 * @param {Object} config The config object
9813 Roo.bootstrap.TextArea = function(config){
9814 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9818 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9828 getAutoCreate : function(){
9830 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9836 if(this.inputType != 'hidden'){
9837 cfg.cls = 'form-group' //input-group
9845 value : this.value || '',
9846 html: this.html || '',
9847 cls : 'form-control',
9848 placeholder : this.placeholder || ''
9852 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9853 input.maxLength = this.maxLength;
9857 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9861 input.cols = this.cols;
9864 if (this.readOnly) {
9865 input.readonly = true;
9869 input.name = this.name;
9873 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9877 ['xs','sm','md','lg'].map(function(size){
9878 if (settings[size]) {
9879 cfg.cls += ' col-' + size + '-' + settings[size];
9883 var inputblock = input;
9885 if(this.hasFeedback && !this.allowBlank){
9889 cls: 'glyphicon form-control-feedback'
9893 cls : 'has-feedback',
9902 if (this.before || this.after) {
9905 cls : 'input-group',
9909 inputblock.cn.push({
9911 cls : 'input-group-addon',
9916 inputblock.cn.push(input);
9918 if(this.hasFeedback && !this.allowBlank){
9919 inputblock.cls += ' has-feedback';
9920 inputblock.cn.push(feedback);
9924 inputblock.cn.push({
9926 cls : 'input-group-addon',
9933 if (align ==='left' && this.fieldLabel.length) {
9938 cls : 'control-label',
9939 html : this.fieldLabel
9950 if(this.labelWidth > 12){
9951 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9954 if(this.labelWidth < 13 && this.labelmd == 0){
9955 this.labelmd = this.labelWidth;
9958 if(this.labellg > 0){
9959 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9960 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9963 if(this.labelmd > 0){
9964 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9965 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9968 if(this.labelsm > 0){
9969 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9970 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9973 if(this.labelxs > 0){
9974 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9975 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9978 } else if ( this.fieldLabel.length) {
9983 //cls : 'input-group-addon',
9984 html : this.fieldLabel
10002 if (this.disabled) {
10003 input.disabled=true;
10010 * return the real textarea element.
10012 inputEl: function ()
10014 return this.el.select('textarea.form-control',true).first();
10018 * Clear any invalid styles/messages for this field
10020 clearInvalid : function()
10023 if(!this.el || this.preventMark){ // not rendered
10027 var label = this.el.select('label', true).first();
10028 var icon = this.el.select('i.fa-star', true).first();
10034 this.el.removeClass(this.invalidClass);
10036 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10038 var feedback = this.el.select('.form-control-feedback', true).first();
10041 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10046 this.fireEvent('valid', this);
10050 * Mark this field as valid
10052 markValid : function()
10054 if(!this.el || this.preventMark){ // not rendered
10058 this.el.removeClass([this.invalidClass, this.validClass]);
10060 var feedback = this.el.select('.form-control-feedback', true).first();
10063 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10066 if(this.disabled || this.allowBlank){
10070 var label = this.el.select('label', true).first();
10071 var icon = this.el.select('i.fa-star', true).first();
10077 this.el.addClass(this.validClass);
10079 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10081 var feedback = this.el.select('.form-control-feedback', true).first();
10084 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10085 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10090 this.fireEvent('valid', this);
10094 * Mark this field as invalid
10095 * @param {String} msg The validation message
10097 markInvalid : function(msg)
10099 if(!this.el || this.preventMark){ // not rendered
10103 this.el.removeClass([this.invalidClass, this.validClass]);
10105 var feedback = this.el.select('.form-control-feedback', true).first();
10108 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10111 if(this.disabled || this.allowBlank){
10115 var label = this.el.select('label', true).first();
10116 var icon = this.el.select('i.fa-star', true).first();
10118 if(!this.getValue().length && label && !icon){
10119 this.el.createChild({
10121 cls : 'text-danger fa fa-lg fa-star',
10122 tooltip : 'This field is required',
10123 style : 'margin-right:5px;'
10127 this.el.addClass(this.invalidClass);
10129 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10131 var feedback = this.el.select('.form-control-feedback', true).first();
10134 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10136 if(this.getValue().length || this.forceFeedback){
10137 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10144 this.fireEvent('invalid', this, msg);
10152 * trigger field - base class for combo..
10157 * @class Roo.bootstrap.TriggerField
10158 * @extends Roo.bootstrap.Input
10159 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10160 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10161 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10162 * for which you can provide a custom implementation. For example:
10164 var trigger = new Roo.bootstrap.TriggerField();
10165 trigger.onTriggerClick = myTriggerFn;
10166 trigger.applyTo('my-field');
10169 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10170 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10171 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10172 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10173 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10176 * Create a new TriggerField.
10177 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10178 * to the base TextField)
10180 Roo.bootstrap.TriggerField = function(config){
10181 this.mimicing = false;
10182 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10185 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10187 * @cfg {String} triggerClass A CSS class to apply to the trigger
10190 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10195 * @cfg {Boolean} removable (true|false) special filter default false
10199 /** @cfg {Boolean} grow @hide */
10200 /** @cfg {Number} growMin @hide */
10201 /** @cfg {Number} growMax @hide */
10207 autoSize: Roo.emptyFn,
10211 deferHeight : true,
10214 actionMode : 'wrap',
10219 getAutoCreate : function(){
10221 var align = this.labelAlign || this.parentLabelAlign();
10226 cls: 'form-group' //input-group
10233 type : this.inputType,
10234 cls : 'form-control',
10235 autocomplete: 'new-password',
10236 placeholder : this.placeholder || ''
10240 input.name = this.name;
10243 input.cls += ' input-' + this.size;
10246 if (this.disabled) {
10247 input.disabled=true;
10250 var inputblock = input;
10252 if(this.hasFeedback && !this.allowBlank){
10256 cls: 'glyphicon form-control-feedback'
10259 if(this.removable && !this.editable && !this.tickable){
10261 cls : 'has-feedback',
10267 cls : 'roo-combo-removable-btn close'
10274 cls : 'has-feedback',
10283 if(this.removable && !this.editable && !this.tickable){
10285 cls : 'roo-removable',
10291 cls : 'roo-combo-removable-btn close'
10298 if (this.before || this.after) {
10301 cls : 'input-group',
10305 inputblock.cn.push({
10307 cls : 'input-group-addon',
10312 inputblock.cn.push(input);
10314 if(this.hasFeedback && !this.allowBlank){
10315 inputblock.cls += ' has-feedback';
10316 inputblock.cn.push(feedback);
10320 inputblock.cn.push({
10322 cls : 'input-group-addon',
10335 cls: 'form-hidden-field'
10349 cls: 'form-hidden-field'
10353 cls: 'roo-select2-choices',
10357 cls: 'roo-select2-search-field',
10370 cls: 'roo-select2-container input-group',
10375 // cls: 'typeahead typeahead-long dropdown-menu',
10376 // style: 'display:none'
10381 if(!this.multiple && this.showToggleBtn){
10387 if (this.caret != false) {
10390 cls: 'fa fa-' + this.caret
10397 cls : 'input-group-addon btn dropdown-toggle',
10402 cls: 'combobox-clear',
10416 combobox.cls += ' roo-select2-container-multi';
10419 if (align ==='left' && this.fieldLabel.length) {
10421 cfg.cls += ' roo-form-group-label-left';
10426 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10427 tooltip : 'This field is required'
10432 cls : 'control-label',
10433 html : this.fieldLabel
10445 var labelCfg = cfg.cn[1];
10446 var contentCfg = cfg.cn[2];
10448 if(this.indicatorpos == 'right'){
10453 cls : 'control-label',
10457 html : this.fieldLabel
10461 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10462 tooltip : 'This field is required'
10475 labelCfg = cfg.cn[0];
10476 contentCfg = cfg.cn[1];
10479 if(this.labelWidth > 12){
10480 labelCfg.style = "width: " + this.labelWidth + 'px';
10483 if(this.labelWidth < 13 && this.labelmd == 0){
10484 this.labelmd = this.labelWidth;
10487 if(this.labellg > 0){
10488 labelCfg.cls += ' col-lg-' + this.labellg;
10489 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10492 if(this.labelmd > 0){
10493 labelCfg.cls += ' col-md-' + this.labelmd;
10494 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10497 if(this.labelsm > 0){
10498 labelCfg.cls += ' col-sm-' + this.labelsm;
10499 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10502 if(this.labelxs > 0){
10503 labelCfg.cls += ' col-xs-' + this.labelxs;
10504 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10507 } else if ( this.fieldLabel.length) {
10508 // Roo.log(" label");
10512 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10513 tooltip : 'This field is required'
10517 //cls : 'input-group-addon',
10518 html : this.fieldLabel
10526 if(this.indicatorpos == 'right'){
10534 html : this.fieldLabel
10538 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10539 tooltip : 'This field is required'
10552 // Roo.log(" no label && no align");
10559 ['xs','sm','md','lg'].map(function(size){
10560 if (settings[size]) {
10561 cfg.cls += ' col-' + size + '-' + settings[size];
10572 onResize : function(w, h){
10573 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10574 // if(typeof w == 'number'){
10575 // var x = w - this.trigger.getWidth();
10576 // this.inputEl().setWidth(this.adjustWidth('input', x));
10577 // this.trigger.setStyle('left', x+'px');
10582 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10585 getResizeEl : function(){
10586 return this.inputEl();
10590 getPositionEl : function(){
10591 return this.inputEl();
10595 alignErrorIcon : function(){
10596 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10600 initEvents : function(){
10604 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10605 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10606 if(!this.multiple && this.showToggleBtn){
10607 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10608 if(this.hideTrigger){
10609 this.trigger.setDisplayed(false);
10611 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10615 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10618 if(this.removable && !this.editable && !this.tickable){
10619 var close = this.closeTriggerEl();
10622 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10623 close.on('click', this.removeBtnClick, this, close);
10627 //this.trigger.addClassOnOver('x-form-trigger-over');
10628 //this.trigger.addClassOnClick('x-form-trigger-click');
10631 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10635 closeTriggerEl : function()
10637 var close = this.el.select('.roo-combo-removable-btn', true).first();
10638 return close ? close : false;
10641 removeBtnClick : function(e, h, el)
10643 e.preventDefault();
10645 if(this.fireEvent("remove", this) !== false){
10647 this.fireEvent("afterremove", this)
10651 createList : function()
10653 this.list = Roo.get(document.body).createChild({
10655 cls: 'typeahead typeahead-long dropdown-menu',
10656 style: 'display:none'
10659 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10664 initTrigger : function(){
10669 onDestroy : function(){
10671 this.trigger.removeAllListeners();
10672 // this.trigger.remove();
10675 // this.wrap.remove();
10677 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10681 onFocus : function(){
10682 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10684 if(!this.mimicing){
10685 this.wrap.addClass('x-trigger-wrap-focus');
10686 this.mimicing = true;
10687 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10688 if(this.monitorTab){
10689 this.el.on("keydown", this.checkTab, this);
10696 checkTab : function(e){
10697 if(e.getKey() == e.TAB){
10698 this.triggerBlur();
10703 onBlur : function(){
10708 mimicBlur : function(e, t){
10710 if(!this.wrap.contains(t) && this.validateBlur()){
10711 this.triggerBlur();
10717 triggerBlur : function(){
10718 this.mimicing = false;
10719 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10720 if(this.monitorTab){
10721 this.el.un("keydown", this.checkTab, this);
10723 //this.wrap.removeClass('x-trigger-wrap-focus');
10724 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10728 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10729 validateBlur : function(e, t){
10734 onDisable : function(){
10735 this.inputEl().dom.disabled = true;
10736 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10738 // this.wrap.addClass('x-item-disabled');
10743 onEnable : function(){
10744 this.inputEl().dom.disabled = false;
10745 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10747 // this.el.removeClass('x-item-disabled');
10752 onShow : function(){
10753 var ae = this.getActionEl();
10756 ae.dom.style.display = '';
10757 ae.dom.style.visibility = 'visible';
10763 onHide : function(){
10764 var ae = this.getActionEl();
10765 ae.dom.style.display = 'none';
10769 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10770 * by an implementing function.
10772 * @param {EventObject} e
10774 onTriggerClick : Roo.emptyFn
10778 * Ext JS Library 1.1.1
10779 * Copyright(c) 2006-2007, Ext JS, LLC.
10781 * Originally Released Under LGPL - original licence link has changed is not relivant.
10784 * <script type="text/javascript">
10789 * @class Roo.data.SortTypes
10791 * Defines the default sorting (casting?) comparison functions used when sorting data.
10793 Roo.data.SortTypes = {
10795 * Default sort that does nothing
10796 * @param {Mixed} s The value being converted
10797 * @return {Mixed} The comparison value
10799 none : function(s){
10804 * The regular expression used to strip tags
10808 stripTagsRE : /<\/?[^>]+>/gi,
10811 * Strips all HTML tags to sort on text only
10812 * @param {Mixed} s The value being converted
10813 * @return {String} The comparison value
10815 asText : function(s){
10816 return String(s).replace(this.stripTagsRE, "");
10820 * Strips all HTML tags to sort on text only - Case insensitive
10821 * @param {Mixed} s The value being converted
10822 * @return {String} The comparison value
10824 asUCText : function(s){
10825 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10829 * Case insensitive string
10830 * @param {Mixed} s The value being converted
10831 * @return {String} The comparison value
10833 asUCString : function(s) {
10834 return String(s).toUpperCase();
10839 * @param {Mixed} s The value being converted
10840 * @return {Number} The comparison value
10842 asDate : function(s) {
10846 if(s instanceof Date){
10847 return s.getTime();
10849 return Date.parse(String(s));
10854 * @param {Mixed} s The value being converted
10855 * @return {Float} The comparison value
10857 asFloat : function(s) {
10858 var val = parseFloat(String(s).replace(/,/g, ""));
10867 * @param {Mixed} s The value being converted
10868 * @return {Number} The comparison value
10870 asInt : function(s) {
10871 var val = parseInt(String(s).replace(/,/g, ""));
10879 * Ext JS Library 1.1.1
10880 * Copyright(c) 2006-2007, Ext JS, LLC.
10882 * Originally Released Under LGPL - original licence link has changed is not relivant.
10885 * <script type="text/javascript">
10889 * @class Roo.data.Record
10890 * Instances of this class encapsulate both record <em>definition</em> information, and record
10891 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10892 * to access Records cached in an {@link Roo.data.Store} object.<br>
10894 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10895 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10898 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10900 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10901 * {@link #create}. The parameters are the same.
10902 * @param {Array} data An associative Array of data values keyed by the field name.
10903 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10904 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10905 * not specified an integer id is generated.
10907 Roo.data.Record = function(data, id){
10908 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10913 * Generate a constructor for a specific record layout.
10914 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10915 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10916 * Each field definition object may contain the following properties: <ul>
10917 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
10918 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10919 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10920 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10921 * is being used, then this is a string containing the javascript expression to reference the data relative to
10922 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10923 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10924 * this may be omitted.</p></li>
10925 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10926 * <ul><li>auto (Default, implies no conversion)</li>
10931 * <li>date</li></ul></p></li>
10932 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10933 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10934 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10935 * by the Reader into an object that will be stored in the Record. It is passed the
10936 * following parameters:<ul>
10937 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10939 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10941 * <br>usage:<br><pre><code>
10942 var TopicRecord = Roo.data.Record.create(
10943 {name: 'title', mapping: 'topic_title'},
10944 {name: 'author', mapping: 'username'},
10945 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10946 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10947 {name: 'lastPoster', mapping: 'user2'},
10948 {name: 'excerpt', mapping: 'post_text'}
10951 var myNewRecord = new TopicRecord({
10952 title: 'Do my job please',
10955 lastPost: new Date(),
10956 lastPoster: 'Animal',
10957 excerpt: 'No way dude!'
10959 myStore.add(myNewRecord);
10964 Roo.data.Record.create = function(o){
10965 var f = function(){
10966 f.superclass.constructor.apply(this, arguments);
10968 Roo.extend(f, Roo.data.Record);
10969 var p = f.prototype;
10970 p.fields = new Roo.util.MixedCollection(false, function(field){
10973 for(var i = 0, len = o.length; i < len; i++){
10974 p.fields.add(new Roo.data.Field(o[i]));
10976 f.getField = function(name){
10977 return p.fields.get(name);
10982 Roo.data.Record.AUTO_ID = 1000;
10983 Roo.data.Record.EDIT = 'edit';
10984 Roo.data.Record.REJECT = 'reject';
10985 Roo.data.Record.COMMIT = 'commit';
10987 Roo.data.Record.prototype = {
10989 * Readonly flag - true if this record has been modified.
10998 join : function(store){
10999 this.store = store;
11003 * Set the named field to the specified value.
11004 * @param {String} name The name of the field to set.
11005 * @param {Object} value The value to set the field to.
11007 set : function(name, value){
11008 if(this.data[name] == value){
11012 if(!this.modified){
11013 this.modified = {};
11015 if(typeof this.modified[name] == 'undefined'){
11016 this.modified[name] = this.data[name];
11018 this.data[name] = value;
11019 if(!this.editing && this.store){
11020 this.store.afterEdit(this);
11025 * Get the value of the named field.
11026 * @param {String} name The name of the field to get the value of.
11027 * @return {Object} The value of the field.
11029 get : function(name){
11030 return this.data[name];
11034 beginEdit : function(){
11035 this.editing = true;
11036 this.modified = {};
11040 cancelEdit : function(){
11041 this.editing = false;
11042 delete this.modified;
11046 endEdit : function(){
11047 this.editing = false;
11048 if(this.dirty && this.store){
11049 this.store.afterEdit(this);
11054 * Usually called by the {@link Roo.data.Store} which owns the Record.
11055 * Rejects all changes made to the Record since either creation, or the last commit operation.
11056 * Modified fields are reverted to their original values.
11058 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11059 * of reject operations.
11061 reject : function(){
11062 var m = this.modified;
11064 if(typeof m[n] != "function"){
11065 this.data[n] = m[n];
11068 this.dirty = false;
11069 delete this.modified;
11070 this.editing = false;
11072 this.store.afterReject(this);
11077 * Usually called by the {@link Roo.data.Store} which owns the Record.
11078 * Commits all changes made to the Record since either creation, or the last commit operation.
11080 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11081 * of commit operations.
11083 commit : function(){
11084 this.dirty = false;
11085 delete this.modified;
11086 this.editing = false;
11088 this.store.afterCommit(this);
11093 hasError : function(){
11094 return this.error != null;
11098 clearError : function(){
11103 * Creates a copy of this record.
11104 * @param {String} id (optional) A new record id if you don't want to use this record's id
11107 copy : function(newId) {
11108 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11112 * Ext JS Library 1.1.1
11113 * Copyright(c) 2006-2007, Ext JS, LLC.
11115 * Originally Released Under LGPL - original licence link has changed is not relivant.
11118 * <script type="text/javascript">
11124 * @class Roo.data.Store
11125 * @extends Roo.util.Observable
11126 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11127 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11129 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
11130 * has no knowledge of the format of the data returned by the Proxy.<br>
11132 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11133 * instances from the data object. These records are cached and made available through accessor functions.
11135 * Creates a new Store.
11136 * @param {Object} config A config object containing the objects needed for the Store to access data,
11137 * and read the data into Records.
11139 Roo.data.Store = function(config){
11140 this.data = new Roo.util.MixedCollection(false);
11141 this.data.getKey = function(o){
11144 this.baseParams = {};
11146 this.paramNames = {
11151 "multisort" : "_multisort"
11154 if(config && config.data){
11155 this.inlineData = config.data;
11156 delete config.data;
11159 Roo.apply(this, config);
11161 if(this.reader){ // reader passed
11162 this.reader = Roo.factory(this.reader, Roo.data);
11163 this.reader.xmodule = this.xmodule || false;
11164 if(!this.recordType){
11165 this.recordType = this.reader.recordType;
11167 if(this.reader.onMetaChange){
11168 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11172 if(this.recordType){
11173 this.fields = this.recordType.prototype.fields;
11175 this.modified = [];
11179 * @event datachanged
11180 * Fires when the data cache has changed, and a widget which is using this Store
11181 * as a Record cache should refresh its view.
11182 * @param {Store} this
11184 datachanged : true,
11186 * @event metachange
11187 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11188 * @param {Store} this
11189 * @param {Object} meta The JSON metadata
11194 * Fires when Records have been added to the Store
11195 * @param {Store} this
11196 * @param {Roo.data.Record[]} records The array of Records added
11197 * @param {Number} index The index at which the record(s) were added
11202 * Fires when a Record has been removed from the Store
11203 * @param {Store} this
11204 * @param {Roo.data.Record} record The Record that was removed
11205 * @param {Number} index The index at which the record was removed
11210 * Fires when a Record has been updated
11211 * @param {Store} this
11212 * @param {Roo.data.Record} record The Record that was updated
11213 * @param {String} operation The update operation being performed. Value may be one of:
11215 Roo.data.Record.EDIT
11216 Roo.data.Record.REJECT
11217 Roo.data.Record.COMMIT
11223 * Fires when the data cache has been cleared.
11224 * @param {Store} this
11228 * @event beforeload
11229 * Fires before a request is made for a new data object. If the beforeload handler returns false
11230 * the load action will be canceled.
11231 * @param {Store} this
11232 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11236 * @event beforeloadadd
11237 * Fires after a new set of Records has been loaded.
11238 * @param {Store} this
11239 * @param {Roo.data.Record[]} records The Records that were loaded
11240 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11242 beforeloadadd : true,
11245 * Fires after a new set of Records has been loaded, before they are added to the store.
11246 * @param {Store} this
11247 * @param {Roo.data.Record[]} records The Records that were loaded
11248 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11249 * @params {Object} return from reader
11253 * @event loadexception
11254 * Fires if an exception occurs in the Proxy during loading.
11255 * Called with the signature of the Proxy's "loadexception" event.
11256 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11259 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11260 * @param {Object} load options
11261 * @param {Object} jsonData from your request (normally this contains the Exception)
11263 loadexception : true
11267 this.proxy = Roo.factory(this.proxy, Roo.data);
11268 this.proxy.xmodule = this.xmodule || false;
11269 this.relayEvents(this.proxy, ["loadexception"]);
11271 this.sortToggle = {};
11272 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11274 Roo.data.Store.superclass.constructor.call(this);
11276 if(this.inlineData){
11277 this.loadData(this.inlineData);
11278 delete this.inlineData;
11282 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11284 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11285 * without a remote query - used by combo/forms at present.
11289 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11292 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11295 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11296 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11299 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11300 * on any HTTP request
11303 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11306 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11310 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11311 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11313 remoteSort : false,
11316 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11317 * loaded or when a record is removed. (defaults to false).
11319 pruneModifiedRecords : false,
11322 lastOptions : null,
11325 * Add Records to the Store and fires the add event.
11326 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11328 add : function(records){
11329 records = [].concat(records);
11330 for(var i = 0, len = records.length; i < len; i++){
11331 records[i].join(this);
11333 var index = this.data.length;
11334 this.data.addAll(records);
11335 this.fireEvent("add", this, records, index);
11339 * Remove a Record from the Store and fires the remove event.
11340 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11342 remove : function(record){
11343 var index = this.data.indexOf(record);
11344 this.data.removeAt(index);
11346 if(this.pruneModifiedRecords){
11347 this.modified.remove(record);
11349 this.fireEvent("remove", this, record, index);
11353 * Remove all Records from the Store and fires the clear event.
11355 removeAll : function(){
11357 if(this.pruneModifiedRecords){
11358 this.modified = [];
11360 this.fireEvent("clear", this);
11364 * Inserts Records to the Store at the given index and fires the add event.
11365 * @param {Number} index The start index at which to insert the passed Records.
11366 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11368 insert : function(index, records){
11369 records = [].concat(records);
11370 for(var i = 0, len = records.length; i < len; i++){
11371 this.data.insert(index, records[i]);
11372 records[i].join(this);
11374 this.fireEvent("add", this, records, index);
11378 * Get the index within the cache of the passed Record.
11379 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11380 * @return {Number} The index of the passed Record. Returns -1 if not found.
11382 indexOf : function(record){
11383 return this.data.indexOf(record);
11387 * Get the index within the cache of the Record with the passed id.
11388 * @param {String} id The id of the Record to find.
11389 * @return {Number} The index of the Record. Returns -1 if not found.
11391 indexOfId : function(id){
11392 return this.data.indexOfKey(id);
11396 * Get the Record with the specified id.
11397 * @param {String} id The id of the Record to find.
11398 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11400 getById : function(id){
11401 return this.data.key(id);
11405 * Get the Record at the specified index.
11406 * @param {Number} index The index of the Record to find.
11407 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11409 getAt : function(index){
11410 return this.data.itemAt(index);
11414 * Returns a range of Records between specified indices.
11415 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11416 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11417 * @return {Roo.data.Record[]} An array of Records
11419 getRange : function(start, end){
11420 return this.data.getRange(start, end);
11424 storeOptions : function(o){
11425 o = Roo.apply({}, o);
11428 this.lastOptions = o;
11432 * Loads the Record cache from the configured Proxy using the configured Reader.
11434 * If using remote paging, then the first load call must specify the <em>start</em>
11435 * and <em>limit</em> properties in the options.params property to establish the initial
11436 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11438 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11439 * and this call will return before the new data has been loaded. Perform any post-processing
11440 * in a callback function, or in a "load" event handler.</strong>
11442 * @param {Object} options An object containing properties which control loading options:<ul>
11443 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11444 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11445 * passed the following arguments:<ul>
11446 * <li>r : Roo.data.Record[]</li>
11447 * <li>options: Options object from the load call</li>
11448 * <li>success: Boolean success indicator</li></ul></li>
11449 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11450 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11453 load : function(options){
11454 options = options || {};
11455 if(this.fireEvent("beforeload", this, options) !== false){
11456 this.storeOptions(options);
11457 var p = Roo.apply(options.params || {}, this.baseParams);
11458 // if meta was not loaded from remote source.. try requesting it.
11459 if (!this.reader.metaFromRemote) {
11460 p._requestMeta = 1;
11462 if(this.sortInfo && this.remoteSort){
11463 var pn = this.paramNames;
11464 p[pn["sort"]] = this.sortInfo.field;
11465 p[pn["dir"]] = this.sortInfo.direction;
11467 if (this.multiSort) {
11468 var pn = this.paramNames;
11469 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11472 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11477 * Reloads the Record cache from the configured Proxy using the configured Reader and
11478 * the options from the last load operation performed.
11479 * @param {Object} options (optional) An object containing properties which may override the options
11480 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11481 * the most recently used options are reused).
11483 reload : function(options){
11484 this.load(Roo.applyIf(options||{}, this.lastOptions));
11488 // Called as a callback by the Reader during a load operation.
11489 loadRecords : function(o, options, success){
11490 if(!o || success === false){
11491 if(success !== false){
11492 this.fireEvent("load", this, [], options, o);
11494 if(options.callback){
11495 options.callback.call(options.scope || this, [], options, false);
11499 // if data returned failure - throw an exception.
11500 if (o.success === false) {
11501 // show a message if no listener is registered.
11502 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11503 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11505 // loadmask wil be hooked into this..
11506 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11509 var r = o.records, t = o.totalRecords || r.length;
11511 this.fireEvent("beforeloadadd", this, r, options, o);
11513 if(!options || options.add !== true){
11514 if(this.pruneModifiedRecords){
11515 this.modified = [];
11517 for(var i = 0, len = r.length; i < len; i++){
11521 this.data = this.snapshot;
11522 delete this.snapshot;
11525 this.data.addAll(r);
11526 this.totalLength = t;
11528 this.fireEvent("datachanged", this);
11530 this.totalLength = Math.max(t, this.data.length+r.length);
11534 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11536 var e = new Roo.data.Record({});
11538 e.set(this.parent.displayField, this.parent.emptyTitle);
11539 e.set(this.parent.valueField, '');
11544 this.fireEvent("load", this, r, options, o);
11545 if(options.callback){
11546 options.callback.call(options.scope || this, r, options, true);
11552 * Loads data from a passed data block. A Reader which understands the format of the data
11553 * must have been configured in the constructor.
11554 * @param {Object} data The data block from which to read the Records. The format of the data expected
11555 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11556 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11558 loadData : function(o, append){
11559 var r = this.reader.readRecords(o);
11560 this.loadRecords(r, {add: append}, true);
11564 * Gets the number of cached records.
11566 * <em>If using paging, this may not be the total size of the dataset. If the data object
11567 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11568 * the data set size</em>
11570 getCount : function(){
11571 return this.data.length || 0;
11575 * Gets the total number of records in the dataset as returned by the server.
11577 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11578 * the dataset size</em>
11580 getTotalCount : function(){
11581 return this.totalLength || 0;
11585 * Returns the sort state of the Store as an object with two properties:
11587 field {String} The name of the field by which the Records are sorted
11588 direction {String} The sort order, "ASC" or "DESC"
11591 getSortState : function(){
11592 return this.sortInfo;
11596 applySort : function(){
11597 if(this.sortInfo && !this.remoteSort){
11598 var s = this.sortInfo, f = s.field;
11599 var st = this.fields.get(f).sortType;
11600 var fn = function(r1, r2){
11601 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11602 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11604 this.data.sort(s.direction, fn);
11605 if(this.snapshot && this.snapshot != this.data){
11606 this.snapshot.sort(s.direction, fn);
11612 * Sets the default sort column and order to be used by the next load operation.
11613 * @param {String} fieldName The name of the field to sort by.
11614 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11616 setDefaultSort : function(field, dir){
11617 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11621 * Sort the Records.
11622 * If remote sorting is used, the sort is performed on the server, and the cache is
11623 * reloaded. If local sorting is used, the cache is sorted internally.
11624 * @param {String} fieldName The name of the field to sort by.
11625 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11627 sort : function(fieldName, dir){
11628 var f = this.fields.get(fieldName);
11630 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11632 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11633 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11638 this.sortToggle[f.name] = dir;
11639 this.sortInfo = {field: f.name, direction: dir};
11640 if(!this.remoteSort){
11642 this.fireEvent("datachanged", this);
11644 this.load(this.lastOptions);
11649 * Calls the specified function for each of the Records in the cache.
11650 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11651 * Returning <em>false</em> aborts and exits the iteration.
11652 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11654 each : function(fn, scope){
11655 this.data.each(fn, scope);
11659 * Gets all records modified since the last commit. Modified records are persisted across load operations
11660 * (e.g., during paging).
11661 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11663 getModifiedRecords : function(){
11664 return this.modified;
11668 createFilterFn : function(property, value, anyMatch){
11669 if(!value.exec){ // not a regex
11670 value = String(value);
11671 if(value.length == 0){
11674 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11676 return function(r){
11677 return value.test(r.data[property]);
11682 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11683 * @param {String} property A field on your records
11684 * @param {Number} start The record index to start at (defaults to 0)
11685 * @param {Number} end The last record index to include (defaults to length - 1)
11686 * @return {Number} The sum
11688 sum : function(property, start, end){
11689 var rs = this.data.items, v = 0;
11690 start = start || 0;
11691 end = (end || end === 0) ? end : rs.length-1;
11693 for(var i = start; i <= end; i++){
11694 v += (rs[i].data[property] || 0);
11700 * Filter the records by a specified property.
11701 * @param {String} field A field on your records
11702 * @param {String/RegExp} value Either a string that the field
11703 * should start with or a RegExp to test against the field
11704 * @param {Boolean} anyMatch True to match any part not just the beginning
11706 filter : function(property, value, anyMatch){
11707 var fn = this.createFilterFn(property, value, anyMatch);
11708 return fn ? this.filterBy(fn) : this.clearFilter();
11712 * Filter by a function. The specified function will be called with each
11713 * record in this data source. If the function returns true the record is included,
11714 * otherwise it is filtered.
11715 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11716 * @param {Object} scope (optional) The scope of the function (defaults to this)
11718 filterBy : function(fn, scope){
11719 this.snapshot = this.snapshot || this.data;
11720 this.data = this.queryBy(fn, scope||this);
11721 this.fireEvent("datachanged", this);
11725 * Query the records by a specified property.
11726 * @param {String} field A field on your records
11727 * @param {String/RegExp} value Either a string that the field
11728 * should start with or a RegExp to test against the field
11729 * @param {Boolean} anyMatch True to match any part not just the beginning
11730 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11732 query : function(property, value, anyMatch){
11733 var fn = this.createFilterFn(property, value, anyMatch);
11734 return fn ? this.queryBy(fn) : this.data.clone();
11738 * Query by a function. The specified function will be called with each
11739 * record in this data source. If the function returns true the record is included
11741 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11742 * @param {Object} scope (optional) The scope of the function (defaults to this)
11743 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11745 queryBy : function(fn, scope){
11746 var data = this.snapshot || this.data;
11747 return data.filterBy(fn, scope||this);
11751 * Collects unique values for a particular dataIndex from this store.
11752 * @param {String} dataIndex The property to collect
11753 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11754 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11755 * @return {Array} An array of the unique values
11757 collect : function(dataIndex, allowNull, bypassFilter){
11758 var d = (bypassFilter === true && this.snapshot) ?
11759 this.snapshot.items : this.data.items;
11760 var v, sv, r = [], l = {};
11761 for(var i = 0, len = d.length; i < len; i++){
11762 v = d[i].data[dataIndex];
11764 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11773 * Revert to a view of the Record cache with no filtering applied.
11774 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11776 clearFilter : function(suppressEvent){
11777 if(this.snapshot && this.snapshot != this.data){
11778 this.data = this.snapshot;
11779 delete this.snapshot;
11780 if(suppressEvent !== true){
11781 this.fireEvent("datachanged", this);
11787 afterEdit : function(record){
11788 if(this.modified.indexOf(record) == -1){
11789 this.modified.push(record);
11791 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11795 afterReject : function(record){
11796 this.modified.remove(record);
11797 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11801 afterCommit : function(record){
11802 this.modified.remove(record);
11803 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11807 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11808 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11810 commitChanges : function(){
11811 var m = this.modified.slice(0);
11812 this.modified = [];
11813 for(var i = 0, len = m.length; i < len; i++){
11819 * Cancel outstanding changes on all changed records.
11821 rejectChanges : function(){
11822 var m = this.modified.slice(0);
11823 this.modified = [];
11824 for(var i = 0, len = m.length; i < len; i++){
11829 onMetaChange : function(meta, rtype, o){
11830 this.recordType = rtype;
11831 this.fields = rtype.prototype.fields;
11832 delete this.snapshot;
11833 this.sortInfo = meta.sortInfo || this.sortInfo;
11834 this.modified = [];
11835 this.fireEvent('metachange', this, this.reader.meta);
11838 moveIndex : function(data, type)
11840 var index = this.indexOf(data);
11842 var newIndex = index + type;
11846 this.insert(newIndex, data);
11851 * Ext JS Library 1.1.1
11852 * Copyright(c) 2006-2007, Ext JS, LLC.
11854 * Originally Released Under LGPL - original licence link has changed is not relivant.
11857 * <script type="text/javascript">
11861 * @class Roo.data.SimpleStore
11862 * @extends Roo.data.Store
11863 * Small helper class to make creating Stores from Array data easier.
11864 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11865 * @cfg {Array} fields An array of field definition objects, or field name strings.
11866 * @cfg {Array} data The multi-dimensional array of data
11868 * @param {Object} config
11870 Roo.data.SimpleStore = function(config){
11871 Roo.data.SimpleStore.superclass.constructor.call(this, {
11873 reader: new Roo.data.ArrayReader({
11876 Roo.data.Record.create(config.fields)
11878 proxy : new Roo.data.MemoryProxy(config.data)
11882 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11884 * Ext JS Library 1.1.1
11885 * Copyright(c) 2006-2007, Ext JS, LLC.
11887 * Originally Released Under LGPL - original licence link has changed is not relivant.
11890 * <script type="text/javascript">
11895 * @extends Roo.data.Store
11896 * @class Roo.data.JsonStore
11897 * Small helper class to make creating Stores for JSON data easier. <br/>
11899 var store = new Roo.data.JsonStore({
11900 url: 'get-images.php',
11902 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11905 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11906 * JsonReader and HttpProxy (unless inline data is provided).</b>
11907 * @cfg {Array} fields An array of field definition objects, or field name strings.
11909 * @param {Object} config
11911 Roo.data.JsonStore = function(c){
11912 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11913 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11914 reader: new Roo.data.JsonReader(c, c.fields)
11917 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11919 * Ext JS Library 1.1.1
11920 * Copyright(c) 2006-2007, Ext JS, LLC.
11922 * Originally Released Under LGPL - original licence link has changed is not relivant.
11925 * <script type="text/javascript">
11929 Roo.data.Field = function(config){
11930 if(typeof config == "string"){
11931 config = {name: config};
11933 Roo.apply(this, config);
11936 this.type = "auto";
11939 var st = Roo.data.SortTypes;
11940 // named sortTypes are supported, here we look them up
11941 if(typeof this.sortType == "string"){
11942 this.sortType = st[this.sortType];
11945 // set default sortType for strings and dates
11946 if(!this.sortType){
11949 this.sortType = st.asUCString;
11952 this.sortType = st.asDate;
11955 this.sortType = st.none;
11960 var stripRe = /[\$,%]/g;
11962 // prebuilt conversion function for this field, instead of
11963 // switching every time we're reading a value
11965 var cv, dateFormat = this.dateFormat;
11970 cv = function(v){ return v; };
11973 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11977 return v !== undefined && v !== null && v !== '' ?
11978 parseInt(String(v).replace(stripRe, ""), 10) : '';
11983 return v !== undefined && v !== null && v !== '' ?
11984 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11989 cv = function(v){ return v === true || v === "true" || v == 1; };
11996 if(v instanceof Date){
12000 if(dateFormat == "timestamp"){
12001 return new Date(v*1000);
12003 return Date.parseDate(v, dateFormat);
12005 var parsed = Date.parse(v);
12006 return parsed ? new Date(parsed) : null;
12015 Roo.data.Field.prototype = {
12023 * Ext JS Library 1.1.1
12024 * Copyright(c) 2006-2007, Ext JS, LLC.
12026 * Originally Released Under LGPL - original licence link has changed is not relivant.
12029 * <script type="text/javascript">
12032 // Base class for reading structured data from a data source. This class is intended to be
12033 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12036 * @class Roo.data.DataReader
12037 * Base class for reading structured data from a data source. This class is intended to be
12038 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12041 Roo.data.DataReader = function(meta, recordType){
12045 this.recordType = recordType instanceof Array ?
12046 Roo.data.Record.create(recordType) : recordType;
12049 Roo.data.DataReader.prototype = {
12051 * Create an empty record
12052 * @param {Object} data (optional) - overlay some values
12053 * @return {Roo.data.Record} record created.
12055 newRow : function(d) {
12057 this.recordType.prototype.fields.each(function(c) {
12059 case 'int' : da[c.name] = 0; break;
12060 case 'date' : da[c.name] = new Date(); break;
12061 case 'float' : da[c.name] = 0.0; break;
12062 case 'boolean' : da[c.name] = false; break;
12063 default : da[c.name] = ""; break;
12067 return new this.recordType(Roo.apply(da, d));
12072 * Ext JS Library 1.1.1
12073 * Copyright(c) 2006-2007, Ext JS, LLC.
12075 * Originally Released Under LGPL - original licence link has changed is not relivant.
12078 * <script type="text/javascript">
12082 * @class Roo.data.DataProxy
12083 * @extends Roo.data.Observable
12084 * This class is an abstract base class for implementations which provide retrieval of
12085 * unformatted data objects.<br>
12087 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12088 * (of the appropriate type which knows how to parse the data object) to provide a block of
12089 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12091 * Custom implementations must implement the load method as described in
12092 * {@link Roo.data.HttpProxy#load}.
12094 Roo.data.DataProxy = function(){
12097 * @event beforeload
12098 * Fires before a network request is made to retrieve a data object.
12099 * @param {Object} This DataProxy object.
12100 * @param {Object} params The params parameter to the load function.
12105 * Fires before the load method's callback is called.
12106 * @param {Object} This DataProxy object.
12107 * @param {Object} o The data object.
12108 * @param {Object} arg The callback argument object passed to the load function.
12112 * @event loadexception
12113 * Fires if an Exception occurs during data retrieval.
12114 * @param {Object} This DataProxy object.
12115 * @param {Object} o The data object.
12116 * @param {Object} arg The callback argument object passed to the load function.
12117 * @param {Object} e The Exception.
12119 loadexception : true
12121 Roo.data.DataProxy.superclass.constructor.call(this);
12124 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12127 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12131 * Ext JS Library 1.1.1
12132 * Copyright(c) 2006-2007, Ext JS, LLC.
12134 * Originally Released Under LGPL - original licence link has changed is not relivant.
12137 * <script type="text/javascript">
12140 * @class Roo.data.MemoryProxy
12141 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12142 * to the Reader when its load method is called.
12144 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12146 Roo.data.MemoryProxy = function(data){
12150 Roo.data.MemoryProxy.superclass.constructor.call(this);
12154 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12157 * Load data from the requested source (in this case an in-memory
12158 * data object passed to the constructor), read the data object into
12159 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12160 * process that block using the passed callback.
12161 * @param {Object} params This parameter is not used by the MemoryProxy class.
12162 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12163 * object into a block of Roo.data.Records.
12164 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12165 * The function must be passed <ul>
12166 * <li>The Record block object</li>
12167 * <li>The "arg" argument from the load function</li>
12168 * <li>A boolean success indicator</li>
12170 * @param {Object} scope The scope in which to call the callback
12171 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12173 load : function(params, reader, callback, scope, arg){
12174 params = params || {};
12177 result = reader.readRecords(this.data);
12179 this.fireEvent("loadexception", this, arg, null, e);
12180 callback.call(scope, null, arg, false);
12183 callback.call(scope, result, arg, true);
12187 update : function(params, records){
12192 * Ext JS Library 1.1.1
12193 * Copyright(c) 2006-2007, Ext JS, LLC.
12195 * Originally Released Under LGPL - original licence link has changed is not relivant.
12198 * <script type="text/javascript">
12201 * @class Roo.data.HttpProxy
12202 * @extends Roo.data.DataProxy
12203 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12204 * configured to reference a certain URL.<br><br>
12206 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12207 * from which the running page was served.<br><br>
12209 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12211 * Be aware that to enable the browser to parse an XML document, the server must set
12212 * the Content-Type header in the HTTP response to "text/xml".
12214 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12215 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12216 * will be used to make the request.
12218 Roo.data.HttpProxy = function(conn){
12219 Roo.data.HttpProxy.superclass.constructor.call(this);
12220 // is conn a conn config or a real conn?
12222 this.useAjax = !conn || !conn.events;
12226 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12227 // thse are take from connection...
12230 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12233 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12234 * extra parameters to each request made by this object. (defaults to undefined)
12237 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12238 * to each request made by this object. (defaults to undefined)
12241 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
12244 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12247 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12253 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12257 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12258 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12259 * a finer-grained basis than the DataProxy events.
12261 getConnection : function(){
12262 return this.useAjax ? Roo.Ajax : this.conn;
12266 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12267 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12268 * process that block using the passed callback.
12269 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12270 * for the request to the remote server.
12271 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12272 * object into a block of Roo.data.Records.
12273 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12274 * The function must be passed <ul>
12275 * <li>The Record block object</li>
12276 * <li>The "arg" argument from the load function</li>
12277 * <li>A boolean success indicator</li>
12279 * @param {Object} scope The scope in which to call the callback
12280 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12282 load : function(params, reader, callback, scope, arg){
12283 if(this.fireEvent("beforeload", this, params) !== false){
12285 params : params || {},
12287 callback : callback,
12292 callback : this.loadResponse,
12296 Roo.applyIf(o, this.conn);
12297 if(this.activeRequest){
12298 Roo.Ajax.abort(this.activeRequest);
12300 this.activeRequest = Roo.Ajax.request(o);
12302 this.conn.request(o);
12305 callback.call(scope||this, null, arg, false);
12310 loadResponse : function(o, success, response){
12311 delete this.activeRequest;
12313 this.fireEvent("loadexception", this, o, response);
12314 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12319 result = o.reader.read(response);
12321 this.fireEvent("loadexception", this, o, response, e);
12322 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12326 this.fireEvent("load", this, o, o.request.arg);
12327 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12331 update : function(dataSet){
12336 updateResponse : function(dataSet){
12341 * Ext JS Library 1.1.1
12342 * Copyright(c) 2006-2007, Ext JS, LLC.
12344 * Originally Released Under LGPL - original licence link has changed is not relivant.
12347 * <script type="text/javascript">
12351 * @class Roo.data.ScriptTagProxy
12352 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12353 * other than the originating domain of the running page.<br><br>
12355 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
12356 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12358 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12359 * source code that is used as the source inside a <script> tag.<br><br>
12361 * In order for the browser to process the returned data, the server must wrap the data object
12362 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12363 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12364 * depending on whether the callback name was passed:
12367 boolean scriptTag = false;
12368 String cb = request.getParameter("callback");
12371 response.setContentType("text/javascript");
12373 response.setContentType("application/x-json");
12375 Writer out = response.getWriter();
12377 out.write(cb + "(");
12379 out.print(dataBlock.toJsonString());
12386 * @param {Object} config A configuration object.
12388 Roo.data.ScriptTagProxy = function(config){
12389 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12390 Roo.apply(this, config);
12391 this.head = document.getElementsByTagName("head")[0];
12394 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12396 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12398 * @cfg {String} url The URL from which to request the data object.
12401 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12405 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12406 * the server the name of the callback function set up by the load call to process the returned data object.
12407 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12408 * javascript output which calls this named function passing the data object as its only parameter.
12410 callbackParam : "callback",
12412 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12413 * name to the request.
12418 * Load data from the configured URL, read the data object into
12419 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12420 * process that block using the passed callback.
12421 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12422 * for the request to the remote server.
12423 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12424 * object into a block of Roo.data.Records.
12425 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12426 * The function must be passed <ul>
12427 * <li>The Record block object</li>
12428 * <li>The "arg" argument from the load function</li>
12429 * <li>A boolean success indicator</li>
12431 * @param {Object} scope The scope in which to call the callback
12432 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12434 load : function(params, reader, callback, scope, arg){
12435 if(this.fireEvent("beforeload", this, params) !== false){
12437 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12439 var url = this.url;
12440 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12442 url += "&_dc=" + (new Date().getTime());
12444 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12447 cb : "stcCallback"+transId,
12448 scriptId : "stcScript"+transId,
12452 callback : callback,
12458 window[trans.cb] = function(o){
12459 conn.handleResponse(o, trans);
12462 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12464 if(this.autoAbort !== false){
12468 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12470 var script = document.createElement("script");
12471 script.setAttribute("src", url);
12472 script.setAttribute("type", "text/javascript");
12473 script.setAttribute("id", trans.scriptId);
12474 this.head.appendChild(script);
12476 this.trans = trans;
12478 callback.call(scope||this, null, arg, false);
12483 isLoading : function(){
12484 return this.trans ? true : false;
12488 * Abort the current server request.
12490 abort : function(){
12491 if(this.isLoading()){
12492 this.destroyTrans(this.trans);
12497 destroyTrans : function(trans, isLoaded){
12498 this.head.removeChild(document.getElementById(trans.scriptId));
12499 clearTimeout(trans.timeoutId);
12501 window[trans.cb] = undefined;
12503 delete window[trans.cb];
12506 // if hasn't been loaded, wait for load to remove it to prevent script error
12507 window[trans.cb] = function(){
12508 window[trans.cb] = undefined;
12510 delete window[trans.cb];
12517 handleResponse : function(o, trans){
12518 this.trans = false;
12519 this.destroyTrans(trans, true);
12522 result = trans.reader.readRecords(o);
12524 this.fireEvent("loadexception", this, o, trans.arg, e);
12525 trans.callback.call(trans.scope||window, null, trans.arg, false);
12528 this.fireEvent("load", this, o, trans.arg);
12529 trans.callback.call(trans.scope||window, result, trans.arg, true);
12533 handleFailure : function(trans){
12534 this.trans = false;
12535 this.destroyTrans(trans, false);
12536 this.fireEvent("loadexception", this, null, trans.arg);
12537 trans.callback.call(trans.scope||window, null, trans.arg, false);
12541 * Ext JS Library 1.1.1
12542 * Copyright(c) 2006-2007, Ext JS, LLC.
12544 * Originally Released Under LGPL - original licence link has changed is not relivant.
12547 * <script type="text/javascript">
12551 * @class Roo.data.JsonReader
12552 * @extends Roo.data.DataReader
12553 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12554 * based on mappings in a provided Roo.data.Record constructor.
12556 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12557 * in the reply previously.
12562 var RecordDef = Roo.data.Record.create([
12563 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12564 {name: 'occupation'} // This field will use "occupation" as the mapping.
12566 var myReader = new Roo.data.JsonReader({
12567 totalProperty: "results", // The property which contains the total dataset size (optional)
12568 root: "rows", // The property which contains an Array of row objects
12569 id: "id" // The property within each row object that provides an ID for the record (optional)
12573 * This would consume a JSON file like this:
12575 { 'results': 2, 'rows': [
12576 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12577 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12580 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12581 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12582 * paged from the remote server.
12583 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12584 * @cfg {String} root name of the property which contains the Array of row objects.
12585 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12586 * @cfg {Array} fields Array of field definition objects
12588 * Create a new JsonReader
12589 * @param {Object} meta Metadata configuration options
12590 * @param {Object} recordType Either an Array of field definition objects,
12591 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12593 Roo.data.JsonReader = function(meta, recordType){
12596 // set some defaults:
12597 Roo.applyIf(meta, {
12598 totalProperty: 'total',
12599 successProperty : 'success',
12604 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12606 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12609 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12610 * Used by Store query builder to append _requestMeta to params.
12613 metaFromRemote : false,
12615 * This method is only used by a DataProxy which has retrieved data from a remote server.
12616 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12617 * @return {Object} data A data block which is used by an Roo.data.Store object as
12618 * a cache of Roo.data.Records.
12620 read : function(response){
12621 var json = response.responseText;
12623 var o = /* eval:var:o */ eval("("+json+")");
12625 throw {message: "JsonReader.read: Json object not found"};
12631 this.metaFromRemote = true;
12632 this.meta = o.metaData;
12633 this.recordType = Roo.data.Record.create(o.metaData.fields);
12634 this.onMetaChange(this.meta, this.recordType, o);
12636 return this.readRecords(o);
12639 // private function a store will implement
12640 onMetaChange : function(meta, recordType, o){
12647 simpleAccess: function(obj, subsc) {
12654 getJsonAccessor: function(){
12656 return function(expr) {
12658 return(re.test(expr))
12659 ? new Function("obj", "return obj." + expr)
12664 return Roo.emptyFn;
12669 * Create a data block containing Roo.data.Records from an XML document.
12670 * @param {Object} o An object which contains an Array of row objects in the property specified
12671 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12672 * which contains the total size of the dataset.
12673 * @return {Object} data A data block which is used by an Roo.data.Store object as
12674 * a cache of Roo.data.Records.
12676 readRecords : function(o){
12678 * After any data loads, the raw JSON data is available for further custom processing.
12682 var s = this.meta, Record = this.recordType,
12683 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12685 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12687 if(s.totalProperty) {
12688 this.getTotal = this.getJsonAccessor(s.totalProperty);
12690 if(s.successProperty) {
12691 this.getSuccess = this.getJsonAccessor(s.successProperty);
12693 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12695 var g = this.getJsonAccessor(s.id);
12696 this.getId = function(rec) {
12698 return (r === undefined || r === "") ? null : r;
12701 this.getId = function(){return null;};
12704 for(var jj = 0; jj < fl; jj++){
12706 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12707 this.ef[jj] = this.getJsonAccessor(map);
12711 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12712 if(s.totalProperty){
12713 var vt = parseInt(this.getTotal(o), 10);
12718 if(s.successProperty){
12719 var vs = this.getSuccess(o);
12720 if(vs === false || vs === 'false'){
12725 for(var i = 0; i < c; i++){
12728 var id = this.getId(n);
12729 for(var j = 0; j < fl; j++){
12731 var v = this.ef[j](n);
12733 Roo.log('missing convert for ' + f.name);
12737 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12739 var record = new Record(values, id);
12741 records[i] = record;
12747 totalRecords : totalRecords
12752 * Ext JS Library 1.1.1
12753 * Copyright(c) 2006-2007, Ext JS, LLC.
12755 * Originally Released Under LGPL - original licence link has changed is not relivant.
12758 * <script type="text/javascript">
12762 * @class Roo.data.ArrayReader
12763 * @extends Roo.data.DataReader
12764 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12765 * Each element of that Array represents a row of data fields. The
12766 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12767 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12771 var RecordDef = Roo.data.Record.create([
12772 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12773 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12775 var myReader = new Roo.data.ArrayReader({
12776 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12780 * This would consume an Array like this:
12782 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12784 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12786 * Create a new JsonReader
12787 * @param {Object} meta Metadata configuration options.
12788 * @param {Object} recordType Either an Array of field definition objects
12789 * as specified to {@link Roo.data.Record#create},
12790 * or an {@link Roo.data.Record} object
12791 * created using {@link Roo.data.Record#create}.
12793 Roo.data.ArrayReader = function(meta, recordType){
12794 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12797 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12799 * Create a data block containing Roo.data.Records from an XML document.
12800 * @param {Object} o An Array of row objects which represents the dataset.
12801 * @return {Object} data A data block which is used by an Roo.data.Store object as
12802 * a cache of Roo.data.Records.
12804 readRecords : function(o){
12805 var sid = this.meta ? this.meta.id : null;
12806 var recordType = this.recordType, fields = recordType.prototype.fields;
12809 for(var i = 0; i < root.length; i++){
12812 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12813 for(var j = 0, jlen = fields.length; j < jlen; j++){
12814 var f = fields.items[j];
12815 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12816 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12818 values[f.name] = v;
12820 var record = new recordType(values, id);
12822 records[records.length] = record;
12826 totalRecords : records.length
12835 * @class Roo.bootstrap.ComboBox
12836 * @extends Roo.bootstrap.TriggerField
12837 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12838 * @cfg {Boolean} append (true|false) default false
12839 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12840 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12841 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12842 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12843 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12844 * @cfg {Boolean} animate default true
12845 * @cfg {Boolean} emptyResultText only for touch device
12846 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12847 * @cfg {String} emptyTitle default ''
12849 * Create a new ComboBox.
12850 * @param {Object} config Configuration options
12852 Roo.bootstrap.ComboBox = function(config){
12853 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12857 * Fires when the dropdown list is expanded
12858 * @param {Roo.bootstrap.ComboBox} combo This combo box
12863 * Fires when the dropdown list is collapsed
12864 * @param {Roo.bootstrap.ComboBox} combo This combo box
12868 * @event beforeselect
12869 * Fires before a list item is selected. Return false to cancel the selection.
12870 * @param {Roo.bootstrap.ComboBox} combo This combo box
12871 * @param {Roo.data.Record} record The data record returned from the underlying store
12872 * @param {Number} index The index of the selected item in the dropdown list
12874 'beforeselect' : true,
12877 * Fires when a list item is selected
12878 * @param {Roo.bootstrap.ComboBox} combo This combo box
12879 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12880 * @param {Number} index The index of the selected item in the dropdown list
12884 * @event beforequery
12885 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12886 * The event object passed has these properties:
12887 * @param {Roo.bootstrap.ComboBox} combo This combo box
12888 * @param {String} query The query
12889 * @param {Boolean} forceAll true to force "all" query
12890 * @param {Boolean} cancel true to cancel the query
12891 * @param {Object} e The query event object
12893 'beforequery': true,
12896 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12897 * @param {Roo.bootstrap.ComboBox} combo This combo box
12902 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12903 * @param {Roo.bootstrap.ComboBox} combo This combo box
12904 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12909 * Fires when the remove value from the combobox array
12910 * @param {Roo.bootstrap.ComboBox} combo This combo box
12914 * @event afterremove
12915 * Fires when the remove value from the combobox array
12916 * @param {Roo.bootstrap.ComboBox} combo This combo box
12918 'afterremove' : true,
12920 * @event specialfilter
12921 * Fires when specialfilter
12922 * @param {Roo.bootstrap.ComboBox} combo This combo box
12924 'specialfilter' : true,
12927 * Fires when tick the element
12928 * @param {Roo.bootstrap.ComboBox} combo This combo box
12932 * @event touchviewdisplay
12933 * Fires when touch view require special display (default is using displayField)
12934 * @param {Roo.bootstrap.ComboBox} combo This combo box
12935 * @param {Object} cfg set html .
12937 'touchviewdisplay' : true
12942 this.tickItems = [];
12944 this.selectedIndex = -1;
12945 if(this.mode == 'local'){
12946 if(config.queryDelay === undefined){
12947 this.queryDelay = 10;
12949 if(config.minChars === undefined){
12955 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12958 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12959 * rendering into an Roo.Editor, defaults to false)
12962 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12963 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12966 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12969 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12970 * the dropdown list (defaults to undefined, with no header element)
12974 * @cfg {String/Roo.Template} tpl The template to use to render the output
12978 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12980 listWidth: undefined,
12982 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12983 * mode = 'remote' or 'text' if mode = 'local')
12985 displayField: undefined,
12988 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12989 * mode = 'remote' or 'value' if mode = 'local').
12990 * Note: use of a valueField requires the user make a selection
12991 * in order for a value to be mapped.
12993 valueField: undefined,
12995 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13000 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13001 * field's data value (defaults to the underlying DOM element's name)
13003 hiddenName: undefined,
13005 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13009 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13011 selectedClass: 'active',
13014 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13018 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13019 * anchor positions (defaults to 'tl-bl')
13021 listAlign: 'tl-bl?',
13023 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13027 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13028 * query specified by the allQuery config option (defaults to 'query')
13030 triggerAction: 'query',
13032 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13033 * (defaults to 4, does not apply if editable = false)
13037 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13038 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13042 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13043 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13047 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13048 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13052 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13053 * when editable = true (defaults to false)
13055 selectOnFocus:false,
13057 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13059 queryParam: 'query',
13061 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13062 * when mode = 'remote' (defaults to 'Loading...')
13064 loadingText: 'Loading...',
13066 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13070 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13074 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13075 * traditional select (defaults to true)
13079 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13083 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13087 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13088 * listWidth has a higher value)
13092 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13093 * allow the user to set arbitrary text into the field (defaults to false)
13095 forceSelection:false,
13097 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13098 * if typeAhead = true (defaults to 250)
13100 typeAheadDelay : 250,
13102 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13103 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13105 valueNotFoundText : undefined,
13107 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13109 blockFocus : false,
13112 * @cfg {Boolean} disableClear Disable showing of clear button.
13114 disableClear : false,
13116 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13118 alwaysQuery : false,
13121 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13126 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13128 invalidClass : "has-warning",
13131 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13133 validClass : "has-success",
13136 * @cfg {Boolean} specialFilter (true|false) special filter default false
13138 specialFilter : false,
13141 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13143 mobileTouchView : true,
13146 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13148 useNativeIOS : false,
13151 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13153 mobile_restrict_height : false,
13155 ios_options : false,
13167 btnPosition : 'right',
13168 triggerList : true,
13169 showToggleBtn : true,
13171 emptyResultText: 'Empty',
13172 triggerText : 'Select',
13175 // element that contains real text value.. (when hidden is used..)
13177 getAutoCreate : function()
13182 * Render classic select for iso
13185 if(Roo.isIOS && this.useNativeIOS){
13186 cfg = this.getAutoCreateNativeIOS();
13194 if(Roo.isTouch && this.mobileTouchView){
13195 cfg = this.getAutoCreateTouchView();
13202 if(!this.tickable){
13203 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13208 * ComboBox with tickable selections
13211 var align = this.labelAlign || this.parentLabelAlign();
13214 cls : 'form-group roo-combobox-tickable' //input-group
13217 var btn_text_select = '';
13218 var btn_text_done = '';
13219 var btn_text_cancel = '';
13221 if (this.btn_text_show) {
13222 btn_text_select = 'Select';
13223 btn_text_done = 'Done';
13224 btn_text_cancel = 'Cancel';
13229 cls : 'tickable-buttons',
13234 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13235 //html : this.triggerText
13236 html: btn_text_select
13242 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13244 html: btn_text_done
13250 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13252 html: btn_text_cancel
13258 buttons.cn.unshift({
13260 cls: 'roo-select2-search-field-input'
13266 Roo.each(buttons.cn, function(c){
13268 c.cls += ' btn-' + _this.size;
13271 if (_this.disabled) {
13282 cls: 'form-hidden-field'
13286 cls: 'roo-select2-choices',
13290 cls: 'roo-select2-search-field',
13301 cls: 'roo-select2-container input-group roo-select2-container-multi',
13306 // cls: 'typeahead typeahead-long dropdown-menu',
13307 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13312 if(this.hasFeedback && !this.allowBlank){
13316 cls: 'glyphicon form-control-feedback'
13319 combobox.cn.push(feedback);
13323 if (align ==='left' && this.fieldLabel.length) {
13325 cfg.cls += ' roo-form-group-label-left';
13330 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13331 tooltip : 'This field is required'
13336 cls : 'control-label',
13337 html : this.fieldLabel
13349 var labelCfg = cfg.cn[1];
13350 var contentCfg = cfg.cn[2];
13353 if(this.indicatorpos == 'right'){
13359 cls : 'control-label',
13363 html : this.fieldLabel
13367 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13368 tooltip : 'This field is required'
13383 labelCfg = cfg.cn[0];
13384 contentCfg = cfg.cn[1];
13388 if(this.labelWidth > 12){
13389 labelCfg.style = "width: " + this.labelWidth + 'px';
13392 if(this.labelWidth < 13 && this.labelmd == 0){
13393 this.labelmd = this.labelWidth;
13396 if(this.labellg > 0){
13397 labelCfg.cls += ' col-lg-' + this.labellg;
13398 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13401 if(this.labelmd > 0){
13402 labelCfg.cls += ' col-md-' + this.labelmd;
13403 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13406 if(this.labelsm > 0){
13407 labelCfg.cls += ' col-sm-' + this.labelsm;
13408 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13411 if(this.labelxs > 0){
13412 labelCfg.cls += ' col-xs-' + this.labelxs;
13413 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13417 } else if ( this.fieldLabel.length) {
13418 // Roo.log(" label");
13422 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13423 tooltip : 'This field is required'
13427 //cls : 'input-group-addon',
13428 html : this.fieldLabel
13433 if(this.indicatorpos == 'right'){
13437 //cls : 'input-group-addon',
13438 html : this.fieldLabel
13442 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13443 tooltip : 'This field is required'
13452 // Roo.log(" no label && no align");
13459 ['xs','sm','md','lg'].map(function(size){
13460 if (settings[size]) {
13461 cfg.cls += ' col-' + size + '-' + settings[size];
13469 _initEventsCalled : false,
13472 initEvents: function()
13474 if (this._initEventsCalled) { // as we call render... prevent looping...
13477 this._initEventsCalled = true;
13480 throw "can not find store for combo";
13483 this.indicator = this.indicatorEl();
13485 this.store = Roo.factory(this.store, Roo.data);
13486 this.store.parent = this;
13488 // if we are building from html. then this element is so complex, that we can not really
13489 // use the rendered HTML.
13490 // so we have to trash and replace the previous code.
13491 if (Roo.XComponent.build_from_html) {
13492 // remove this element....
13493 var e = this.el.dom, k=0;
13494 while (e ) { e = e.previousSibling; ++k;}
13499 this.rendered = false;
13501 this.render(this.parent().getChildContainer(true), k);
13504 if(Roo.isIOS && this.useNativeIOS){
13505 this.initIOSView();
13513 if(Roo.isTouch && this.mobileTouchView){
13514 this.initTouchView();
13519 this.initTickableEvents();
13523 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13525 if(this.hiddenName){
13527 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13529 this.hiddenField.dom.value =
13530 this.hiddenValue !== undefined ? this.hiddenValue :
13531 this.value !== undefined ? this.value : '';
13533 // prevent input submission
13534 this.el.dom.removeAttribute('name');
13535 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13540 // this.el.dom.setAttribute('autocomplete', 'off');
13543 var cls = 'x-combo-list';
13545 //this.list = new Roo.Layer({
13546 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13552 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13553 _this.list.setWidth(lw);
13556 this.list.on('mouseover', this.onViewOver, this);
13557 this.list.on('mousemove', this.onViewMove, this);
13558 this.list.on('scroll', this.onViewScroll, this);
13561 this.list.swallowEvent('mousewheel');
13562 this.assetHeight = 0;
13565 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13566 this.assetHeight += this.header.getHeight();
13569 this.innerList = this.list.createChild({cls:cls+'-inner'});
13570 this.innerList.on('mouseover', this.onViewOver, this);
13571 this.innerList.on('mousemove', this.onViewMove, this);
13572 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13574 if(this.allowBlank && !this.pageSize && !this.disableClear){
13575 this.footer = this.list.createChild({cls:cls+'-ft'});
13576 this.pageTb = new Roo.Toolbar(this.footer);
13580 this.footer = this.list.createChild({cls:cls+'-ft'});
13581 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13582 {pageSize: this.pageSize});
13586 if (this.pageTb && this.allowBlank && !this.disableClear) {
13588 this.pageTb.add(new Roo.Toolbar.Fill(), {
13589 cls: 'x-btn-icon x-btn-clear',
13591 handler: function()
13594 _this.clearValue();
13595 _this.onSelect(false, -1);
13600 this.assetHeight += this.footer.getHeight();
13605 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13608 this.view = new Roo.View(this.list, this.tpl, {
13609 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13611 //this.view.wrapEl.setDisplayed(false);
13612 this.view.on('click', this.onViewClick, this);
13615 this.store.on('beforeload', this.onBeforeLoad, this);
13616 this.store.on('load', this.onLoad, this);
13617 this.store.on('loadexception', this.onLoadException, this);
13619 if(this.resizable){
13620 this.resizer = new Roo.Resizable(this.list, {
13621 pinned:true, handles:'se'
13623 this.resizer.on('resize', function(r, w, h){
13624 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13625 this.listWidth = w;
13626 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13627 this.restrictHeight();
13629 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13632 if(!this.editable){
13633 this.editable = true;
13634 this.setEditable(false);
13639 if (typeof(this.events.add.listeners) != 'undefined') {
13641 this.addicon = this.wrap.createChild(
13642 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13644 this.addicon.on('click', function(e) {
13645 this.fireEvent('add', this);
13648 if (typeof(this.events.edit.listeners) != 'undefined') {
13650 this.editicon = this.wrap.createChild(
13651 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13652 if (this.addicon) {
13653 this.editicon.setStyle('margin-left', '40px');
13655 this.editicon.on('click', function(e) {
13657 // we fire even if inothing is selected..
13658 this.fireEvent('edit', this, this.lastData );
13664 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13665 "up" : function(e){
13666 this.inKeyMode = true;
13670 "down" : function(e){
13671 if(!this.isExpanded()){
13672 this.onTriggerClick();
13674 this.inKeyMode = true;
13679 "enter" : function(e){
13680 // this.onViewClick();
13684 if(this.fireEvent("specialkey", this, e)){
13685 this.onViewClick(false);
13691 "esc" : function(e){
13695 "tab" : function(e){
13698 if(this.fireEvent("specialkey", this, e)){
13699 this.onViewClick(false);
13707 doRelay : function(foo, bar, hname){
13708 if(hname == 'down' || this.scope.isExpanded()){
13709 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13718 this.queryDelay = Math.max(this.queryDelay || 10,
13719 this.mode == 'local' ? 10 : 250);
13722 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13724 if(this.typeAhead){
13725 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13727 if(this.editable !== false){
13728 this.inputEl().on("keyup", this.onKeyUp, this);
13730 if(this.forceSelection){
13731 this.inputEl().on('blur', this.doForce, this);
13735 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13736 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13740 initTickableEvents: function()
13744 if(this.hiddenName){
13746 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13748 this.hiddenField.dom.value =
13749 this.hiddenValue !== undefined ? this.hiddenValue :
13750 this.value !== undefined ? this.value : '';
13752 // prevent input submission
13753 this.el.dom.removeAttribute('name');
13754 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13759 // this.list = this.el.select('ul.dropdown-menu',true).first();
13761 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13762 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13763 if(this.triggerList){
13764 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13767 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13768 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13770 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13771 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13773 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13774 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13776 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13777 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13778 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13781 this.cancelBtn.hide();
13786 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13787 _this.list.setWidth(lw);
13790 this.list.on('mouseover', this.onViewOver, this);
13791 this.list.on('mousemove', this.onViewMove, this);
13793 this.list.on('scroll', this.onViewScroll, this);
13796 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13797 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13800 this.view = new Roo.View(this.list, this.tpl, {
13805 selectedClass: this.selectedClass
13808 //this.view.wrapEl.setDisplayed(false);
13809 this.view.on('click', this.onViewClick, this);
13813 this.store.on('beforeload', this.onBeforeLoad, this);
13814 this.store.on('load', this.onLoad, this);
13815 this.store.on('loadexception', this.onLoadException, this);
13818 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13819 "up" : function(e){
13820 this.inKeyMode = true;
13824 "down" : function(e){
13825 this.inKeyMode = true;
13829 "enter" : function(e){
13830 if(this.fireEvent("specialkey", this, e)){
13831 this.onViewClick(false);
13837 "esc" : function(e){
13838 this.onTickableFooterButtonClick(e, false, false);
13841 "tab" : function(e){
13842 this.fireEvent("specialkey", this, e);
13844 this.onTickableFooterButtonClick(e, false, false);
13851 doRelay : function(e, fn, key){
13852 if(this.scope.isExpanded()){
13853 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13862 this.queryDelay = Math.max(this.queryDelay || 10,
13863 this.mode == 'local' ? 10 : 250);
13866 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13868 if(this.typeAhead){
13869 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13872 if(this.editable !== false){
13873 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13876 this.indicator = this.indicatorEl();
13878 if(this.indicator){
13879 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13880 this.indicator.hide();
13885 onDestroy : function(){
13887 this.view.setStore(null);
13888 this.view.el.removeAllListeners();
13889 this.view.el.remove();
13890 this.view.purgeListeners();
13893 this.list.dom.innerHTML = '';
13897 this.store.un('beforeload', this.onBeforeLoad, this);
13898 this.store.un('load', this.onLoad, this);
13899 this.store.un('loadexception', this.onLoadException, this);
13901 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13905 fireKey : function(e){
13906 if(e.isNavKeyPress() && !this.list.isVisible()){
13907 this.fireEvent("specialkey", this, e);
13912 onResize: function(w, h){
13913 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13915 // if(typeof w != 'number'){
13916 // // we do not handle it!?!?
13919 // var tw = this.trigger.getWidth();
13920 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13921 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13923 // this.inputEl().setWidth( this.adjustWidth('input', x));
13925 // //this.trigger.setStyle('left', x+'px');
13927 // if(this.list && this.listWidth === undefined){
13928 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13929 // this.list.setWidth(lw);
13930 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13938 * Allow or prevent the user from directly editing the field text. If false is passed,
13939 * the user will only be able to select from the items defined in the dropdown list. This method
13940 * is the runtime equivalent of setting the 'editable' config option at config time.
13941 * @param {Boolean} value True to allow the user to directly edit the field text
13943 setEditable : function(value){
13944 if(value == this.editable){
13947 this.editable = value;
13949 this.inputEl().dom.setAttribute('readOnly', true);
13950 this.inputEl().on('mousedown', this.onTriggerClick, this);
13951 this.inputEl().addClass('x-combo-noedit');
13953 this.inputEl().dom.setAttribute('readOnly', false);
13954 this.inputEl().un('mousedown', this.onTriggerClick, this);
13955 this.inputEl().removeClass('x-combo-noedit');
13961 onBeforeLoad : function(combo,opts){
13962 if(!this.hasFocus){
13966 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13968 this.restrictHeight();
13969 this.selectedIndex = -1;
13973 onLoad : function(){
13975 this.hasQuery = false;
13977 if(!this.hasFocus){
13981 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13982 this.loading.hide();
13985 if(this.store.getCount() > 0){
13988 this.restrictHeight();
13989 if(this.lastQuery == this.allQuery){
13990 if(this.editable && !this.tickable){
13991 this.inputEl().dom.select();
13995 !this.selectByValue(this.value, true) &&
13998 !this.store.lastOptions ||
13999 typeof(this.store.lastOptions.add) == 'undefined' ||
14000 this.store.lastOptions.add != true
14003 this.select(0, true);
14006 if(this.autoFocus){
14009 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14010 this.taTask.delay(this.typeAheadDelay);
14014 this.onEmptyResults();
14020 onLoadException : function()
14022 this.hasQuery = false;
14024 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14025 this.loading.hide();
14028 if(this.tickable && this.editable){
14033 // only causes errors at present
14034 //Roo.log(this.store.reader.jsonData);
14035 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14037 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14043 onTypeAhead : function(){
14044 if(this.store.getCount() > 0){
14045 var r = this.store.getAt(0);
14046 var newValue = r.data[this.displayField];
14047 var len = newValue.length;
14048 var selStart = this.getRawValue().length;
14050 if(selStart != len){
14051 this.setRawValue(newValue);
14052 this.selectText(selStart, newValue.length);
14058 onSelect : function(record, index){
14060 if(this.fireEvent('beforeselect', this, record, index) !== false){
14062 this.setFromData(index > -1 ? record.data : false);
14065 this.fireEvent('select', this, record, index);
14070 * Returns the currently selected field value or empty string if no value is set.
14071 * @return {String} value The selected value
14073 getValue : function()
14075 if(Roo.isIOS && this.useNativeIOS){
14076 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14080 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14083 if(this.valueField){
14084 return typeof this.value != 'undefined' ? this.value : '';
14086 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14090 getRawValue : function()
14092 if(Roo.isIOS && this.useNativeIOS){
14093 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14096 var v = this.inputEl().getValue();
14102 * Clears any text/value currently set in the field
14104 clearValue : function(){
14106 if(this.hiddenField){
14107 this.hiddenField.dom.value = '';
14110 this.setRawValue('');
14111 this.lastSelectionText = '';
14112 this.lastData = false;
14114 var close = this.closeTriggerEl();
14125 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14126 * will be displayed in the field. If the value does not match the data value of an existing item,
14127 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14128 * Otherwise the field will be blank (although the value will still be set).
14129 * @param {String} value The value to match
14131 setValue : function(v)
14133 if(Roo.isIOS && this.useNativeIOS){
14134 this.setIOSValue(v);
14144 if(this.valueField){
14145 var r = this.findRecord(this.valueField, v);
14147 text = r.data[this.displayField];
14148 }else if(this.valueNotFoundText !== undefined){
14149 text = this.valueNotFoundText;
14152 this.lastSelectionText = text;
14153 if(this.hiddenField){
14154 this.hiddenField.dom.value = v;
14156 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14159 var close = this.closeTriggerEl();
14162 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14168 * @property {Object} the last set data for the element
14173 * Sets the value of the field based on a object which is related to the record format for the store.
14174 * @param {Object} value the value to set as. or false on reset?
14176 setFromData : function(o){
14183 var dv = ''; // display value
14184 var vv = ''; // value value..
14186 if (this.displayField) {
14187 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14189 // this is an error condition!!!
14190 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14193 if(this.valueField){
14194 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14197 var close = this.closeTriggerEl();
14200 if(dv.length || vv * 1 > 0){
14202 this.blockFocus=true;
14208 if(this.hiddenField){
14209 this.hiddenField.dom.value = vv;
14211 this.lastSelectionText = dv;
14212 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14216 // no hidden field.. - we store the value in 'value', but still display
14217 // display field!!!!
14218 this.lastSelectionText = dv;
14219 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14226 reset : function(){
14227 // overridden so that last data is reset..
14234 this.setValue(this.originalValue);
14235 //this.clearInvalid();
14236 this.lastData = false;
14238 this.view.clearSelections();
14244 findRecord : function(prop, value){
14246 if(this.store.getCount() > 0){
14247 this.store.each(function(r){
14248 if(r.data[prop] == value){
14258 getName: function()
14260 // returns hidden if it's set..
14261 if (!this.rendered) {return ''};
14262 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14266 onViewMove : function(e, t){
14267 this.inKeyMode = false;
14271 onViewOver : function(e, t){
14272 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14275 var item = this.view.findItemFromChild(t);
14278 var index = this.view.indexOf(item);
14279 this.select(index, false);
14284 onViewClick : function(view, doFocus, el, e)
14286 var index = this.view.getSelectedIndexes()[0];
14288 var r = this.store.getAt(index);
14292 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14299 Roo.each(this.tickItems, function(v,k){
14301 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14303 _this.tickItems.splice(k, 1);
14305 if(typeof(e) == 'undefined' && view == false){
14306 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14318 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14319 this.tickItems.push(r.data);
14322 if(typeof(e) == 'undefined' && view == false){
14323 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14330 this.onSelect(r, index);
14332 if(doFocus !== false && !this.blockFocus){
14333 this.inputEl().focus();
14338 restrictHeight : function(){
14339 //this.innerList.dom.style.height = '';
14340 //var inner = this.innerList.dom;
14341 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14342 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14343 //this.list.beginUpdate();
14344 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14345 this.list.alignTo(this.inputEl(), this.listAlign);
14346 this.list.alignTo(this.inputEl(), this.listAlign);
14347 //this.list.endUpdate();
14351 onEmptyResults : function(){
14353 if(this.tickable && this.editable){
14354 this.hasFocus = false;
14355 this.restrictHeight();
14363 * Returns true if the dropdown list is expanded, else false.
14365 isExpanded : function(){
14366 return this.list.isVisible();
14370 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14371 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14372 * @param {String} value The data value of the item to select
14373 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14374 * selected item if it is not currently in view (defaults to true)
14375 * @return {Boolean} True if the value matched an item in the list, else false
14377 selectByValue : function(v, scrollIntoView){
14378 if(v !== undefined && v !== null){
14379 var r = this.findRecord(this.valueField || this.displayField, v);
14381 this.select(this.store.indexOf(r), scrollIntoView);
14389 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14390 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14391 * @param {Number} index The zero-based index of the list item to select
14392 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14393 * selected item if it is not currently in view (defaults to true)
14395 select : function(index, scrollIntoView){
14396 this.selectedIndex = index;
14397 this.view.select(index);
14398 if(scrollIntoView !== false){
14399 var el = this.view.getNode(index);
14401 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14404 this.list.scrollChildIntoView(el, false);
14410 selectNext : function(){
14411 var ct = this.store.getCount();
14413 if(this.selectedIndex == -1){
14415 }else if(this.selectedIndex < ct-1){
14416 this.select(this.selectedIndex+1);
14422 selectPrev : function(){
14423 var ct = this.store.getCount();
14425 if(this.selectedIndex == -1){
14427 }else if(this.selectedIndex != 0){
14428 this.select(this.selectedIndex-1);
14434 onKeyUp : function(e){
14435 if(this.editable !== false && !e.isSpecialKey()){
14436 this.lastKey = e.getKey();
14437 this.dqTask.delay(this.queryDelay);
14442 validateBlur : function(){
14443 return !this.list || !this.list.isVisible();
14447 initQuery : function(){
14449 var v = this.getRawValue();
14451 if(this.tickable && this.editable){
14452 v = this.tickableInputEl().getValue();
14459 doForce : function(){
14460 if(this.inputEl().dom.value.length > 0){
14461 this.inputEl().dom.value =
14462 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14468 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14469 * query allowing the query action to be canceled if needed.
14470 * @param {String} query The SQL query to execute
14471 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14472 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14473 * saved in the current store (defaults to false)
14475 doQuery : function(q, forceAll){
14477 if(q === undefined || q === null){
14482 forceAll: forceAll,
14486 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14491 forceAll = qe.forceAll;
14492 if(forceAll === true || (q.length >= this.minChars)){
14494 this.hasQuery = true;
14496 if(this.lastQuery != q || this.alwaysQuery){
14497 this.lastQuery = q;
14498 if(this.mode == 'local'){
14499 this.selectedIndex = -1;
14501 this.store.clearFilter();
14504 if(this.specialFilter){
14505 this.fireEvent('specialfilter', this);
14510 this.store.filter(this.displayField, q);
14513 this.store.fireEvent("datachanged", this.store);
14520 this.store.baseParams[this.queryParam] = q;
14522 var options = {params : this.getParams(q)};
14525 options.add = true;
14526 options.params.start = this.page * this.pageSize;
14529 this.store.load(options);
14532 * this code will make the page width larger, at the beginning, the list not align correctly,
14533 * we should expand the list on onLoad
14534 * so command out it
14539 this.selectedIndex = -1;
14544 this.loadNext = false;
14548 getParams : function(q){
14550 //p[this.queryParam] = q;
14554 p.limit = this.pageSize;
14560 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14562 collapse : function(){
14563 if(!this.isExpanded()){
14569 this.hasFocus = false;
14573 this.cancelBtn.hide();
14574 this.trigger.show();
14577 this.tickableInputEl().dom.value = '';
14578 this.tickableInputEl().blur();
14583 Roo.get(document).un('mousedown', this.collapseIf, this);
14584 Roo.get(document).un('mousewheel', this.collapseIf, this);
14585 if (!this.editable) {
14586 Roo.get(document).un('keydown', this.listKeyPress, this);
14588 this.fireEvent('collapse', this);
14594 collapseIf : function(e){
14595 var in_combo = e.within(this.el);
14596 var in_list = e.within(this.list);
14597 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14599 if (in_combo || in_list || is_list) {
14600 //e.stopPropagation();
14605 this.onTickableFooterButtonClick(e, false, false);
14613 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14615 expand : function(){
14617 if(this.isExpanded() || !this.hasFocus){
14621 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14622 this.list.setWidth(lw);
14628 this.restrictHeight();
14632 this.tickItems = Roo.apply([], this.item);
14635 this.cancelBtn.show();
14636 this.trigger.hide();
14639 this.tickableInputEl().focus();
14644 Roo.get(document).on('mousedown', this.collapseIf, this);
14645 Roo.get(document).on('mousewheel', this.collapseIf, this);
14646 if (!this.editable) {
14647 Roo.get(document).on('keydown', this.listKeyPress, this);
14650 this.fireEvent('expand', this);
14654 // Implements the default empty TriggerField.onTriggerClick function
14655 onTriggerClick : function(e)
14657 Roo.log('trigger click');
14659 if(this.disabled || !this.triggerList){
14664 this.loadNext = false;
14666 if(this.isExpanded()){
14668 if (!this.blockFocus) {
14669 this.inputEl().focus();
14673 this.hasFocus = true;
14674 if(this.triggerAction == 'all') {
14675 this.doQuery(this.allQuery, true);
14677 this.doQuery(this.getRawValue());
14679 if (!this.blockFocus) {
14680 this.inputEl().focus();
14685 onTickableTriggerClick : function(e)
14692 this.loadNext = false;
14693 this.hasFocus = true;
14695 if(this.triggerAction == 'all') {
14696 this.doQuery(this.allQuery, true);
14698 this.doQuery(this.getRawValue());
14702 onSearchFieldClick : function(e)
14704 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14705 this.onTickableFooterButtonClick(e, false, false);
14709 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14714 this.loadNext = false;
14715 this.hasFocus = true;
14717 if(this.triggerAction == 'all') {
14718 this.doQuery(this.allQuery, true);
14720 this.doQuery(this.getRawValue());
14724 listKeyPress : function(e)
14726 //Roo.log('listkeypress');
14727 // scroll to first matching element based on key pres..
14728 if (e.isSpecialKey()) {
14731 var k = String.fromCharCode(e.getKey()).toUpperCase();
14734 var csel = this.view.getSelectedNodes();
14735 var cselitem = false;
14737 var ix = this.view.indexOf(csel[0]);
14738 cselitem = this.store.getAt(ix);
14739 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14745 this.store.each(function(v) {
14747 // start at existing selection.
14748 if (cselitem.id == v.id) {
14754 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14755 match = this.store.indexOf(v);
14761 if (match === false) {
14762 return true; // no more action?
14765 this.view.select(match);
14766 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14767 sn.scrollIntoView(sn.dom.parentNode, false);
14770 onViewScroll : function(e, t){
14772 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
14776 this.hasQuery = true;
14778 this.loading = this.list.select('.loading', true).first();
14780 if(this.loading === null){
14781 this.list.createChild({
14783 cls: 'loading roo-select2-more-results roo-select2-active',
14784 html: 'Loading more results...'
14787 this.loading = this.list.select('.loading', true).first();
14789 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14791 this.loading.hide();
14794 this.loading.show();
14799 this.loadNext = true;
14801 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14806 addItem : function(o)
14808 var dv = ''; // display value
14810 if (this.displayField) {
14811 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14813 // this is an error condition!!!
14814 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14821 var choice = this.choices.createChild({
14823 cls: 'roo-select2-search-choice',
14832 cls: 'roo-select2-search-choice-close fa fa-times',
14837 }, this.searchField);
14839 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14841 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14849 this.inputEl().dom.value = '';
14854 onRemoveItem : function(e, _self, o)
14856 e.preventDefault();
14858 this.lastItem = Roo.apply([], this.item);
14860 var index = this.item.indexOf(o.data) * 1;
14863 Roo.log('not this item?!');
14867 this.item.splice(index, 1);
14872 this.fireEvent('remove', this, e);
14878 syncValue : function()
14880 if(!this.item.length){
14887 Roo.each(this.item, function(i){
14888 if(_this.valueField){
14889 value.push(i[_this.valueField]);
14896 this.value = value.join(',');
14898 if(this.hiddenField){
14899 this.hiddenField.dom.value = this.value;
14902 this.store.fireEvent("datachanged", this.store);
14907 clearItem : function()
14909 if(!this.multiple){
14915 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14923 if(this.tickable && !Roo.isTouch){
14924 this.view.refresh();
14928 inputEl: function ()
14930 if(Roo.isIOS && this.useNativeIOS){
14931 return this.el.select('select.roo-ios-select', true).first();
14934 if(Roo.isTouch && this.mobileTouchView){
14935 return this.el.select('input.form-control',true).first();
14939 return this.searchField;
14942 return this.el.select('input.form-control',true).first();
14945 onTickableFooterButtonClick : function(e, btn, el)
14947 e.preventDefault();
14949 this.lastItem = Roo.apply([], this.item);
14951 if(btn && btn.name == 'cancel'){
14952 this.tickItems = Roo.apply([], this.item);
14961 Roo.each(this.tickItems, function(o){
14969 validate : function()
14971 if(this.getVisibilityEl().hasClass('hidden')){
14975 var v = this.getRawValue();
14978 v = this.getValue();
14981 if(this.disabled || this.allowBlank || v.length){
14986 this.markInvalid();
14990 tickableInputEl : function()
14992 if(!this.tickable || !this.editable){
14993 return this.inputEl();
14996 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15000 getAutoCreateTouchView : function()
15005 cls: 'form-group' //input-group
15011 type : this.inputType,
15012 cls : 'form-control x-combo-noedit',
15013 autocomplete: 'new-password',
15014 placeholder : this.placeholder || '',
15019 input.name = this.name;
15023 input.cls += ' input-' + this.size;
15026 if (this.disabled) {
15027 input.disabled = true;
15038 inputblock.cls += ' input-group';
15040 inputblock.cn.unshift({
15042 cls : 'input-group-addon',
15047 if(this.removable && !this.multiple){
15048 inputblock.cls += ' roo-removable';
15050 inputblock.cn.push({
15053 cls : 'roo-combo-removable-btn close'
15057 if(this.hasFeedback && !this.allowBlank){
15059 inputblock.cls += ' has-feedback';
15061 inputblock.cn.push({
15063 cls: 'glyphicon form-control-feedback'
15070 inputblock.cls += (this.before) ? '' : ' input-group';
15072 inputblock.cn.push({
15074 cls : 'input-group-addon',
15085 cls: 'form-hidden-field'
15099 cls: 'form-hidden-field'
15103 cls: 'roo-select2-choices',
15107 cls: 'roo-select2-search-field',
15120 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15126 if(!this.multiple && this.showToggleBtn){
15133 if (this.caret != false) {
15136 cls: 'fa fa-' + this.caret
15143 cls : 'input-group-addon btn dropdown-toggle',
15148 cls: 'combobox-clear',
15162 combobox.cls += ' roo-select2-container-multi';
15165 var align = this.labelAlign || this.parentLabelAlign();
15167 if (align ==='left' && this.fieldLabel.length) {
15172 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15173 tooltip : 'This field is required'
15177 cls : 'control-label',
15178 html : this.fieldLabel
15189 var labelCfg = cfg.cn[1];
15190 var contentCfg = cfg.cn[2];
15193 if(this.indicatorpos == 'right'){
15198 cls : 'control-label',
15202 html : this.fieldLabel
15206 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15207 tooltip : 'This field is required'
15220 labelCfg = cfg.cn[0];
15221 contentCfg = cfg.cn[1];
15226 if(this.labelWidth > 12){
15227 labelCfg.style = "width: " + this.labelWidth + 'px';
15230 if(this.labelWidth < 13 && this.labelmd == 0){
15231 this.labelmd = this.labelWidth;
15234 if(this.labellg > 0){
15235 labelCfg.cls += ' col-lg-' + this.labellg;
15236 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15239 if(this.labelmd > 0){
15240 labelCfg.cls += ' col-md-' + this.labelmd;
15241 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15244 if(this.labelsm > 0){
15245 labelCfg.cls += ' col-sm-' + this.labelsm;
15246 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15249 if(this.labelxs > 0){
15250 labelCfg.cls += ' col-xs-' + this.labelxs;
15251 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15255 } else if ( this.fieldLabel.length) {
15259 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15260 tooltip : 'This field is required'
15264 cls : 'control-label',
15265 html : this.fieldLabel
15276 if(this.indicatorpos == 'right'){
15280 cls : 'control-label',
15281 html : this.fieldLabel,
15285 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15286 tooltip : 'This field is required'
15303 var settings = this;
15305 ['xs','sm','md','lg'].map(function(size){
15306 if (settings[size]) {
15307 cfg.cls += ' col-' + size + '-' + settings[size];
15314 initTouchView : function()
15316 this.renderTouchView();
15318 this.touchViewEl.on('scroll', function(){
15319 this.el.dom.scrollTop = 0;
15322 this.originalValue = this.getValue();
15324 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15326 this.inputEl().on("click", this.showTouchView, this);
15327 if (this.triggerEl) {
15328 this.triggerEl.on("click", this.showTouchView, this);
15332 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15333 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15335 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15337 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15338 this.store.on('load', this.onTouchViewLoad, this);
15339 this.store.on('loadexception', this.onTouchViewLoadException, this);
15341 if(this.hiddenName){
15343 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15345 this.hiddenField.dom.value =
15346 this.hiddenValue !== undefined ? this.hiddenValue :
15347 this.value !== undefined ? this.value : '';
15349 this.el.dom.removeAttribute('name');
15350 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15354 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15355 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15358 if(this.removable && !this.multiple){
15359 var close = this.closeTriggerEl();
15361 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15362 close.on('click', this.removeBtnClick, this, close);
15366 * fix the bug in Safari iOS8
15368 this.inputEl().on("focus", function(e){
15369 document.activeElement.blur();
15372 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15379 renderTouchView : function()
15381 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15382 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15384 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15385 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15387 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15388 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15389 this.touchViewBodyEl.setStyle('overflow', 'auto');
15391 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15392 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15394 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15395 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15399 showTouchView : function()
15405 this.touchViewHeaderEl.hide();
15407 if(this.modalTitle.length){
15408 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15409 this.touchViewHeaderEl.show();
15412 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15413 this.touchViewEl.show();
15415 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15417 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15418 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15420 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15422 if(this.modalTitle.length){
15423 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15426 this.touchViewBodyEl.setHeight(bodyHeight);
15430 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15432 this.touchViewEl.addClass('in');
15435 if(this._touchViewMask){
15436 Roo.get(document.body).addClass("x-body-masked");
15437 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15438 this._touchViewMask.setStyle('z-index', 10000);
15439 this._touchViewMask.addClass('show');
15442 this.doTouchViewQuery();
15446 hideTouchView : function()
15448 this.touchViewEl.removeClass('in');
15452 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15454 this.touchViewEl.setStyle('display', 'none');
15457 if(this._touchViewMask){
15458 this._touchViewMask.removeClass('show');
15459 Roo.get(document.body).removeClass("x-body-masked");
15463 setTouchViewValue : function()
15470 Roo.each(this.tickItems, function(o){
15475 this.hideTouchView();
15478 doTouchViewQuery : function()
15487 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15491 if(!this.alwaysQuery || this.mode == 'local'){
15492 this.onTouchViewLoad();
15499 onTouchViewBeforeLoad : function(combo,opts)
15505 onTouchViewLoad : function()
15507 if(this.store.getCount() < 1){
15508 this.onTouchViewEmptyResults();
15512 this.clearTouchView();
15514 var rawValue = this.getRawValue();
15516 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15518 this.tickItems = [];
15520 this.store.data.each(function(d, rowIndex){
15521 var row = this.touchViewListGroup.createChild(template);
15523 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15524 row.addClass(d.data.cls);
15527 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15530 html : d.data[this.displayField]
15533 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15534 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15537 row.removeClass('selected');
15538 if(!this.multiple && this.valueField &&
15539 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15542 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15543 row.addClass('selected');
15546 if(this.multiple && this.valueField &&
15547 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15551 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15552 this.tickItems.push(d.data);
15555 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15559 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15561 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15563 if(this.modalTitle.length){
15564 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15567 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15569 if(this.mobile_restrict_height && listHeight < bodyHeight){
15570 this.touchViewBodyEl.setHeight(listHeight);
15575 if(firstChecked && listHeight > bodyHeight){
15576 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15581 onTouchViewLoadException : function()
15583 this.hideTouchView();
15586 onTouchViewEmptyResults : function()
15588 this.clearTouchView();
15590 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15592 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15596 clearTouchView : function()
15598 this.touchViewListGroup.dom.innerHTML = '';
15601 onTouchViewClick : function(e, el, o)
15603 e.preventDefault();
15606 var rowIndex = o.rowIndex;
15608 var r = this.store.getAt(rowIndex);
15610 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15612 if(!this.multiple){
15613 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15614 c.dom.removeAttribute('checked');
15617 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15619 this.setFromData(r.data);
15621 var close = this.closeTriggerEl();
15627 this.hideTouchView();
15629 this.fireEvent('select', this, r, rowIndex);
15634 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15635 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15636 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15640 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15641 this.addItem(r.data);
15642 this.tickItems.push(r.data);
15646 getAutoCreateNativeIOS : function()
15649 cls: 'form-group' //input-group,
15654 cls : 'roo-ios-select'
15658 combobox.name = this.name;
15661 if (this.disabled) {
15662 combobox.disabled = true;
15665 var settings = this;
15667 ['xs','sm','md','lg'].map(function(size){
15668 if (settings[size]) {
15669 cfg.cls += ' col-' + size + '-' + settings[size];
15679 initIOSView : function()
15681 this.store.on('load', this.onIOSViewLoad, this);
15686 onIOSViewLoad : function()
15688 if(this.store.getCount() < 1){
15692 this.clearIOSView();
15694 if(this.allowBlank) {
15696 var default_text = '-- SELECT --';
15698 if(this.placeholder.length){
15699 default_text = this.placeholder;
15702 if(this.emptyTitle.length){
15703 default_text += ' - ' + this.emptyTitle + ' -';
15706 var opt = this.inputEl().createChild({
15709 html : default_text
15713 o[this.valueField] = 0;
15714 o[this.displayField] = default_text;
15716 this.ios_options.push({
15723 this.store.data.each(function(d, rowIndex){
15727 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15728 html = d.data[this.displayField];
15733 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15734 value = d.data[this.valueField];
15743 if(this.value == d.data[this.valueField]){
15744 option['selected'] = true;
15747 var opt = this.inputEl().createChild(option);
15749 this.ios_options.push({
15756 this.inputEl().on('change', function(){
15757 this.fireEvent('select', this);
15762 clearIOSView: function()
15764 this.inputEl().dom.innerHTML = '';
15766 this.ios_options = [];
15769 setIOSValue: function(v)
15773 if(!this.ios_options){
15777 Roo.each(this.ios_options, function(opts){
15779 opts.el.dom.removeAttribute('selected');
15781 if(opts.data[this.valueField] != v){
15785 opts.el.dom.setAttribute('selected', true);
15791 * @cfg {Boolean} grow
15795 * @cfg {Number} growMin
15799 * @cfg {Number} growMax
15808 Roo.apply(Roo.bootstrap.ComboBox, {
15812 cls: 'modal-header',
15834 cls: 'list-group-item',
15838 cls: 'roo-combobox-list-group-item-value'
15842 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15856 listItemCheckbox : {
15858 cls: 'list-group-item',
15862 cls: 'roo-combobox-list-group-item-value'
15866 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15882 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15887 cls: 'modal-footer',
15895 cls: 'col-xs-6 text-left',
15898 cls: 'btn btn-danger roo-touch-view-cancel',
15904 cls: 'col-xs-6 text-right',
15907 cls: 'btn btn-success roo-touch-view-ok',
15918 Roo.apply(Roo.bootstrap.ComboBox, {
15920 touchViewTemplate : {
15922 cls: 'modal fade roo-combobox-touch-view',
15926 cls: 'modal-dialog',
15927 style : 'position:fixed', // we have to fix position....
15931 cls: 'modal-content',
15933 Roo.bootstrap.ComboBox.header,
15934 Roo.bootstrap.ComboBox.body,
15935 Roo.bootstrap.ComboBox.footer
15944 * Ext JS Library 1.1.1
15945 * Copyright(c) 2006-2007, Ext JS, LLC.
15947 * Originally Released Under LGPL - original licence link has changed is not relivant.
15950 * <script type="text/javascript">
15955 * @extends Roo.util.Observable
15956 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15957 * This class also supports single and multi selection modes. <br>
15958 * Create a data model bound view:
15960 var store = new Roo.data.Store(...);
15962 var view = new Roo.View({
15964 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15966 singleSelect: true,
15967 selectedClass: "ydataview-selected",
15971 // listen for node click?
15972 view.on("click", function(vw, index, node, e){
15973 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15977 dataModel.load("foobar.xml");
15979 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15981 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15982 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15984 * Note: old style constructor is still suported (container, template, config)
15987 * Create a new View
15988 * @param {Object} config The config object
15991 Roo.View = function(config, depreciated_tpl, depreciated_config){
15993 this.parent = false;
15995 if (typeof(depreciated_tpl) == 'undefined') {
15996 // new way.. - universal constructor.
15997 Roo.apply(this, config);
15998 this.el = Roo.get(this.el);
16001 this.el = Roo.get(config);
16002 this.tpl = depreciated_tpl;
16003 Roo.apply(this, depreciated_config);
16005 this.wrapEl = this.el.wrap().wrap();
16006 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16009 if(typeof(this.tpl) == "string"){
16010 this.tpl = new Roo.Template(this.tpl);
16012 // support xtype ctors..
16013 this.tpl = new Roo.factory(this.tpl, Roo);
16017 this.tpl.compile();
16022 * @event beforeclick
16023 * Fires before a click is processed. Returns false to cancel the default action.
16024 * @param {Roo.View} this
16025 * @param {Number} index The index of the target node
16026 * @param {HTMLElement} node The target node
16027 * @param {Roo.EventObject} e The raw event object
16029 "beforeclick" : true,
16032 * Fires when a template node is clicked.
16033 * @param {Roo.View} this
16034 * @param {Number} index The index of the target node
16035 * @param {HTMLElement} node The target node
16036 * @param {Roo.EventObject} e The raw event object
16041 * Fires when a template node is double clicked.
16042 * @param {Roo.View} this
16043 * @param {Number} index The index of the target node
16044 * @param {HTMLElement} node The target node
16045 * @param {Roo.EventObject} e The raw event object
16049 * @event contextmenu
16050 * Fires when a template node is right clicked.
16051 * @param {Roo.View} this
16052 * @param {Number} index The index of the target node
16053 * @param {HTMLElement} node The target node
16054 * @param {Roo.EventObject} e The raw event object
16056 "contextmenu" : true,
16058 * @event selectionchange
16059 * Fires when the selected nodes change.
16060 * @param {Roo.View} this
16061 * @param {Array} selections Array of the selected nodes
16063 "selectionchange" : true,
16066 * @event beforeselect
16067 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16068 * @param {Roo.View} this
16069 * @param {HTMLElement} node The node to be selected
16070 * @param {Array} selections Array of currently selected nodes
16072 "beforeselect" : true,
16074 * @event preparedata
16075 * Fires on every row to render, to allow you to change the data.
16076 * @param {Roo.View} this
16077 * @param {Object} data to be rendered (change this)
16079 "preparedata" : true
16087 "click": this.onClick,
16088 "dblclick": this.onDblClick,
16089 "contextmenu": this.onContextMenu,
16093 this.selections = [];
16095 this.cmp = new Roo.CompositeElementLite([]);
16097 this.store = Roo.factory(this.store, Roo.data);
16098 this.setStore(this.store, true);
16101 if ( this.footer && this.footer.xtype) {
16103 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16105 this.footer.dataSource = this.store;
16106 this.footer.container = fctr;
16107 this.footer = Roo.factory(this.footer, Roo);
16108 fctr.insertFirst(this.el);
16110 // this is a bit insane - as the paging toolbar seems to detach the el..
16111 // dom.parentNode.parentNode.parentNode
16112 // they get detached?
16116 Roo.View.superclass.constructor.call(this);
16121 Roo.extend(Roo.View, Roo.util.Observable, {
16124 * @cfg {Roo.data.Store} store Data store to load data from.
16129 * @cfg {String|Roo.Element} el The container element.
16134 * @cfg {String|Roo.Template} tpl The template used by this View
16138 * @cfg {String} dataName the named area of the template to use as the data area
16139 * Works with domtemplates roo-name="name"
16143 * @cfg {String} selectedClass The css class to add to selected nodes
16145 selectedClass : "x-view-selected",
16147 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16152 * @cfg {String} text to display on mask (default Loading)
16156 * @cfg {Boolean} multiSelect Allow multiple selection
16158 multiSelect : false,
16160 * @cfg {Boolean} singleSelect Allow single selection
16162 singleSelect: false,
16165 * @cfg {Boolean} toggleSelect - selecting
16167 toggleSelect : false,
16170 * @cfg {Boolean} tickable - selecting
16175 * Returns the element this view is bound to.
16176 * @return {Roo.Element}
16178 getEl : function(){
16179 return this.wrapEl;
16185 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16187 refresh : function(){
16188 //Roo.log('refresh');
16191 // if we are using something like 'domtemplate', then
16192 // the what gets used is:
16193 // t.applySubtemplate(NAME, data, wrapping data..)
16194 // the outer template then get' applied with
16195 // the store 'extra data'
16196 // and the body get's added to the
16197 // roo-name="data" node?
16198 // <span class='roo-tpl-{name}'></span> ?????
16202 this.clearSelections();
16203 this.el.update("");
16205 var records = this.store.getRange();
16206 if(records.length < 1) {
16208 // is this valid?? = should it render a template??
16210 this.el.update(this.emptyText);
16214 if (this.dataName) {
16215 this.el.update(t.apply(this.store.meta)); //????
16216 el = this.el.child('.roo-tpl-' + this.dataName);
16219 for(var i = 0, len = records.length; i < len; i++){
16220 var data = this.prepareData(records[i].data, i, records[i]);
16221 this.fireEvent("preparedata", this, data, i, records[i]);
16223 var d = Roo.apply({}, data);
16226 Roo.apply(d, {'roo-id' : Roo.id()});
16230 Roo.each(this.parent.item, function(item){
16231 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16234 Roo.apply(d, {'roo-data-checked' : 'checked'});
16238 html[html.length] = Roo.util.Format.trim(
16240 t.applySubtemplate(this.dataName, d, this.store.meta) :
16247 el.update(html.join(""));
16248 this.nodes = el.dom.childNodes;
16249 this.updateIndexes(0);
16254 * Function to override to reformat the data that is sent to
16255 * the template for each node.
16256 * DEPRICATED - use the preparedata event handler.
16257 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16258 * a JSON object for an UpdateManager bound view).
16260 prepareData : function(data, index, record)
16262 this.fireEvent("preparedata", this, data, index, record);
16266 onUpdate : function(ds, record){
16267 // Roo.log('on update');
16268 this.clearSelections();
16269 var index = this.store.indexOf(record);
16270 var n = this.nodes[index];
16271 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16272 n.parentNode.removeChild(n);
16273 this.updateIndexes(index, index);
16279 onAdd : function(ds, records, index)
16281 //Roo.log(['on Add', ds, records, index] );
16282 this.clearSelections();
16283 if(this.nodes.length == 0){
16287 var n = this.nodes[index];
16288 for(var i = 0, len = records.length; i < len; i++){
16289 var d = this.prepareData(records[i].data, i, records[i]);
16291 this.tpl.insertBefore(n, d);
16294 this.tpl.append(this.el, d);
16297 this.updateIndexes(index);
16300 onRemove : function(ds, record, index){
16301 // Roo.log('onRemove');
16302 this.clearSelections();
16303 var el = this.dataName ?
16304 this.el.child('.roo-tpl-' + this.dataName) :
16307 el.dom.removeChild(this.nodes[index]);
16308 this.updateIndexes(index);
16312 * Refresh an individual node.
16313 * @param {Number} index
16315 refreshNode : function(index){
16316 this.onUpdate(this.store, this.store.getAt(index));
16319 updateIndexes : function(startIndex, endIndex){
16320 var ns = this.nodes;
16321 startIndex = startIndex || 0;
16322 endIndex = endIndex || ns.length - 1;
16323 for(var i = startIndex; i <= endIndex; i++){
16324 ns[i].nodeIndex = i;
16329 * Changes the data store this view uses and refresh the view.
16330 * @param {Store} store
16332 setStore : function(store, initial){
16333 if(!initial && this.store){
16334 this.store.un("datachanged", this.refresh);
16335 this.store.un("add", this.onAdd);
16336 this.store.un("remove", this.onRemove);
16337 this.store.un("update", this.onUpdate);
16338 this.store.un("clear", this.refresh);
16339 this.store.un("beforeload", this.onBeforeLoad);
16340 this.store.un("load", this.onLoad);
16341 this.store.un("loadexception", this.onLoad);
16345 store.on("datachanged", this.refresh, this);
16346 store.on("add", this.onAdd, this);
16347 store.on("remove", this.onRemove, this);
16348 store.on("update", this.onUpdate, this);
16349 store.on("clear", this.refresh, this);
16350 store.on("beforeload", this.onBeforeLoad, this);
16351 store.on("load", this.onLoad, this);
16352 store.on("loadexception", this.onLoad, this);
16360 * onbeforeLoad - masks the loading area.
16363 onBeforeLoad : function(store,opts)
16365 //Roo.log('onBeforeLoad');
16367 this.el.update("");
16369 this.el.mask(this.mask ? this.mask : "Loading" );
16371 onLoad : function ()
16378 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16379 * @param {HTMLElement} node
16380 * @return {HTMLElement} The template node
16382 findItemFromChild : function(node){
16383 var el = this.dataName ?
16384 this.el.child('.roo-tpl-' + this.dataName,true) :
16387 if(!node || node.parentNode == el){
16390 var p = node.parentNode;
16391 while(p && p != el){
16392 if(p.parentNode == el){
16401 onClick : function(e){
16402 var item = this.findItemFromChild(e.getTarget());
16404 var index = this.indexOf(item);
16405 if(this.onItemClick(item, index, e) !== false){
16406 this.fireEvent("click", this, index, item, e);
16409 this.clearSelections();
16414 onContextMenu : function(e){
16415 var item = this.findItemFromChild(e.getTarget());
16417 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16422 onDblClick : function(e){
16423 var item = this.findItemFromChild(e.getTarget());
16425 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16429 onItemClick : function(item, index, e)
16431 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16434 if (this.toggleSelect) {
16435 var m = this.isSelected(item) ? 'unselect' : 'select';
16438 _t[m](item, true, false);
16441 if(this.multiSelect || this.singleSelect){
16442 if(this.multiSelect && e.shiftKey && this.lastSelection){
16443 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16445 this.select(item, this.multiSelect && e.ctrlKey);
16446 this.lastSelection = item;
16449 if(!this.tickable){
16450 e.preventDefault();
16458 * Get the number of selected nodes.
16461 getSelectionCount : function(){
16462 return this.selections.length;
16466 * Get the currently selected nodes.
16467 * @return {Array} An array of HTMLElements
16469 getSelectedNodes : function(){
16470 return this.selections;
16474 * Get the indexes of the selected nodes.
16477 getSelectedIndexes : function(){
16478 var indexes = [], s = this.selections;
16479 for(var i = 0, len = s.length; i < len; i++){
16480 indexes.push(s[i].nodeIndex);
16486 * Clear all selections
16487 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16489 clearSelections : function(suppressEvent){
16490 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16491 this.cmp.elements = this.selections;
16492 this.cmp.removeClass(this.selectedClass);
16493 this.selections = [];
16494 if(!suppressEvent){
16495 this.fireEvent("selectionchange", this, this.selections);
16501 * Returns true if the passed node is selected
16502 * @param {HTMLElement/Number} node The node or node index
16503 * @return {Boolean}
16505 isSelected : function(node){
16506 var s = this.selections;
16510 node = this.getNode(node);
16511 return s.indexOf(node) !== -1;
16516 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16517 * @param {Boolean} keepExisting (optional) true to keep existing selections
16518 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16520 select : function(nodeInfo, keepExisting, suppressEvent){
16521 if(nodeInfo instanceof Array){
16523 this.clearSelections(true);
16525 for(var i = 0, len = nodeInfo.length; i < len; i++){
16526 this.select(nodeInfo[i], true, true);
16530 var node = this.getNode(nodeInfo);
16531 if(!node || this.isSelected(node)){
16532 return; // already selected.
16535 this.clearSelections(true);
16538 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16539 Roo.fly(node).addClass(this.selectedClass);
16540 this.selections.push(node);
16541 if(!suppressEvent){
16542 this.fireEvent("selectionchange", this, this.selections);
16550 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16551 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16552 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16554 unselect : function(nodeInfo, keepExisting, suppressEvent)
16556 if(nodeInfo instanceof Array){
16557 Roo.each(this.selections, function(s) {
16558 this.unselect(s, nodeInfo);
16562 var node = this.getNode(nodeInfo);
16563 if(!node || !this.isSelected(node)){
16564 //Roo.log("not selected");
16565 return; // not selected.
16569 Roo.each(this.selections, function(s) {
16571 Roo.fly(node).removeClass(this.selectedClass);
16578 this.selections= ns;
16579 this.fireEvent("selectionchange", this, this.selections);
16583 * Gets a template node.
16584 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16585 * @return {HTMLElement} The node or null if it wasn't found
16587 getNode : function(nodeInfo){
16588 if(typeof nodeInfo == "string"){
16589 return document.getElementById(nodeInfo);
16590 }else if(typeof nodeInfo == "number"){
16591 return this.nodes[nodeInfo];
16597 * Gets a range template nodes.
16598 * @param {Number} startIndex
16599 * @param {Number} endIndex
16600 * @return {Array} An array of nodes
16602 getNodes : function(start, end){
16603 var ns = this.nodes;
16604 start = start || 0;
16605 end = typeof end == "undefined" ? ns.length - 1 : end;
16608 for(var i = start; i <= end; i++){
16612 for(var i = start; i >= end; i--){
16620 * Finds the index of the passed node
16621 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16622 * @return {Number} The index of the node or -1
16624 indexOf : function(node){
16625 node = this.getNode(node);
16626 if(typeof node.nodeIndex == "number"){
16627 return node.nodeIndex;
16629 var ns = this.nodes;
16630 for(var i = 0, len = ns.length; i < len; i++){
16641 * based on jquery fullcalendar
16645 Roo.bootstrap = Roo.bootstrap || {};
16647 * @class Roo.bootstrap.Calendar
16648 * @extends Roo.bootstrap.Component
16649 * Bootstrap Calendar class
16650 * @cfg {Boolean} loadMask (true|false) default false
16651 * @cfg {Object} header generate the user specific header of the calendar, default false
16654 * Create a new Container
16655 * @param {Object} config The config object
16660 Roo.bootstrap.Calendar = function(config){
16661 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16665 * Fires when a date is selected
16666 * @param {DatePicker} this
16667 * @param {Date} date The selected date
16671 * @event monthchange
16672 * Fires when the displayed month changes
16673 * @param {DatePicker} this
16674 * @param {Date} date The selected month
16676 'monthchange': true,
16678 * @event evententer
16679 * Fires when mouse over an event
16680 * @param {Calendar} this
16681 * @param {event} Event
16683 'evententer': true,
16685 * @event eventleave
16686 * Fires when the mouse leaves an
16687 * @param {Calendar} this
16690 'eventleave': true,
16692 * @event eventclick
16693 * Fires when the mouse click an
16694 * @param {Calendar} this
16703 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16706 * @cfg {Number} startDay
16707 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16715 getAutoCreate : function(){
16718 var fc_button = function(name, corner, style, content ) {
16719 return Roo.apply({},{
16721 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16723 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16726 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16737 style : 'width:100%',
16744 cls : 'fc-header-left',
16746 fc_button('prev', 'left', 'arrow', '‹' ),
16747 fc_button('next', 'right', 'arrow', '›' ),
16748 { tag: 'span', cls: 'fc-header-space' },
16749 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16757 cls : 'fc-header-center',
16761 cls: 'fc-header-title',
16764 html : 'month / year'
16772 cls : 'fc-header-right',
16774 /* fc_button('month', 'left', '', 'month' ),
16775 fc_button('week', '', '', 'week' ),
16776 fc_button('day', 'right', '', 'day' )
16788 header = this.header;
16791 var cal_heads = function() {
16793 // fixme - handle this.
16795 for (var i =0; i < Date.dayNames.length; i++) {
16796 var d = Date.dayNames[i];
16799 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16800 html : d.substring(0,3)
16804 ret[0].cls += ' fc-first';
16805 ret[6].cls += ' fc-last';
16808 var cal_cell = function(n) {
16811 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16816 cls: 'fc-day-number',
16820 cls: 'fc-day-content',
16824 style: 'position: relative;' // height: 17px;
16836 var cal_rows = function() {
16839 for (var r = 0; r < 6; r++) {
16846 for (var i =0; i < Date.dayNames.length; i++) {
16847 var d = Date.dayNames[i];
16848 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16851 row.cn[0].cls+=' fc-first';
16852 row.cn[0].cn[0].style = 'min-height:90px';
16853 row.cn[6].cls+=' fc-last';
16857 ret[0].cls += ' fc-first';
16858 ret[4].cls += ' fc-prev-last';
16859 ret[5].cls += ' fc-last';
16866 cls: 'fc-border-separate',
16867 style : 'width:100%',
16875 cls : 'fc-first fc-last',
16893 cls : 'fc-content',
16894 style : "position: relative;",
16897 cls : 'fc-view fc-view-month fc-grid',
16898 style : 'position: relative',
16899 unselectable : 'on',
16902 cls : 'fc-event-container',
16903 style : 'position:absolute;z-index:8;top:0;left:0;'
16921 initEvents : function()
16924 throw "can not find store for calendar";
16930 style: "text-align:center",
16934 style: "background-color:white;width:50%;margin:250 auto",
16938 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16949 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16951 var size = this.el.select('.fc-content', true).first().getSize();
16952 this.maskEl.setSize(size.width, size.height);
16953 this.maskEl.enableDisplayMode("block");
16954 if(!this.loadMask){
16955 this.maskEl.hide();
16958 this.store = Roo.factory(this.store, Roo.data);
16959 this.store.on('load', this.onLoad, this);
16960 this.store.on('beforeload', this.onBeforeLoad, this);
16964 this.cells = this.el.select('.fc-day',true);
16965 //Roo.log(this.cells);
16966 this.textNodes = this.el.query('.fc-day-number');
16967 this.cells.addClassOnOver('fc-state-hover');
16969 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16970 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16971 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16972 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16974 this.on('monthchange', this.onMonthChange, this);
16976 this.update(new Date().clearTime());
16979 resize : function() {
16980 var sz = this.el.getSize();
16982 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16983 this.el.select('.fc-day-content div',true).setHeight(34);
16988 showPrevMonth : function(e){
16989 this.update(this.activeDate.add("mo", -1));
16991 showToday : function(e){
16992 this.update(new Date().clearTime());
16995 showNextMonth : function(e){
16996 this.update(this.activeDate.add("mo", 1));
17000 showPrevYear : function(){
17001 this.update(this.activeDate.add("y", -1));
17005 showNextYear : function(){
17006 this.update(this.activeDate.add("y", 1));
17011 update : function(date)
17013 var vd = this.activeDate;
17014 this.activeDate = date;
17015 // if(vd && this.el){
17016 // var t = date.getTime();
17017 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17018 // Roo.log('using add remove');
17020 // this.fireEvent('monthchange', this, date);
17022 // this.cells.removeClass("fc-state-highlight");
17023 // this.cells.each(function(c){
17024 // if(c.dateValue == t){
17025 // c.addClass("fc-state-highlight");
17026 // setTimeout(function(){
17027 // try{c.dom.firstChild.focus();}catch(e){}
17037 var days = date.getDaysInMonth();
17039 var firstOfMonth = date.getFirstDateOfMonth();
17040 var startingPos = firstOfMonth.getDay()-this.startDay;
17042 if(startingPos < this.startDay){
17046 var pm = date.add(Date.MONTH, -1);
17047 var prevStart = pm.getDaysInMonth()-startingPos;
17049 this.cells = this.el.select('.fc-day',true);
17050 this.textNodes = this.el.query('.fc-day-number');
17051 this.cells.addClassOnOver('fc-state-hover');
17053 var cells = this.cells.elements;
17054 var textEls = this.textNodes;
17056 Roo.each(cells, function(cell){
17057 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17060 days += startingPos;
17062 // convert everything to numbers so it's fast
17063 var day = 86400000;
17064 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17067 //Roo.log(prevStart);
17069 var today = new Date().clearTime().getTime();
17070 var sel = date.clearTime().getTime();
17071 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17072 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17073 var ddMatch = this.disabledDatesRE;
17074 var ddText = this.disabledDatesText;
17075 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17076 var ddaysText = this.disabledDaysText;
17077 var format = this.format;
17079 var setCellClass = function(cal, cell){
17083 //Roo.log('set Cell Class');
17085 var t = d.getTime();
17089 cell.dateValue = t;
17091 cell.className += " fc-today";
17092 cell.className += " fc-state-highlight";
17093 cell.title = cal.todayText;
17096 // disable highlight in other month..
17097 //cell.className += " fc-state-highlight";
17102 cell.className = " fc-state-disabled";
17103 cell.title = cal.minText;
17107 cell.className = " fc-state-disabled";
17108 cell.title = cal.maxText;
17112 if(ddays.indexOf(d.getDay()) != -1){
17113 cell.title = ddaysText;
17114 cell.className = " fc-state-disabled";
17117 if(ddMatch && format){
17118 var fvalue = d.dateFormat(format);
17119 if(ddMatch.test(fvalue)){
17120 cell.title = ddText.replace("%0", fvalue);
17121 cell.className = " fc-state-disabled";
17125 if (!cell.initialClassName) {
17126 cell.initialClassName = cell.dom.className;
17129 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17134 for(; i < startingPos; i++) {
17135 textEls[i].innerHTML = (++prevStart);
17136 d.setDate(d.getDate()+1);
17138 cells[i].className = "fc-past fc-other-month";
17139 setCellClass(this, cells[i]);
17144 for(; i < days; i++){
17145 intDay = i - startingPos + 1;
17146 textEls[i].innerHTML = (intDay);
17147 d.setDate(d.getDate()+1);
17149 cells[i].className = ''; // "x-date-active";
17150 setCellClass(this, cells[i]);
17154 for(; i < 42; i++) {
17155 textEls[i].innerHTML = (++extraDays);
17156 d.setDate(d.getDate()+1);
17158 cells[i].className = "fc-future fc-other-month";
17159 setCellClass(this, cells[i]);
17162 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17164 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17166 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17167 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17169 if(totalRows != 6){
17170 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17171 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17174 this.fireEvent('monthchange', this, date);
17178 if(!this.internalRender){
17179 var main = this.el.dom.firstChild;
17180 var w = main.offsetWidth;
17181 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17182 Roo.fly(main).setWidth(w);
17183 this.internalRender = true;
17184 // opera does not respect the auto grow header center column
17185 // then, after it gets a width opera refuses to recalculate
17186 // without a second pass
17187 if(Roo.isOpera && !this.secondPass){
17188 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17189 this.secondPass = true;
17190 this.update.defer(10, this, [date]);
17197 findCell : function(dt) {
17198 dt = dt.clearTime().getTime();
17200 this.cells.each(function(c){
17201 //Roo.log("check " +c.dateValue + '?=' + dt);
17202 if(c.dateValue == dt){
17212 findCells : function(ev) {
17213 var s = ev.start.clone().clearTime().getTime();
17215 var e= ev.end.clone().clearTime().getTime();
17218 this.cells.each(function(c){
17219 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17221 if(c.dateValue > e){
17224 if(c.dateValue < s){
17233 // findBestRow: function(cells)
17237 // for (var i =0 ; i < cells.length;i++) {
17238 // ret = Math.max(cells[i].rows || 0,ret);
17245 addItem : function(ev)
17247 // look for vertical location slot in
17248 var cells = this.findCells(ev);
17250 // ev.row = this.findBestRow(cells);
17252 // work out the location.
17256 for(var i =0; i < cells.length; i++) {
17258 cells[i].row = cells[0].row;
17261 cells[i].row = cells[i].row + 1;
17271 if (crow.start.getY() == cells[i].getY()) {
17273 crow.end = cells[i];
17290 cells[0].events.push(ev);
17292 this.calevents.push(ev);
17295 clearEvents: function() {
17297 if(!this.calevents){
17301 Roo.each(this.cells.elements, function(c){
17307 Roo.each(this.calevents, function(e) {
17308 Roo.each(e.els, function(el) {
17309 el.un('mouseenter' ,this.onEventEnter, this);
17310 el.un('mouseleave' ,this.onEventLeave, this);
17315 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17321 renderEvents: function()
17325 this.cells.each(function(c) {
17334 if(c.row != c.events.length){
17335 r = 4 - (4 - (c.row - c.events.length));
17338 c.events = ev.slice(0, r);
17339 c.more = ev.slice(r);
17341 if(c.more.length && c.more.length == 1){
17342 c.events.push(c.more.pop());
17345 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17349 this.cells.each(function(c) {
17351 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17354 for (var e = 0; e < c.events.length; e++){
17355 var ev = c.events[e];
17356 var rows = ev.rows;
17358 for(var i = 0; i < rows.length; i++) {
17360 // how many rows should it span..
17363 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17364 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17366 unselectable : "on",
17369 cls: 'fc-event-inner',
17373 // cls: 'fc-event-time',
17374 // html : cells.length > 1 ? '' : ev.time
17378 cls: 'fc-event-title',
17379 html : String.format('{0}', ev.title)
17386 cls: 'ui-resizable-handle ui-resizable-e',
17387 html : '  '
17394 cfg.cls += ' fc-event-start';
17396 if ((i+1) == rows.length) {
17397 cfg.cls += ' fc-event-end';
17400 var ctr = _this.el.select('.fc-event-container',true).first();
17401 var cg = ctr.createChild(cfg);
17403 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17404 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17406 var r = (c.more.length) ? 1 : 0;
17407 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17408 cg.setWidth(ebox.right - sbox.x -2);
17410 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17411 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17412 cg.on('click', _this.onEventClick, _this, ev);
17423 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17424 style : 'position: absolute',
17425 unselectable : "on",
17428 cls: 'fc-event-inner',
17432 cls: 'fc-event-title',
17440 cls: 'ui-resizable-handle ui-resizable-e',
17441 html : '  '
17447 var ctr = _this.el.select('.fc-event-container',true).first();
17448 var cg = ctr.createChild(cfg);
17450 var sbox = c.select('.fc-day-content',true).first().getBox();
17451 var ebox = c.select('.fc-day-content',true).first().getBox();
17453 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17454 cg.setWidth(ebox.right - sbox.x -2);
17456 cg.on('click', _this.onMoreEventClick, _this, c.more);
17466 onEventEnter: function (e, el,event,d) {
17467 this.fireEvent('evententer', this, el, event);
17470 onEventLeave: function (e, el,event,d) {
17471 this.fireEvent('eventleave', this, el, event);
17474 onEventClick: function (e, el,event,d) {
17475 this.fireEvent('eventclick', this, el, event);
17478 onMonthChange: function () {
17482 onMoreEventClick: function(e, el, more)
17486 this.calpopover.placement = 'right';
17487 this.calpopover.setTitle('More');
17489 this.calpopover.setContent('');
17491 var ctr = this.calpopover.el.select('.popover-content', true).first();
17493 Roo.each(more, function(m){
17495 cls : 'fc-event-hori fc-event-draggable',
17498 var cg = ctr.createChild(cfg);
17500 cg.on('click', _this.onEventClick, _this, m);
17503 this.calpopover.show(el);
17508 onLoad: function ()
17510 this.calevents = [];
17513 if(this.store.getCount() > 0){
17514 this.store.data.each(function(d){
17517 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17518 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17519 time : d.data.start_time,
17520 title : d.data.title,
17521 description : d.data.description,
17522 venue : d.data.venue
17527 this.renderEvents();
17529 if(this.calevents.length && this.loadMask){
17530 this.maskEl.hide();
17534 onBeforeLoad: function()
17536 this.clearEvents();
17538 this.maskEl.show();
17552 * @class Roo.bootstrap.Popover
17553 * @extends Roo.bootstrap.Component
17554 * Bootstrap Popover class
17555 * @cfg {String} html contents of the popover (or false to use children..)
17556 * @cfg {String} title of popover (or false to hide)
17557 * @cfg {String} placement how it is placed
17558 * @cfg {String} trigger click || hover (or false to trigger manually)
17559 * @cfg {String} over what (parent or false to trigger manually.)
17560 * @cfg {Number} delay - delay before showing
17563 * Create a new Popover
17564 * @param {Object} config The config object
17567 Roo.bootstrap.Popover = function(config){
17568 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17574 * After the popover show
17576 * @param {Roo.bootstrap.Popover} this
17581 * After the popover hide
17583 * @param {Roo.bootstrap.Popover} this
17589 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17591 title: 'Fill in a title',
17594 placement : 'right',
17595 trigger : 'hover', // hover
17601 can_build_overlaid : false,
17603 getChildContainer : function()
17605 return this.el.select('.popover-content',true).first();
17608 getAutoCreate : function(){
17611 cls : 'popover roo-dynamic',
17612 style: 'display:block',
17618 cls : 'popover-inner',
17622 cls: 'popover-title',
17626 cls : 'popover-content',
17637 setTitle: function(str)
17640 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17642 setContent: function(str)
17645 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17647 // as it get's added to the bottom of the page.
17648 onRender : function(ct, position)
17650 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17652 var cfg = Roo.apply({}, this.getAutoCreate());
17656 cfg.cls += ' ' + this.cls;
17659 cfg.style = this.style;
17661 //Roo.log("adding to ");
17662 this.el = Roo.get(document.body).createChild(cfg, position);
17663 // Roo.log(this.el);
17668 initEvents : function()
17670 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17671 this.el.enableDisplayMode('block');
17673 if (this.over === false) {
17676 if (this.triggers === false) {
17679 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17680 var triggers = this.trigger ? this.trigger.split(' ') : [];
17681 Roo.each(triggers, function(trigger) {
17683 if (trigger == 'click') {
17684 on_el.on('click', this.toggle, this);
17685 } else if (trigger != 'manual') {
17686 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17687 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17689 on_el.on(eventIn ,this.enter, this);
17690 on_el.on(eventOut, this.leave, this);
17701 toggle : function () {
17702 this.hoverState == 'in' ? this.leave() : this.enter();
17705 enter : function () {
17707 clearTimeout(this.timeout);
17709 this.hoverState = 'in';
17711 if (!this.delay || !this.delay.show) {
17716 this.timeout = setTimeout(function () {
17717 if (_t.hoverState == 'in') {
17720 }, this.delay.show)
17723 leave : function() {
17724 clearTimeout(this.timeout);
17726 this.hoverState = 'out';
17728 if (!this.delay || !this.delay.hide) {
17733 this.timeout = setTimeout(function () {
17734 if (_t.hoverState == 'out') {
17737 }, this.delay.hide)
17740 show : function (on_el)
17743 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17747 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17748 if (this.html !== false) {
17749 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17751 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17752 if (!this.title.length) {
17753 this.el.select('.popover-title',true).hide();
17756 var placement = typeof this.placement == 'function' ?
17757 this.placement.call(this, this.el, on_el) :
17760 var autoToken = /\s?auto?\s?/i;
17761 var autoPlace = autoToken.test(placement);
17763 placement = placement.replace(autoToken, '') || 'top';
17767 //this.el.setXY([0,0]);
17769 this.el.dom.style.display='block';
17770 this.el.addClass(placement);
17772 //this.el.appendTo(on_el);
17774 var p = this.getPosition();
17775 var box = this.el.getBox();
17780 var align = Roo.bootstrap.Popover.alignment[placement];
17783 this.el.alignTo(on_el, align[0],align[1]);
17784 //var arrow = this.el.select('.arrow',true).first();
17785 //arrow.set(align[2],
17787 this.el.addClass('in');
17790 if (this.el.hasClass('fade')) {
17794 this.hoverState = 'in';
17796 this.fireEvent('show', this);
17801 this.el.setXY([0,0]);
17802 this.el.removeClass('in');
17804 this.hoverState = null;
17806 this.fireEvent('hide', this);
17811 Roo.bootstrap.Popover.alignment = {
17812 'left' : ['r-l', [-10,0], 'right'],
17813 'right' : ['l-r', [10,0], 'left'],
17814 'bottom' : ['t-b', [0,10], 'top'],
17815 'top' : [ 'b-t', [0,-10], 'bottom']
17826 * @class Roo.bootstrap.Progress
17827 * @extends Roo.bootstrap.Component
17828 * Bootstrap Progress class
17829 * @cfg {Boolean} striped striped of the progress bar
17830 * @cfg {Boolean} active animated of the progress bar
17834 * Create a new Progress
17835 * @param {Object} config The config object
17838 Roo.bootstrap.Progress = function(config){
17839 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17842 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17847 getAutoCreate : function(){
17855 cfg.cls += ' progress-striped';
17859 cfg.cls += ' active';
17878 * @class Roo.bootstrap.ProgressBar
17879 * @extends Roo.bootstrap.Component
17880 * Bootstrap ProgressBar class
17881 * @cfg {Number} aria_valuenow aria-value now
17882 * @cfg {Number} aria_valuemin aria-value min
17883 * @cfg {Number} aria_valuemax aria-value max
17884 * @cfg {String} label label for the progress bar
17885 * @cfg {String} panel (success | info | warning | danger )
17886 * @cfg {String} role role of the progress bar
17887 * @cfg {String} sr_only text
17891 * Create a new ProgressBar
17892 * @param {Object} config The config object
17895 Roo.bootstrap.ProgressBar = function(config){
17896 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17899 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17903 aria_valuemax : 100,
17909 getAutoCreate : function()
17914 cls: 'progress-bar',
17915 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17927 cfg.role = this.role;
17930 if(this.aria_valuenow){
17931 cfg['aria-valuenow'] = this.aria_valuenow;
17934 if(this.aria_valuemin){
17935 cfg['aria-valuemin'] = this.aria_valuemin;
17938 if(this.aria_valuemax){
17939 cfg['aria-valuemax'] = this.aria_valuemax;
17942 if(this.label && !this.sr_only){
17943 cfg.html = this.label;
17947 cfg.cls += ' progress-bar-' + this.panel;
17953 update : function(aria_valuenow)
17955 this.aria_valuenow = aria_valuenow;
17957 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17972 * @class Roo.bootstrap.TabGroup
17973 * @extends Roo.bootstrap.Column
17974 * Bootstrap Column class
17975 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17976 * @cfg {Boolean} carousel true to make the group behave like a carousel
17977 * @cfg {Boolean} bullets show bullets for the panels
17978 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17979 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17980 * @cfg {Boolean} showarrow (true|false) show arrow default true
17983 * Create a new TabGroup
17984 * @param {Object} config The config object
17987 Roo.bootstrap.TabGroup = function(config){
17988 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17990 this.navId = Roo.id();
17993 Roo.bootstrap.TabGroup.register(this);
17997 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18000 transition : false,
18005 slideOnTouch : false,
18008 getAutoCreate : function()
18010 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18012 cfg.cls += ' tab-content';
18014 if (this.carousel) {
18015 cfg.cls += ' carousel slide';
18018 cls : 'carousel-inner',
18022 if(this.bullets && !Roo.isTouch){
18025 cls : 'carousel-bullets',
18029 if(this.bullets_cls){
18030 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18037 cfg.cn[0].cn.push(bullets);
18040 if(this.showarrow){
18041 cfg.cn[0].cn.push({
18043 class : 'carousel-arrow',
18047 class : 'carousel-prev',
18051 class : 'fa fa-chevron-left'
18057 class : 'carousel-next',
18061 class : 'fa fa-chevron-right'
18074 initEvents: function()
18076 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18077 // this.el.on("touchstart", this.onTouchStart, this);
18080 if(this.autoslide){
18083 this.slideFn = window.setInterval(function() {
18084 _this.showPanelNext();
18088 if(this.showarrow){
18089 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18090 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18096 // onTouchStart : function(e, el, o)
18098 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18102 // this.showPanelNext();
18106 getChildContainer : function()
18108 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18112 * register a Navigation item
18113 * @param {Roo.bootstrap.NavItem} the navitem to add
18115 register : function(item)
18117 this.tabs.push( item);
18118 item.navId = this.navId; // not really needed..
18123 getActivePanel : function()
18126 Roo.each(this.tabs, function(t) {
18136 getPanelByName : function(n)
18139 Roo.each(this.tabs, function(t) {
18140 if (t.tabId == n) {
18148 indexOfPanel : function(p)
18151 Roo.each(this.tabs, function(t,i) {
18152 if (t.tabId == p.tabId) {
18161 * show a specific panel
18162 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18163 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18165 showPanel : function (pan)
18167 if(this.transition || typeof(pan) == 'undefined'){
18168 Roo.log("waiting for the transitionend");
18172 if (typeof(pan) == 'number') {
18173 pan = this.tabs[pan];
18176 if (typeof(pan) == 'string') {
18177 pan = this.getPanelByName(pan);
18180 var cur = this.getActivePanel();
18183 Roo.log('pan or acitve pan is undefined');
18187 if (pan.tabId == this.getActivePanel().tabId) {
18191 if (false === cur.fireEvent('beforedeactivate')) {
18195 if(this.bullets > 0 && !Roo.isTouch){
18196 this.setActiveBullet(this.indexOfPanel(pan));
18199 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18201 this.transition = true;
18202 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18203 var lr = dir == 'next' ? 'left' : 'right';
18204 pan.el.addClass(dir); // or prev
18205 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18206 cur.el.addClass(lr); // or right
18207 pan.el.addClass(lr);
18210 cur.el.on('transitionend', function() {
18211 Roo.log("trans end?");
18213 pan.el.removeClass([lr,dir]);
18214 pan.setActive(true);
18216 cur.el.removeClass([lr]);
18217 cur.setActive(false);
18219 _this.transition = false;
18221 }, this, { single: true } );
18226 cur.setActive(false);
18227 pan.setActive(true);
18232 showPanelNext : function()
18234 var i = this.indexOfPanel(this.getActivePanel());
18236 if (i >= this.tabs.length - 1 && !this.autoslide) {
18240 if (i >= this.tabs.length - 1 && this.autoslide) {
18244 this.showPanel(this.tabs[i+1]);
18247 showPanelPrev : function()
18249 var i = this.indexOfPanel(this.getActivePanel());
18251 if (i < 1 && !this.autoslide) {
18255 if (i < 1 && this.autoslide) {
18256 i = this.tabs.length;
18259 this.showPanel(this.tabs[i-1]);
18263 addBullet: function()
18265 if(!this.bullets || Roo.isTouch){
18268 var ctr = this.el.select('.carousel-bullets',true).first();
18269 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18270 var bullet = ctr.createChild({
18271 cls : 'bullet bullet-' + i
18272 },ctr.dom.lastChild);
18277 bullet.on('click', (function(e, el, o, ii, t){
18279 e.preventDefault();
18281 this.showPanel(ii);
18283 if(this.autoslide && this.slideFn){
18284 clearInterval(this.slideFn);
18285 this.slideFn = window.setInterval(function() {
18286 _this.showPanelNext();
18290 }).createDelegate(this, [i, bullet], true));
18295 setActiveBullet : function(i)
18301 Roo.each(this.el.select('.bullet', true).elements, function(el){
18302 el.removeClass('selected');
18305 var bullet = this.el.select('.bullet-' + i, true).first();
18311 bullet.addClass('selected');
18322 Roo.apply(Roo.bootstrap.TabGroup, {
18326 * register a Navigation Group
18327 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18329 register : function(navgrp)
18331 this.groups[navgrp.navId] = navgrp;
18335 * fetch a Navigation Group based on the navigation ID
18336 * if one does not exist , it will get created.
18337 * @param {string} the navgroup to add
18338 * @returns {Roo.bootstrap.NavGroup} the navgroup
18340 get: function(navId) {
18341 if (typeof(this.groups[navId]) == 'undefined') {
18342 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18344 return this.groups[navId] ;
18359 * @class Roo.bootstrap.TabPanel
18360 * @extends Roo.bootstrap.Component
18361 * Bootstrap TabPanel class
18362 * @cfg {Boolean} active panel active
18363 * @cfg {String} html panel content
18364 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18365 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18366 * @cfg {String} href click to link..
18370 * Create a new TabPanel
18371 * @param {Object} config The config object
18374 Roo.bootstrap.TabPanel = function(config){
18375 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18379 * Fires when the active status changes
18380 * @param {Roo.bootstrap.TabPanel} this
18381 * @param {Boolean} state the new state
18386 * @event beforedeactivate
18387 * Fires before a tab is de-activated - can be used to do validation on a form.
18388 * @param {Roo.bootstrap.TabPanel} this
18389 * @return {Boolean} false if there is an error
18392 'beforedeactivate': true
18395 this.tabId = this.tabId || Roo.id();
18399 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18407 getAutoCreate : function(){
18410 // item is needed for carousel - not sure if it has any effect otherwise
18411 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18412 html: this.html || ''
18416 cfg.cls += ' active';
18420 cfg.tabId = this.tabId;
18427 initEvents: function()
18429 var p = this.parent();
18431 this.navId = this.navId || p.navId;
18433 if (typeof(this.navId) != 'undefined') {
18434 // not really needed.. but just in case.. parent should be a NavGroup.
18435 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18439 var i = tg.tabs.length - 1;
18441 if(this.active && tg.bullets > 0 && i < tg.bullets){
18442 tg.setActiveBullet(i);
18446 this.el.on('click', this.onClick, this);
18449 this.el.on("touchstart", this.onTouchStart, this);
18450 this.el.on("touchmove", this.onTouchMove, this);
18451 this.el.on("touchend", this.onTouchEnd, this);
18456 onRender : function(ct, position)
18458 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18461 setActive : function(state)
18463 Roo.log("panel - set active " + this.tabId + "=" + state);
18465 this.active = state;
18467 this.el.removeClass('active');
18469 } else if (!this.el.hasClass('active')) {
18470 this.el.addClass('active');
18473 this.fireEvent('changed', this, state);
18476 onClick : function(e)
18478 e.preventDefault();
18480 if(!this.href.length){
18484 window.location.href = this.href;
18493 onTouchStart : function(e)
18495 this.swiping = false;
18497 this.startX = e.browserEvent.touches[0].clientX;
18498 this.startY = e.browserEvent.touches[0].clientY;
18501 onTouchMove : function(e)
18503 this.swiping = true;
18505 this.endX = e.browserEvent.touches[0].clientX;
18506 this.endY = e.browserEvent.touches[0].clientY;
18509 onTouchEnd : function(e)
18516 var tabGroup = this.parent();
18518 if(this.endX > this.startX){ // swiping right
18519 tabGroup.showPanelPrev();
18523 if(this.startX > this.endX){ // swiping left
18524 tabGroup.showPanelNext();
18543 * @class Roo.bootstrap.DateField
18544 * @extends Roo.bootstrap.Input
18545 * Bootstrap DateField class
18546 * @cfg {Number} weekStart default 0
18547 * @cfg {String} viewMode default empty, (months|years)
18548 * @cfg {String} minViewMode default empty, (months|years)
18549 * @cfg {Number} startDate default -Infinity
18550 * @cfg {Number} endDate default Infinity
18551 * @cfg {Boolean} todayHighlight default false
18552 * @cfg {Boolean} todayBtn default false
18553 * @cfg {Boolean} calendarWeeks default false
18554 * @cfg {Object} daysOfWeekDisabled default empty
18555 * @cfg {Boolean} singleMode default false (true | false)
18557 * @cfg {Boolean} keyboardNavigation default true
18558 * @cfg {String} language default en
18561 * Create a new DateField
18562 * @param {Object} config The config object
18565 Roo.bootstrap.DateField = function(config){
18566 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18570 * Fires when this field show.
18571 * @param {Roo.bootstrap.DateField} this
18572 * @param {Mixed} date The date value
18577 * Fires when this field hide.
18578 * @param {Roo.bootstrap.DateField} this
18579 * @param {Mixed} date The date value
18584 * Fires when select a date.
18585 * @param {Roo.bootstrap.DateField} this
18586 * @param {Mixed} date The date value
18590 * @event beforeselect
18591 * Fires when before select a date.
18592 * @param {Roo.bootstrap.DateField} this
18593 * @param {Mixed} date The date value
18595 beforeselect : true
18599 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18602 * @cfg {String} format
18603 * The default date format string which can be overriden for localization support. The format must be
18604 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18608 * @cfg {String} altFormats
18609 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18610 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18612 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18620 todayHighlight : false,
18626 keyboardNavigation: true,
18628 calendarWeeks: false,
18630 startDate: -Infinity,
18634 daysOfWeekDisabled: [],
18638 singleMode : false,
18640 UTCDate: function()
18642 return new Date(Date.UTC.apply(Date, arguments));
18645 UTCToday: function()
18647 var today = new Date();
18648 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18651 getDate: function() {
18652 var d = this.getUTCDate();
18653 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18656 getUTCDate: function() {
18660 setDate: function(d) {
18661 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18664 setUTCDate: function(d) {
18666 this.setValue(this.formatDate(this.date));
18669 onRender: function(ct, position)
18672 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18674 this.language = this.language || 'en';
18675 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18676 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18678 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18679 this.format = this.format || 'm/d/y';
18680 this.isInline = false;
18681 this.isInput = true;
18682 this.component = this.el.select('.add-on', true).first() || false;
18683 this.component = (this.component && this.component.length === 0) ? false : this.component;
18684 this.hasInput = this.component && this.inputEl().length;
18686 if (typeof(this.minViewMode === 'string')) {
18687 switch (this.minViewMode) {
18689 this.minViewMode = 1;
18692 this.minViewMode = 2;
18695 this.minViewMode = 0;
18700 if (typeof(this.viewMode === 'string')) {
18701 switch (this.viewMode) {
18714 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18716 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18718 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18720 this.picker().on('mousedown', this.onMousedown, this);
18721 this.picker().on('click', this.onClick, this);
18723 this.picker().addClass('datepicker-dropdown');
18725 this.startViewMode = this.viewMode;
18727 if(this.singleMode){
18728 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18729 v.setVisibilityMode(Roo.Element.DISPLAY);
18733 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18734 v.setStyle('width', '189px');
18738 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18739 if(!this.calendarWeeks){
18744 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18745 v.attr('colspan', function(i, val){
18746 return parseInt(val) + 1;
18751 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18753 this.setStartDate(this.startDate);
18754 this.setEndDate(this.endDate);
18756 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18763 if(this.isInline) {
18768 picker : function()
18770 return this.pickerEl;
18771 // return this.el.select('.datepicker', true).first();
18774 fillDow: function()
18776 var dowCnt = this.weekStart;
18785 if(this.calendarWeeks){
18793 while (dowCnt < this.weekStart + 7) {
18797 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18801 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18804 fillMonths: function()
18807 var months = this.picker().select('>.datepicker-months td', true).first();
18809 months.dom.innerHTML = '';
18815 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18818 months.createChild(month);
18825 this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
18827 if (this.date < this.startDate) {
18828 this.viewDate = new Date(this.startDate);
18829 } else if (this.date > this.endDate) {
18830 this.viewDate = new Date(this.endDate);
18832 this.viewDate = new Date(this.date);
18840 var d = new Date(this.viewDate),
18841 year = d.getUTCFullYear(),
18842 month = d.getUTCMonth(),
18843 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18844 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18845 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18846 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18847 currentDate = this.date && this.date.valueOf(),
18848 today = this.UTCToday();
18850 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18852 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18854 // this.picker.select('>tfoot th.today').
18855 // .text(dates[this.language].today)
18856 // .toggle(this.todayBtn !== false);
18858 this.updateNavArrows();
18861 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18863 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18865 prevMonth.setUTCDate(day);
18867 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18869 var nextMonth = new Date(prevMonth);
18871 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18873 nextMonth = nextMonth.valueOf();
18875 var fillMonths = false;
18877 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18879 while(prevMonth.valueOf() <= nextMonth) {
18882 if (prevMonth.getUTCDay() === this.weekStart) {
18884 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18892 if(this.calendarWeeks){
18893 // ISO 8601: First week contains first thursday.
18894 // ISO also states week starts on Monday, but we can be more abstract here.
18896 // Start of current week: based on weekstart/current date
18897 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18898 // Thursday of this week
18899 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18900 // First Thursday of year, year from thursday
18901 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18902 // Calendar week: ms between thursdays, div ms per day, div 7 days
18903 calWeek = (th - yth) / 864e5 / 7 + 1;
18905 fillMonths.cn.push({
18913 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18915 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18918 if (this.todayHighlight &&
18919 prevMonth.getUTCFullYear() == today.getFullYear() &&
18920 prevMonth.getUTCMonth() == today.getMonth() &&
18921 prevMonth.getUTCDate() == today.getDate()) {
18922 clsName += ' today';
18925 if (currentDate && prevMonth.valueOf() === currentDate) {
18926 clsName += ' active';
18929 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18930 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18931 clsName += ' disabled';
18934 fillMonths.cn.push({
18936 cls: 'day ' + clsName,
18937 html: prevMonth.getDate()
18940 prevMonth.setDate(prevMonth.getDate()+1);
18943 var currentYear = this.date && this.date.getUTCFullYear();
18944 var currentMonth = this.date && this.date.getUTCMonth();
18946 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18948 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18949 v.removeClass('active');
18951 if(currentYear === year && k === currentMonth){
18952 v.addClass('active');
18955 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18956 v.addClass('disabled');
18962 year = parseInt(year/10, 10) * 10;
18964 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18966 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18969 for (var i = -1; i < 11; i++) {
18970 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18972 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18980 showMode: function(dir)
18983 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18986 Roo.each(this.picker().select('>div',true).elements, function(v){
18987 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18990 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18995 if(this.isInline) {
18999 this.picker().removeClass(['bottom', 'top']);
19001 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19003 * place to the top of element!
19007 this.picker().addClass('top');
19008 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19013 this.picker().addClass('bottom');
19015 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19018 parseDate : function(value)
19020 if(!value || value instanceof Date){
19023 var v = Date.parseDate(value, this.format);
19024 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19025 v = Date.parseDate(value, 'Y-m-d');
19027 if(!v && this.altFormats){
19028 if(!this.altFormatsArray){
19029 this.altFormatsArray = this.altFormats.split("|");
19031 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19032 v = Date.parseDate(value, this.altFormatsArray[i]);
19038 formatDate : function(date, fmt)
19040 return (!date || !(date instanceof Date)) ?
19041 date : date.dateFormat(fmt || this.format);
19044 onFocus : function()
19046 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19050 onBlur : function()
19052 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19054 var d = this.inputEl().getValue();
19061 showPopup : function()
19063 this.picker().show();
19067 this.fireEvent('showpopup', this, this.date);
19070 hidePopup : function()
19072 if(this.isInline) {
19075 this.picker().hide();
19076 this.viewMode = this.startViewMode;
19079 this.fireEvent('hidepopup', this, this.date);
19083 onMousedown: function(e)
19085 e.stopPropagation();
19086 e.preventDefault();
19091 Roo.bootstrap.DateField.superclass.keyup.call(this);
19095 setValue: function(v)
19097 if(this.fireEvent('beforeselect', this, v) !== false){
19098 var d = new Date(this.parseDate(v) ).clearTime();
19100 if(isNaN(d.getTime())){
19101 this.date = this.viewDate = '';
19102 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19106 v = this.formatDate(d);
19108 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19110 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19114 this.fireEvent('select', this, this.date);
19118 getValue: function()
19120 return this.formatDate(this.date);
19123 fireKey: function(e)
19125 if (!this.picker().isVisible()){
19126 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19132 var dateChanged = false,
19134 newDate, newViewDate;
19139 e.preventDefault();
19143 if (!this.keyboardNavigation) {
19146 dir = e.keyCode == 37 ? -1 : 1;
19149 newDate = this.moveYear(this.date, dir);
19150 newViewDate = this.moveYear(this.viewDate, dir);
19151 } else if (e.shiftKey){
19152 newDate = this.moveMonth(this.date, dir);
19153 newViewDate = this.moveMonth(this.viewDate, dir);
19155 newDate = new Date(this.date);
19156 newDate.setUTCDate(this.date.getUTCDate() + dir);
19157 newViewDate = new Date(this.viewDate);
19158 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19160 if (this.dateWithinRange(newDate)){
19161 this.date = newDate;
19162 this.viewDate = newViewDate;
19163 this.setValue(this.formatDate(this.date));
19165 e.preventDefault();
19166 dateChanged = true;
19171 if (!this.keyboardNavigation) {
19174 dir = e.keyCode == 38 ? -1 : 1;
19176 newDate = this.moveYear(this.date, dir);
19177 newViewDate = this.moveYear(this.viewDate, dir);
19178 } else if (e.shiftKey){
19179 newDate = this.moveMonth(this.date, dir);
19180 newViewDate = this.moveMonth(this.viewDate, dir);
19182 newDate = new Date(this.date);
19183 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19184 newViewDate = new Date(this.viewDate);
19185 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19187 if (this.dateWithinRange(newDate)){
19188 this.date = newDate;
19189 this.viewDate = newViewDate;
19190 this.setValue(this.formatDate(this.date));
19192 e.preventDefault();
19193 dateChanged = true;
19197 this.setValue(this.formatDate(this.date));
19199 e.preventDefault();
19202 this.setValue(this.formatDate(this.date));
19216 onClick: function(e)
19218 e.stopPropagation();
19219 e.preventDefault();
19221 var target = e.getTarget();
19223 if(target.nodeName.toLowerCase() === 'i'){
19224 target = Roo.get(target).dom.parentNode;
19227 var nodeName = target.nodeName;
19228 var className = target.className;
19229 var html = target.innerHTML;
19230 //Roo.log(nodeName);
19232 switch(nodeName.toLowerCase()) {
19234 switch(className) {
19240 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19241 switch(this.viewMode){
19243 this.viewDate = this.moveMonth(this.viewDate, dir);
19247 this.viewDate = this.moveYear(this.viewDate, dir);
19253 var date = new Date();
19254 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19256 this.setValue(this.formatDate(this.date));
19263 if (className.indexOf('disabled') < 0) {
19264 this.viewDate.setUTCDate(1);
19265 if (className.indexOf('month') > -1) {
19266 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19268 var year = parseInt(html, 10) || 0;
19269 this.viewDate.setUTCFullYear(year);
19273 if(this.singleMode){
19274 this.setValue(this.formatDate(this.viewDate));
19285 //Roo.log(className);
19286 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19287 var day = parseInt(html, 10) || 1;
19288 var year = this.viewDate.getUTCFullYear(),
19289 month = this.viewDate.getUTCMonth();
19291 if (className.indexOf('old') > -1) {
19298 } else if (className.indexOf('new') > -1) {
19306 //Roo.log([year,month,day]);
19307 this.date = this.UTCDate(year, month, day,0,0,0,0);
19308 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19310 //Roo.log(this.formatDate(this.date));
19311 this.setValue(this.formatDate(this.date));
19318 setStartDate: function(startDate)
19320 this.startDate = startDate || -Infinity;
19321 if (this.startDate !== -Infinity) {
19322 this.startDate = this.parseDate(this.startDate);
19325 this.updateNavArrows();
19328 setEndDate: function(endDate)
19330 this.endDate = endDate || Infinity;
19331 if (this.endDate !== Infinity) {
19332 this.endDate = this.parseDate(this.endDate);
19335 this.updateNavArrows();
19338 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19340 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19341 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19342 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19344 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19345 return parseInt(d, 10);
19348 this.updateNavArrows();
19351 updateNavArrows: function()
19353 if(this.singleMode){
19357 var d = new Date(this.viewDate),
19358 year = d.getUTCFullYear(),
19359 month = d.getUTCMonth();
19361 Roo.each(this.picker().select('.prev', true).elements, function(v){
19363 switch (this.viewMode) {
19366 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19372 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19379 Roo.each(this.picker().select('.next', true).elements, function(v){
19381 switch (this.viewMode) {
19384 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19390 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19398 moveMonth: function(date, dir)
19403 var new_date = new Date(date.valueOf()),
19404 day = new_date.getUTCDate(),
19405 month = new_date.getUTCMonth(),
19406 mag = Math.abs(dir),
19408 dir = dir > 0 ? 1 : -1;
19411 // If going back one month, make sure month is not current month
19412 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19414 return new_date.getUTCMonth() == month;
19416 // If going forward one month, make sure month is as expected
19417 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19419 return new_date.getUTCMonth() != new_month;
19421 new_month = month + dir;
19422 new_date.setUTCMonth(new_month);
19423 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19424 if (new_month < 0 || new_month > 11) {
19425 new_month = (new_month + 12) % 12;
19428 // For magnitudes >1, move one month at a time...
19429 for (var i=0; i<mag; i++) {
19430 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19431 new_date = this.moveMonth(new_date, dir);
19433 // ...then reset the day, keeping it in the new month
19434 new_month = new_date.getUTCMonth();
19435 new_date.setUTCDate(day);
19437 return new_month != new_date.getUTCMonth();
19440 // Common date-resetting loop -- if date is beyond end of month, make it
19443 new_date.setUTCDate(--day);
19444 new_date.setUTCMonth(new_month);
19449 moveYear: function(date, dir)
19451 return this.moveMonth(date, dir*12);
19454 dateWithinRange: function(date)
19456 return date >= this.startDate && date <= this.endDate;
19462 this.picker().remove();
19465 validateValue : function(value)
19467 if(this.getVisibilityEl().hasClass('hidden')){
19471 if(value.length < 1) {
19472 if(this.allowBlank){
19478 if(value.length < this.minLength){
19481 if(value.length > this.maxLength){
19485 var vt = Roo.form.VTypes;
19486 if(!vt[this.vtype](value, this)){
19490 if(typeof this.validator == "function"){
19491 var msg = this.validator(value);
19497 if(this.regex && !this.regex.test(value)){
19501 if(typeof(this.parseDate(value)) == 'undefined'){
19505 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19509 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19519 this.date = this.viewDate = '';
19521 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19526 Roo.apply(Roo.bootstrap.DateField, {
19537 html: '<i class="fa fa-arrow-left"/>'
19547 html: '<i class="fa fa-arrow-right"/>'
19589 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19590 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19591 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19592 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19593 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19606 navFnc: 'FullYear',
19611 navFnc: 'FullYear',
19616 Roo.apply(Roo.bootstrap.DateField, {
19620 cls: 'datepicker dropdown-menu roo-dynamic',
19624 cls: 'datepicker-days',
19628 cls: 'table-condensed',
19630 Roo.bootstrap.DateField.head,
19634 Roo.bootstrap.DateField.footer
19641 cls: 'datepicker-months',
19645 cls: 'table-condensed',
19647 Roo.bootstrap.DateField.head,
19648 Roo.bootstrap.DateField.content,
19649 Roo.bootstrap.DateField.footer
19656 cls: 'datepicker-years',
19660 cls: 'table-condensed',
19662 Roo.bootstrap.DateField.head,
19663 Roo.bootstrap.DateField.content,
19664 Roo.bootstrap.DateField.footer
19683 * @class Roo.bootstrap.TimeField
19684 * @extends Roo.bootstrap.Input
19685 * Bootstrap DateField class
19689 * Create a new TimeField
19690 * @param {Object} config The config object
19693 Roo.bootstrap.TimeField = function(config){
19694 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19698 * Fires when this field show.
19699 * @param {Roo.bootstrap.DateField} thisthis
19700 * @param {Mixed} date The date value
19705 * Fires when this field hide.
19706 * @param {Roo.bootstrap.DateField} this
19707 * @param {Mixed} date The date value
19712 * Fires when select a date.
19713 * @param {Roo.bootstrap.DateField} this
19714 * @param {Mixed} date The date value
19720 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19723 * @cfg {String} format
19724 * The default time format string which can be overriden for localization support. The format must be
19725 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19729 onRender: function(ct, position)
19732 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19734 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19736 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19738 this.pop = this.picker().select('>.datepicker-time',true).first();
19739 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19741 this.picker().on('mousedown', this.onMousedown, this);
19742 this.picker().on('click', this.onClick, this);
19744 this.picker().addClass('datepicker-dropdown');
19749 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19750 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19751 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19752 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19753 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19754 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19758 fireKey: function(e){
19759 if (!this.picker().isVisible()){
19760 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19766 e.preventDefault();
19774 this.onTogglePeriod();
19777 this.onIncrementMinutes();
19780 this.onDecrementMinutes();
19789 onClick: function(e) {
19790 e.stopPropagation();
19791 e.preventDefault();
19794 picker : function()
19796 return this.el.select('.datepicker', true).first();
19799 fillTime: function()
19801 var time = this.pop.select('tbody', true).first();
19803 time.dom.innerHTML = '';
19818 cls: 'hours-up glyphicon glyphicon-chevron-up'
19838 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19859 cls: 'timepicker-hour',
19874 cls: 'timepicker-minute',
19889 cls: 'btn btn-primary period',
19911 cls: 'hours-down glyphicon glyphicon-chevron-down'
19931 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19949 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19956 var hours = this.time.getHours();
19957 var minutes = this.time.getMinutes();
19970 hours = hours - 12;
19974 hours = '0' + hours;
19978 minutes = '0' + minutes;
19981 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19982 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19983 this.pop.select('button', true).first().dom.innerHTML = period;
19989 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19991 var cls = ['bottom'];
19993 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20000 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20005 this.picker().addClass(cls.join('-'));
20009 Roo.each(cls, function(c){
20011 _this.picker().setTop(_this.inputEl().getHeight());
20015 _this.picker().setTop(0 - _this.picker().getHeight());
20020 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20024 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20031 onFocus : function()
20033 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20037 onBlur : function()
20039 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20045 this.picker().show();
20050 this.fireEvent('show', this, this.date);
20055 this.picker().hide();
20058 this.fireEvent('hide', this, this.date);
20061 setTime : function()
20064 this.setValue(this.time.format(this.format));
20066 this.fireEvent('select', this, this.date);
20071 onMousedown: function(e){
20072 e.stopPropagation();
20073 e.preventDefault();
20076 onIncrementHours: function()
20078 Roo.log('onIncrementHours');
20079 this.time = this.time.add(Date.HOUR, 1);
20084 onDecrementHours: function()
20086 Roo.log('onDecrementHours');
20087 this.time = this.time.add(Date.HOUR, -1);
20091 onIncrementMinutes: function()
20093 Roo.log('onIncrementMinutes');
20094 this.time = this.time.add(Date.MINUTE, 1);
20098 onDecrementMinutes: function()
20100 Roo.log('onDecrementMinutes');
20101 this.time = this.time.add(Date.MINUTE, -1);
20105 onTogglePeriod: function()
20107 Roo.log('onTogglePeriod');
20108 this.time = this.time.add(Date.HOUR, 12);
20115 Roo.apply(Roo.bootstrap.TimeField, {
20145 cls: 'btn btn-info ok',
20157 Roo.apply(Roo.bootstrap.TimeField, {
20161 cls: 'datepicker dropdown-menu',
20165 cls: 'datepicker-time',
20169 cls: 'table-condensed',
20171 Roo.bootstrap.TimeField.content,
20172 Roo.bootstrap.TimeField.footer
20191 * @class Roo.bootstrap.MonthField
20192 * @extends Roo.bootstrap.Input
20193 * Bootstrap MonthField class
20195 * @cfg {String} language default en
20198 * Create a new MonthField
20199 * @param {Object} config The config object
20202 Roo.bootstrap.MonthField = function(config){
20203 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20208 * Fires when this field show.
20209 * @param {Roo.bootstrap.MonthField} this
20210 * @param {Mixed} date The date value
20215 * Fires when this field hide.
20216 * @param {Roo.bootstrap.MonthField} this
20217 * @param {Mixed} date The date value
20222 * Fires when select a date.
20223 * @param {Roo.bootstrap.MonthField} this
20224 * @param {String} oldvalue The old value
20225 * @param {String} newvalue The new value
20231 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20233 onRender: function(ct, position)
20236 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20238 this.language = this.language || 'en';
20239 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20240 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20242 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20243 this.isInline = false;
20244 this.isInput = true;
20245 this.component = this.el.select('.add-on', true).first() || false;
20246 this.component = (this.component && this.component.length === 0) ? false : this.component;
20247 this.hasInput = this.component && this.inputEL().length;
20249 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20251 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20253 this.picker().on('mousedown', this.onMousedown, this);
20254 this.picker().on('click', this.onClick, this);
20256 this.picker().addClass('datepicker-dropdown');
20258 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20259 v.setStyle('width', '189px');
20266 if(this.isInline) {
20272 setValue: function(v, suppressEvent)
20274 var o = this.getValue();
20276 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20280 if(suppressEvent !== true){
20281 this.fireEvent('select', this, o, v);
20286 getValue: function()
20291 onClick: function(e)
20293 e.stopPropagation();
20294 e.preventDefault();
20296 var target = e.getTarget();
20298 if(target.nodeName.toLowerCase() === 'i'){
20299 target = Roo.get(target).dom.parentNode;
20302 var nodeName = target.nodeName;
20303 var className = target.className;
20304 var html = target.innerHTML;
20306 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20310 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20312 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20318 picker : function()
20320 return this.pickerEl;
20323 fillMonths: function()
20326 var months = this.picker().select('>.datepicker-months td', true).first();
20328 months.dom.innerHTML = '';
20334 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20337 months.createChild(month);
20346 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20347 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20350 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20351 e.removeClass('active');
20353 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20354 e.addClass('active');
20361 if(this.isInline) {
20365 this.picker().removeClass(['bottom', 'top']);
20367 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20369 * place to the top of element!
20373 this.picker().addClass('top');
20374 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20379 this.picker().addClass('bottom');
20381 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20384 onFocus : function()
20386 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20390 onBlur : function()
20392 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20394 var d = this.inputEl().getValue();
20403 this.picker().show();
20404 this.picker().select('>.datepicker-months', true).first().show();
20408 this.fireEvent('show', this, this.date);
20413 if(this.isInline) {
20416 this.picker().hide();
20417 this.fireEvent('hide', this, this.date);
20421 onMousedown: function(e)
20423 e.stopPropagation();
20424 e.preventDefault();
20429 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20433 fireKey: function(e)
20435 if (!this.picker().isVisible()){
20436 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20447 e.preventDefault();
20451 dir = e.keyCode == 37 ? -1 : 1;
20453 this.vIndex = this.vIndex + dir;
20455 if(this.vIndex < 0){
20459 if(this.vIndex > 11){
20463 if(isNaN(this.vIndex)){
20467 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20473 dir = e.keyCode == 38 ? -1 : 1;
20475 this.vIndex = this.vIndex + dir * 4;
20477 if(this.vIndex < 0){
20481 if(this.vIndex > 11){
20485 if(isNaN(this.vIndex)){
20489 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20494 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20495 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20499 e.preventDefault();
20502 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20503 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20519 this.picker().remove();
20524 Roo.apply(Roo.bootstrap.MonthField, {
20543 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20544 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20549 Roo.apply(Roo.bootstrap.MonthField, {
20553 cls: 'datepicker dropdown-menu roo-dynamic',
20557 cls: 'datepicker-months',
20561 cls: 'table-condensed',
20563 Roo.bootstrap.DateField.content
20583 * @class Roo.bootstrap.CheckBox
20584 * @extends Roo.bootstrap.Input
20585 * Bootstrap CheckBox class
20587 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20588 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20589 * @cfg {String} boxLabel The text that appears beside the checkbox
20590 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20591 * @cfg {Boolean} checked initnal the element
20592 * @cfg {Boolean} inline inline the element (default false)
20593 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20594 * @cfg {String} tooltip label tooltip
20597 * Create a new CheckBox
20598 * @param {Object} config The config object
20601 Roo.bootstrap.CheckBox = function(config){
20602 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20607 * Fires when the element is checked or unchecked.
20608 * @param {Roo.bootstrap.CheckBox} this This input
20609 * @param {Boolean} checked The new checked value
20614 * Fires when the element is click.
20615 * @param {Roo.bootstrap.CheckBox} this This input
20622 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20624 inputType: 'checkbox',
20633 getAutoCreate : function()
20635 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20641 cfg.cls = 'form-group ' + this.inputType; //input-group
20644 cfg.cls += ' ' + this.inputType + '-inline';
20650 type : this.inputType,
20651 value : this.inputValue,
20652 cls : 'roo-' + this.inputType, //'form-box',
20653 placeholder : this.placeholder || ''
20657 if(this.inputType != 'radio'){
20661 cls : 'roo-hidden-value',
20662 value : this.checked ? this.inputValue : this.valueOff
20667 if (this.weight) { // Validity check?
20668 cfg.cls += " " + this.inputType + "-" + this.weight;
20671 if (this.disabled) {
20672 input.disabled=true;
20676 input.checked = this.checked;
20681 input.name = this.name;
20683 if(this.inputType != 'radio'){
20684 hidden.name = this.name;
20685 input.name = '_hidden_' + this.name;
20690 input.cls += ' input-' + this.size;
20695 ['xs','sm','md','lg'].map(function(size){
20696 if (settings[size]) {
20697 cfg.cls += ' col-' + size + '-' + settings[size];
20701 var inputblock = input;
20703 if (this.before || this.after) {
20706 cls : 'input-group',
20711 inputblock.cn.push({
20713 cls : 'input-group-addon',
20718 inputblock.cn.push(input);
20720 if(this.inputType != 'radio'){
20721 inputblock.cn.push(hidden);
20725 inputblock.cn.push({
20727 cls : 'input-group-addon',
20734 if (align ==='left' && this.fieldLabel.length) {
20735 // Roo.log("left and has label");
20740 cls : 'control-label',
20741 html : this.fieldLabel
20751 if(this.labelWidth > 12){
20752 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20755 if(this.labelWidth < 13 && this.labelmd == 0){
20756 this.labelmd = this.labelWidth;
20759 if(this.labellg > 0){
20760 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20761 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20764 if(this.labelmd > 0){
20765 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20766 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20769 if(this.labelsm > 0){
20770 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20771 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20774 if(this.labelxs > 0){
20775 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20776 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20779 } else if ( this.fieldLabel.length) {
20780 // Roo.log(" label");
20784 tag: this.boxLabel ? 'span' : 'label',
20786 cls: 'control-label box-input-label',
20787 //cls : 'input-group-addon',
20788 html : this.fieldLabel
20797 // Roo.log(" no label && no align");
20798 cfg.cn = [ inputblock ] ;
20804 var boxLabelCfg = {
20806 //'for': id, // box label is handled by onclick - so no for...
20808 html: this.boxLabel
20812 boxLabelCfg.tooltip = this.tooltip;
20815 cfg.cn.push(boxLabelCfg);
20818 if(this.inputType != 'radio'){
20819 cfg.cn.push(hidden);
20827 * return the real input element.
20829 inputEl: function ()
20831 return this.el.select('input.roo-' + this.inputType,true).first();
20833 hiddenEl: function ()
20835 return this.el.select('input.roo-hidden-value',true).first();
20838 labelEl: function()
20840 return this.el.select('label.control-label',true).first();
20842 /* depricated... */
20846 return this.labelEl();
20849 boxLabelEl: function()
20851 return this.el.select('label.box-label',true).first();
20854 initEvents : function()
20856 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20858 this.inputEl().on('click', this.onClick, this);
20860 if (this.boxLabel) {
20861 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20864 this.startValue = this.getValue();
20867 Roo.bootstrap.CheckBox.register(this);
20871 onClick : function(e)
20873 if(this.fireEvent('click', this, e) !== false){
20874 this.setChecked(!this.checked);
20879 setChecked : function(state,suppressEvent)
20881 this.startValue = this.getValue();
20883 if(this.inputType == 'radio'){
20885 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20886 e.dom.checked = false;
20889 this.inputEl().dom.checked = true;
20891 this.inputEl().dom.value = this.inputValue;
20893 if(suppressEvent !== true){
20894 this.fireEvent('check', this, true);
20902 this.checked = state;
20904 this.inputEl().dom.checked = state;
20907 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20909 if(suppressEvent !== true){
20910 this.fireEvent('check', this, state);
20916 getValue : function()
20918 if(this.inputType == 'radio'){
20919 return this.getGroupValue();
20922 return this.hiddenEl().dom.value;
20926 getGroupValue : function()
20928 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20932 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20935 setValue : function(v,suppressEvent)
20937 if(this.inputType == 'radio'){
20938 this.setGroupValue(v, suppressEvent);
20942 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20947 setGroupValue : function(v, suppressEvent)
20949 this.startValue = this.getValue();
20951 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20952 e.dom.checked = false;
20954 if(e.dom.value == v){
20955 e.dom.checked = true;
20959 if(suppressEvent !== true){
20960 this.fireEvent('check', this, true);
20968 validate : function()
20970 if(this.getVisibilityEl().hasClass('hidden')){
20976 (this.inputType == 'radio' && this.validateRadio()) ||
20977 (this.inputType == 'checkbox' && this.validateCheckbox())
20983 this.markInvalid();
20987 validateRadio : function()
20989 if(this.getVisibilityEl().hasClass('hidden')){
20993 if(this.allowBlank){
20999 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21000 if(!e.dom.checked){
21012 validateCheckbox : function()
21015 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21016 //return (this.getValue() == this.inputValue) ? true : false;
21019 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21027 for(var i in group){
21028 if(group[i].el.isVisible(true)){
21036 for(var i in group){
21041 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21048 * Mark this field as valid
21050 markValid : function()
21054 this.fireEvent('valid', this);
21056 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21059 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21066 if(this.inputType == 'radio'){
21067 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21068 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21069 e.findParent('.form-group', false, true).addClass(_this.validClass);
21076 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21077 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21081 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21087 for(var i in group){
21088 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21089 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21094 * Mark this field as invalid
21095 * @param {String} msg The validation message
21097 markInvalid : function(msg)
21099 if(this.allowBlank){
21105 this.fireEvent('invalid', this, msg);
21107 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21110 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21114 label.markInvalid();
21117 if(this.inputType == 'radio'){
21118 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21119 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21120 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21127 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21128 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21132 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21138 for(var i in group){
21139 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21140 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21145 clearInvalid : function()
21147 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21149 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21151 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21153 if (label && label.iconEl) {
21154 label.iconEl.removeClass(label.validClass);
21155 label.iconEl.removeClass(label.invalidClass);
21159 disable : function()
21161 if(this.inputType != 'radio'){
21162 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21169 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21170 _this.getActionEl().addClass(this.disabledClass);
21171 e.dom.disabled = true;
21175 this.disabled = true;
21176 this.fireEvent("disable", this);
21180 enable : function()
21182 if(this.inputType != 'radio'){
21183 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21190 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21191 _this.getActionEl().removeClass(this.disabledClass);
21192 e.dom.disabled = false;
21196 this.disabled = false;
21197 this.fireEvent("enable", this);
21201 setBoxLabel : function(v)
21206 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21212 Roo.apply(Roo.bootstrap.CheckBox, {
21217 * register a CheckBox Group
21218 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21220 register : function(checkbox)
21222 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21223 this.groups[checkbox.groupId] = {};
21226 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21230 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21234 * fetch a CheckBox Group based on the group ID
21235 * @param {string} the group ID
21236 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21238 get: function(groupId) {
21239 if (typeof(this.groups[groupId]) == 'undefined') {
21243 return this.groups[groupId] ;
21256 * @class Roo.bootstrap.Radio
21257 * @extends Roo.bootstrap.Component
21258 * Bootstrap Radio class
21259 * @cfg {String} boxLabel - the label associated
21260 * @cfg {String} value - the value of radio
21263 * Create a new Radio
21264 * @param {Object} config The config object
21266 Roo.bootstrap.Radio = function(config){
21267 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21271 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21277 getAutoCreate : function()
21281 cls : 'form-group radio',
21286 html : this.boxLabel
21294 initEvents : function()
21296 this.parent().register(this);
21298 this.el.on('click', this.onClick, this);
21302 onClick : function(e)
21304 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21305 this.setChecked(true);
21309 setChecked : function(state, suppressEvent)
21311 this.parent().setValue(this.value, suppressEvent);
21315 setBoxLabel : function(v)
21320 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21335 * @class Roo.bootstrap.SecurePass
21336 * @extends Roo.bootstrap.Input
21337 * Bootstrap SecurePass class
21341 * Create a new SecurePass
21342 * @param {Object} config The config object
21345 Roo.bootstrap.SecurePass = function (config) {
21346 // these go here, so the translation tool can replace them..
21348 PwdEmpty: "Please type a password, and then retype it to confirm.",
21349 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21350 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21351 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21352 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21353 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21354 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21355 TooWeak: "Your password is Too Weak."
21357 this.meterLabel = "Password strength:";
21358 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21359 this.meterClass = [
21360 "roo-password-meter-tooweak",
21361 "roo-password-meter-weak",
21362 "roo-password-meter-medium",
21363 "roo-password-meter-strong",
21364 "roo-password-meter-grey"
21369 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21372 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21374 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21376 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21377 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21378 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21379 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21380 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21381 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21382 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21392 * @cfg {String/Object} Label for the strength meter (defaults to
21393 * 'Password strength:')
21398 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21399 * ['Weak', 'Medium', 'Strong'])
21402 pwdStrengths: false,
21415 initEvents: function ()
21417 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21419 if (this.el.is('input[type=password]') && Roo.isSafari) {
21420 this.el.on('keydown', this.SafariOnKeyDown, this);
21423 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21426 onRender: function (ct, position)
21428 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21429 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21430 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21432 this.trigger.createChild({
21437 cls: 'roo-password-meter-grey col-xs-12',
21440 //width: this.meterWidth + 'px'
21444 cls: 'roo-password-meter-text'
21450 if (this.hideTrigger) {
21451 this.trigger.setDisplayed(false);
21453 this.setSize(this.width || '', this.height || '');
21456 onDestroy: function ()
21458 if (this.trigger) {
21459 this.trigger.removeAllListeners();
21460 this.trigger.remove();
21463 this.wrap.remove();
21465 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21468 checkStrength: function ()
21470 var pwd = this.inputEl().getValue();
21471 if (pwd == this._lastPwd) {
21476 if (this.ClientSideStrongPassword(pwd)) {
21478 } else if (this.ClientSideMediumPassword(pwd)) {
21480 } else if (this.ClientSideWeakPassword(pwd)) {
21486 Roo.log('strength1: ' + strength);
21488 //var pm = this.trigger.child('div/div/div').dom;
21489 var pm = this.trigger.child('div/div');
21490 pm.removeClass(this.meterClass);
21491 pm.addClass(this.meterClass[strength]);
21494 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21496 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21498 this._lastPwd = pwd;
21502 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21504 this._lastPwd = '';
21506 var pm = this.trigger.child('div/div');
21507 pm.removeClass(this.meterClass);
21508 pm.addClass('roo-password-meter-grey');
21511 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21514 this.inputEl().dom.type='password';
21517 validateValue: function (value)
21520 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21523 if (value.length == 0) {
21524 if (this.allowBlank) {
21525 this.clearInvalid();
21529 this.markInvalid(this.errors.PwdEmpty);
21530 this.errorMsg = this.errors.PwdEmpty;
21538 if ('[\x21-\x7e]*'.match(value)) {
21539 this.markInvalid(this.errors.PwdBadChar);
21540 this.errorMsg = this.errors.PwdBadChar;
21543 if (value.length < 6) {
21544 this.markInvalid(this.errors.PwdShort);
21545 this.errorMsg = this.errors.PwdShort;
21548 if (value.length > 16) {
21549 this.markInvalid(this.errors.PwdLong);
21550 this.errorMsg = this.errors.PwdLong;
21554 if (this.ClientSideStrongPassword(value)) {
21556 } else if (this.ClientSideMediumPassword(value)) {
21558 } else if (this.ClientSideWeakPassword(value)) {
21565 if (strength < 2) {
21566 //this.markInvalid(this.errors.TooWeak);
21567 this.errorMsg = this.errors.TooWeak;
21572 console.log('strength2: ' + strength);
21574 //var pm = this.trigger.child('div/div/div').dom;
21576 var pm = this.trigger.child('div/div');
21577 pm.removeClass(this.meterClass);
21578 pm.addClass(this.meterClass[strength]);
21580 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21582 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21584 this.errorMsg = '';
21588 CharacterSetChecks: function (type)
21591 this.fResult = false;
21594 isctype: function (character, type)
21597 case this.kCapitalLetter:
21598 if (character >= 'A' && character <= 'Z') {
21603 case this.kSmallLetter:
21604 if (character >= 'a' && character <= 'z') {
21610 if (character >= '0' && character <= '9') {
21615 case this.kPunctuation:
21616 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21627 IsLongEnough: function (pwd, size)
21629 return !(pwd == null || isNaN(size) || pwd.length < size);
21632 SpansEnoughCharacterSets: function (word, nb)
21634 if (!this.IsLongEnough(word, nb))
21639 var characterSetChecks = new Array(
21640 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21641 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21644 for (var index = 0; index < word.length; ++index) {
21645 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21646 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21647 characterSetChecks[nCharSet].fResult = true;
21654 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21655 if (characterSetChecks[nCharSet].fResult) {
21660 if (nCharSets < nb) {
21666 ClientSideStrongPassword: function (pwd)
21668 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21671 ClientSideMediumPassword: function (pwd)
21673 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21676 ClientSideWeakPassword: function (pwd)
21678 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21681 })//<script type="text/javascript">
21684 * Based Ext JS Library 1.1.1
21685 * Copyright(c) 2006-2007, Ext JS, LLC.
21691 * @class Roo.HtmlEditorCore
21692 * @extends Roo.Component
21693 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21695 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21698 Roo.HtmlEditorCore = function(config){
21701 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21706 * @event initialize
21707 * Fires when the editor is fully initialized (including the iframe)
21708 * @param {Roo.HtmlEditorCore} this
21713 * Fires when the editor is first receives the focus. Any insertion must wait
21714 * until after this event.
21715 * @param {Roo.HtmlEditorCore} this
21719 * @event beforesync
21720 * Fires before the textarea is updated with content from the editor iframe. Return false
21721 * to cancel the sync.
21722 * @param {Roo.HtmlEditorCore} this
21723 * @param {String} html
21727 * @event beforepush
21728 * Fires before the iframe editor is updated with content from the textarea. Return false
21729 * to cancel the push.
21730 * @param {Roo.HtmlEditorCore} this
21731 * @param {String} html
21736 * Fires when the textarea is updated with content from the editor iframe.
21737 * @param {Roo.HtmlEditorCore} this
21738 * @param {String} html
21743 * Fires when the iframe editor is updated with content from the textarea.
21744 * @param {Roo.HtmlEditorCore} this
21745 * @param {String} html
21750 * @event editorevent
21751 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21752 * @param {Roo.HtmlEditorCore} this
21758 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21760 // defaults : white / black...
21761 this.applyBlacklists();
21768 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21772 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21778 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21783 * @cfg {Number} height (in pixels)
21787 * @cfg {Number} width (in pixels)
21792 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21795 stylesheets: false,
21800 // private properties
21801 validationEvent : false,
21803 initialized : false,
21805 sourceEditMode : false,
21806 onFocus : Roo.emptyFn,
21808 hideMode:'offsets',
21812 // blacklist + whitelisted elements..
21819 * Protected method that will not generally be called directly. It
21820 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21821 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21823 getDocMarkup : function(){
21827 // inherit styels from page...??
21828 if (this.stylesheets === false) {
21830 Roo.get(document.head).select('style').each(function(node) {
21831 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21834 Roo.get(document.head).select('link').each(function(node) {
21835 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21838 } else if (!this.stylesheets.length) {
21840 st = '<style type="text/css">' +
21841 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21844 st = '<style type="text/css">' +
21849 st += '<style type="text/css">' +
21850 'IMG { cursor: pointer } ' +
21853 var cls = 'roo-htmleditor-body';
21855 if(this.bodyCls.length){
21856 cls += ' ' + this.bodyCls;
21859 return '<html><head>' + st +
21860 //<style type="text/css">' +
21861 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21863 ' </head><body class="' + cls + '"></body></html>';
21867 onRender : function(ct, position)
21870 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21871 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21874 this.el.dom.style.border = '0 none';
21875 this.el.dom.setAttribute('tabIndex', -1);
21876 this.el.addClass('x-hidden hide');
21880 if(Roo.isIE){ // fix IE 1px bogus margin
21881 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21885 this.frameId = Roo.id();
21889 var iframe = this.owner.wrap.createChild({
21891 cls: 'form-control', // bootstrap..
21893 name: this.frameId,
21894 frameBorder : 'no',
21895 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21900 this.iframe = iframe.dom;
21902 this.assignDocWin();
21904 this.doc.designMode = 'on';
21907 this.doc.write(this.getDocMarkup());
21911 var task = { // must defer to wait for browser to be ready
21913 //console.log("run task?" + this.doc.readyState);
21914 this.assignDocWin();
21915 if(this.doc.body || this.doc.readyState == 'complete'){
21917 this.doc.designMode="on";
21921 Roo.TaskMgr.stop(task);
21922 this.initEditor.defer(10, this);
21929 Roo.TaskMgr.start(task);
21934 onResize : function(w, h)
21936 Roo.log('resize: ' +w + ',' + h );
21937 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21941 if(typeof w == 'number'){
21943 this.iframe.style.width = w + 'px';
21945 if(typeof h == 'number'){
21947 this.iframe.style.height = h + 'px';
21949 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21956 * Toggles the editor between standard and source edit mode.
21957 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21959 toggleSourceEdit : function(sourceEditMode){
21961 this.sourceEditMode = sourceEditMode === true;
21963 if(this.sourceEditMode){
21965 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21968 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21969 //this.iframe.className = '';
21972 //this.setSize(this.owner.wrap.getSize());
21973 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21980 * Protected method that will not generally be called directly. If you need/want
21981 * custom HTML cleanup, this is the method you should override.
21982 * @param {String} html The HTML to be cleaned
21983 * return {String} The cleaned HTML
21985 cleanHtml : function(html){
21986 html = String(html);
21987 if(html.length > 5){
21988 if(Roo.isSafari){ // strip safari nonsense
21989 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21992 if(html == ' '){
21999 * HTML Editor -> Textarea
22000 * Protected method that will not generally be called directly. Syncs the contents
22001 * of the editor iframe with the textarea.
22003 syncValue : function(){
22004 if(this.initialized){
22005 var bd = (this.doc.body || this.doc.documentElement);
22006 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22007 var html = bd.innerHTML;
22009 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22010 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22012 html = '<div style="'+m[0]+'">' + html + '</div>';
22015 html = this.cleanHtml(html);
22016 // fix up the special chars.. normaly like back quotes in word...
22017 // however we do not want to do this with chinese..
22018 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22019 var cc = b.charCodeAt();
22021 (cc >= 0x4E00 && cc < 0xA000 ) ||
22022 (cc >= 0x3400 && cc < 0x4E00 ) ||
22023 (cc >= 0xf900 && cc < 0xfb00 )
22029 if(this.owner.fireEvent('beforesync', this, html) !== false){
22030 this.el.dom.value = html;
22031 this.owner.fireEvent('sync', this, html);
22037 * Protected method that will not generally be called directly. Pushes the value of the textarea
22038 * into the iframe editor.
22040 pushValue : function(){
22041 if(this.initialized){
22042 var v = this.el.dom.value.trim();
22044 // if(v.length < 1){
22048 if(this.owner.fireEvent('beforepush', this, v) !== false){
22049 var d = (this.doc.body || this.doc.documentElement);
22051 this.cleanUpPaste();
22052 this.el.dom.value = d.innerHTML;
22053 this.owner.fireEvent('push', this, v);
22059 deferFocus : function(){
22060 this.focus.defer(10, this);
22064 focus : function(){
22065 if(this.win && !this.sourceEditMode){
22072 assignDocWin: function()
22074 var iframe = this.iframe;
22077 this.doc = iframe.contentWindow.document;
22078 this.win = iframe.contentWindow;
22080 // if (!Roo.get(this.frameId)) {
22083 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22084 // this.win = Roo.get(this.frameId).dom.contentWindow;
22086 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22090 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22091 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22096 initEditor : function(){
22097 //console.log("INIT EDITOR");
22098 this.assignDocWin();
22102 this.doc.designMode="on";
22104 this.doc.write(this.getDocMarkup());
22107 var dbody = (this.doc.body || this.doc.documentElement);
22108 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22109 // this copies styles from the containing element into thsi one..
22110 // not sure why we need all of this..
22111 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22113 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22114 //ss['background-attachment'] = 'fixed'; // w3c
22115 dbody.bgProperties = 'fixed'; // ie
22116 //Roo.DomHelper.applyStyles(dbody, ss);
22117 Roo.EventManager.on(this.doc, {
22118 //'mousedown': this.onEditorEvent,
22119 'mouseup': this.onEditorEvent,
22120 'dblclick': this.onEditorEvent,
22121 'click': this.onEditorEvent,
22122 'keyup': this.onEditorEvent,
22127 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22129 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22130 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22132 this.initialized = true;
22134 this.owner.fireEvent('initialize', this);
22139 onDestroy : function(){
22145 //for (var i =0; i < this.toolbars.length;i++) {
22146 // // fixme - ask toolbars for heights?
22147 // this.toolbars[i].onDestroy();
22150 //this.wrap.dom.innerHTML = '';
22151 //this.wrap.remove();
22156 onFirstFocus : function(){
22158 this.assignDocWin();
22161 this.activated = true;
22164 if(Roo.isGecko){ // prevent silly gecko errors
22166 var s = this.win.getSelection();
22167 if(!s.focusNode || s.focusNode.nodeType != 3){
22168 var r = s.getRangeAt(0);
22169 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22174 this.execCmd('useCSS', true);
22175 this.execCmd('styleWithCSS', false);
22178 this.owner.fireEvent('activate', this);
22182 adjustFont: function(btn){
22183 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22184 //if(Roo.isSafari){ // safari
22187 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22188 if(Roo.isSafari){ // safari
22189 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22190 v = (v < 10) ? 10 : v;
22191 v = (v > 48) ? 48 : v;
22192 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22197 v = Math.max(1, v+adjust);
22199 this.execCmd('FontSize', v );
22202 onEditorEvent : function(e)
22204 this.owner.fireEvent('editorevent', this, e);
22205 // this.updateToolbar();
22206 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22209 insertTag : function(tg)
22211 // could be a bit smarter... -> wrap the current selected tRoo..
22212 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22214 range = this.createRange(this.getSelection());
22215 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22216 wrappingNode.appendChild(range.extractContents());
22217 range.insertNode(wrappingNode);
22224 this.execCmd("formatblock", tg);
22228 insertText : function(txt)
22232 var range = this.createRange();
22233 range.deleteContents();
22234 //alert(Sender.getAttribute('label'));
22236 range.insertNode(this.doc.createTextNode(txt));
22242 * Executes a Midas editor command on the editor document and performs necessary focus and
22243 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22244 * @param {String} cmd The Midas command
22245 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22247 relayCmd : function(cmd, value){
22249 this.execCmd(cmd, value);
22250 this.owner.fireEvent('editorevent', this);
22251 //this.updateToolbar();
22252 this.owner.deferFocus();
22256 * Executes a Midas editor command directly on the editor document.
22257 * For visual commands, you should use {@link #relayCmd} instead.
22258 * <b>This should only be called after the editor is initialized.</b>
22259 * @param {String} cmd The Midas command
22260 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22262 execCmd : function(cmd, value){
22263 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22270 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22272 * @param {String} text | dom node..
22274 insertAtCursor : function(text)
22277 if(!this.activated){
22283 var r = this.doc.selection.createRange();
22294 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22298 // from jquery ui (MIT licenced)
22300 var win = this.win;
22302 if (win.getSelection && win.getSelection().getRangeAt) {
22303 range = win.getSelection().getRangeAt(0);
22304 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22305 range.insertNode(node);
22306 } else if (win.document.selection && win.document.selection.createRange) {
22307 // no firefox support
22308 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22309 win.document.selection.createRange().pasteHTML(txt);
22311 // no firefox support
22312 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22313 this.execCmd('InsertHTML', txt);
22322 mozKeyPress : function(e){
22324 var c = e.getCharCode(), cmd;
22327 c = String.fromCharCode(c).toLowerCase();
22341 this.cleanUpPaste.defer(100, this);
22349 e.preventDefault();
22357 fixKeys : function(){ // load time branching for fastest keydown performance
22359 return function(e){
22360 var k = e.getKey(), r;
22363 r = this.doc.selection.createRange();
22366 r.pasteHTML('    ');
22373 r = this.doc.selection.createRange();
22375 var target = r.parentElement();
22376 if(!target || target.tagName.toLowerCase() != 'li'){
22378 r.pasteHTML('<br />');
22384 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22385 this.cleanUpPaste.defer(100, this);
22391 }else if(Roo.isOpera){
22392 return function(e){
22393 var k = e.getKey();
22397 this.execCmd('InsertHTML','    ');
22400 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22401 this.cleanUpPaste.defer(100, this);
22406 }else if(Roo.isSafari){
22407 return function(e){
22408 var k = e.getKey();
22412 this.execCmd('InsertText','\t');
22416 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22417 this.cleanUpPaste.defer(100, this);
22425 getAllAncestors: function()
22427 var p = this.getSelectedNode();
22430 a.push(p); // push blank onto stack..
22431 p = this.getParentElement();
22435 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22439 a.push(this.doc.body);
22443 lastSelNode : false,
22446 getSelection : function()
22448 this.assignDocWin();
22449 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22452 getSelectedNode: function()
22454 // this may only work on Gecko!!!
22456 // should we cache this!!!!
22461 var range = this.createRange(this.getSelection()).cloneRange();
22464 var parent = range.parentElement();
22466 var testRange = range.duplicate();
22467 testRange.moveToElementText(parent);
22468 if (testRange.inRange(range)) {
22471 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22474 parent = parent.parentElement;
22479 // is ancestor a text element.
22480 var ac = range.commonAncestorContainer;
22481 if (ac.nodeType == 3) {
22482 ac = ac.parentNode;
22485 var ar = ac.childNodes;
22488 var other_nodes = [];
22489 var has_other_nodes = false;
22490 for (var i=0;i<ar.length;i++) {
22491 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22494 // fullly contained node.
22496 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22501 // probably selected..
22502 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22503 other_nodes.push(ar[i]);
22507 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22512 has_other_nodes = true;
22514 if (!nodes.length && other_nodes.length) {
22515 nodes= other_nodes;
22517 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22523 createRange: function(sel)
22525 // this has strange effects when using with
22526 // top toolbar - not sure if it's a great idea.
22527 //this.editor.contentWindow.focus();
22528 if (typeof sel != "undefined") {
22530 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22532 return this.doc.createRange();
22535 return this.doc.createRange();
22538 getParentElement: function()
22541 this.assignDocWin();
22542 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22544 var range = this.createRange(sel);
22547 var p = range.commonAncestorContainer;
22548 while (p.nodeType == 3) { // text node
22559 * Range intersection.. the hard stuff...
22563 * [ -- selected range --- ]
22567 * if end is before start or hits it. fail.
22568 * if start is after end or hits it fail.
22570 * if either hits (but other is outside. - then it's not
22576 // @see http://www.thismuchiknow.co.uk/?p=64.
22577 rangeIntersectsNode : function(range, node)
22579 var nodeRange = node.ownerDocument.createRange();
22581 nodeRange.selectNode(node);
22583 nodeRange.selectNodeContents(node);
22586 var rangeStartRange = range.cloneRange();
22587 rangeStartRange.collapse(true);
22589 var rangeEndRange = range.cloneRange();
22590 rangeEndRange.collapse(false);
22592 var nodeStartRange = nodeRange.cloneRange();
22593 nodeStartRange.collapse(true);
22595 var nodeEndRange = nodeRange.cloneRange();
22596 nodeEndRange.collapse(false);
22598 return rangeStartRange.compareBoundaryPoints(
22599 Range.START_TO_START, nodeEndRange) == -1 &&
22600 rangeEndRange.compareBoundaryPoints(
22601 Range.START_TO_START, nodeStartRange) == 1;
22605 rangeCompareNode : function(range, node)
22607 var nodeRange = node.ownerDocument.createRange();
22609 nodeRange.selectNode(node);
22611 nodeRange.selectNodeContents(node);
22615 range.collapse(true);
22617 nodeRange.collapse(true);
22619 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22620 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22622 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22624 var nodeIsBefore = ss == 1;
22625 var nodeIsAfter = ee == -1;
22627 if (nodeIsBefore && nodeIsAfter) {
22630 if (!nodeIsBefore && nodeIsAfter) {
22631 return 1; //right trailed.
22634 if (nodeIsBefore && !nodeIsAfter) {
22635 return 2; // left trailed.
22641 // private? - in a new class?
22642 cleanUpPaste : function()
22644 // cleans up the whole document..
22645 Roo.log('cleanuppaste');
22647 this.cleanUpChildren(this.doc.body);
22648 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22649 if (clean != this.doc.body.innerHTML) {
22650 this.doc.body.innerHTML = clean;
22655 cleanWordChars : function(input) {// change the chars to hex code
22656 var he = Roo.HtmlEditorCore;
22658 var output = input;
22659 Roo.each(he.swapCodes, function(sw) {
22660 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22662 output = output.replace(swapper, sw[1]);
22669 cleanUpChildren : function (n)
22671 if (!n.childNodes.length) {
22674 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22675 this.cleanUpChild(n.childNodes[i]);
22682 cleanUpChild : function (node)
22685 //console.log(node);
22686 if (node.nodeName == "#text") {
22687 // clean up silly Windows -- stuff?
22690 if (node.nodeName == "#comment") {
22691 node.parentNode.removeChild(node);
22692 // clean up silly Windows -- stuff?
22695 var lcname = node.tagName.toLowerCase();
22696 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22697 // whitelist of tags..
22699 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22701 node.parentNode.removeChild(node);
22706 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22708 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22709 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22711 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22712 // remove_keep_children = true;
22715 if (remove_keep_children) {
22716 this.cleanUpChildren(node);
22717 // inserts everything just before this node...
22718 while (node.childNodes.length) {
22719 var cn = node.childNodes[0];
22720 node.removeChild(cn);
22721 node.parentNode.insertBefore(cn, node);
22723 node.parentNode.removeChild(node);
22727 if (!node.attributes || !node.attributes.length) {
22728 this.cleanUpChildren(node);
22732 function cleanAttr(n,v)
22735 if (v.match(/^\./) || v.match(/^\//)) {
22738 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22741 if (v.match(/^#/)) {
22744 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22745 node.removeAttribute(n);
22749 var cwhite = this.cwhite;
22750 var cblack = this.cblack;
22752 function cleanStyle(n,v)
22754 if (v.match(/expression/)) { //XSS?? should we even bother..
22755 node.removeAttribute(n);
22759 var parts = v.split(/;/);
22762 Roo.each(parts, function(p) {
22763 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22767 var l = p.split(':').shift().replace(/\s+/g,'');
22768 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22770 if ( cwhite.length && cblack.indexOf(l) > -1) {
22771 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22772 //node.removeAttribute(n);
22776 // only allow 'c whitelisted system attributes'
22777 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22778 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22779 //node.removeAttribute(n);
22789 if (clean.length) {
22790 node.setAttribute(n, clean.join(';'));
22792 node.removeAttribute(n);
22798 for (var i = node.attributes.length-1; i > -1 ; i--) {
22799 var a = node.attributes[i];
22802 if (a.name.toLowerCase().substr(0,2)=='on') {
22803 node.removeAttribute(a.name);
22806 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22807 node.removeAttribute(a.name);
22810 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22811 cleanAttr(a.name,a.value); // fixme..
22814 if (a.name == 'style') {
22815 cleanStyle(a.name,a.value);
22818 /// clean up MS crap..
22819 // tecnically this should be a list of valid class'es..
22822 if (a.name == 'class') {
22823 if (a.value.match(/^Mso/)) {
22824 node.className = '';
22827 if (a.value.match(/^body$/)) {
22828 node.className = '';
22839 this.cleanUpChildren(node);
22845 * Clean up MS wordisms...
22847 cleanWord : function(node)
22852 this.cleanWord(this.doc.body);
22855 if (node.nodeName == "#text") {
22856 // clean up silly Windows -- stuff?
22859 if (node.nodeName == "#comment") {
22860 node.parentNode.removeChild(node);
22861 // clean up silly Windows -- stuff?
22865 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22866 node.parentNode.removeChild(node);
22870 // remove - but keep children..
22871 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22872 while (node.childNodes.length) {
22873 var cn = node.childNodes[0];
22874 node.removeChild(cn);
22875 node.parentNode.insertBefore(cn, node);
22877 node.parentNode.removeChild(node);
22878 this.iterateChildren(node, this.cleanWord);
22882 if (node.className.length) {
22884 var cn = node.className.split(/\W+/);
22886 Roo.each(cn, function(cls) {
22887 if (cls.match(/Mso[a-zA-Z]+/)) {
22892 node.className = cna.length ? cna.join(' ') : '';
22894 node.removeAttribute("class");
22898 if (node.hasAttribute("lang")) {
22899 node.removeAttribute("lang");
22902 if (node.hasAttribute("style")) {
22904 var styles = node.getAttribute("style").split(";");
22906 Roo.each(styles, function(s) {
22907 if (!s.match(/:/)) {
22910 var kv = s.split(":");
22911 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22914 // what ever is left... we allow.
22917 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22918 if (!nstyle.length) {
22919 node.removeAttribute('style');
22922 this.iterateChildren(node, this.cleanWord);
22928 * iterateChildren of a Node, calling fn each time, using this as the scole..
22929 * @param {DomNode} node node to iterate children of.
22930 * @param {Function} fn method of this class to call on each item.
22932 iterateChildren : function(node, fn)
22934 if (!node.childNodes.length) {
22937 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22938 fn.call(this, node.childNodes[i])
22944 * cleanTableWidths.
22946 * Quite often pasting from word etc.. results in tables with column and widths.
22947 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22950 cleanTableWidths : function(node)
22955 this.cleanTableWidths(this.doc.body);
22960 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22963 Roo.log(node.tagName);
22964 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22965 this.iterateChildren(node, this.cleanTableWidths);
22968 if (node.hasAttribute('width')) {
22969 node.removeAttribute('width');
22973 if (node.hasAttribute("style")) {
22976 var styles = node.getAttribute("style").split(";");
22978 Roo.each(styles, function(s) {
22979 if (!s.match(/:/)) {
22982 var kv = s.split(":");
22983 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22986 // what ever is left... we allow.
22989 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22990 if (!nstyle.length) {
22991 node.removeAttribute('style');
22995 this.iterateChildren(node, this.cleanTableWidths);
23003 domToHTML : function(currentElement, depth, nopadtext) {
23005 depth = depth || 0;
23006 nopadtext = nopadtext || false;
23008 if (!currentElement) {
23009 return this.domToHTML(this.doc.body);
23012 //Roo.log(currentElement);
23014 var allText = false;
23015 var nodeName = currentElement.nodeName;
23016 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23018 if (nodeName == '#text') {
23020 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23025 if (nodeName != 'BODY') {
23028 // Prints the node tagName, such as <A>, <IMG>, etc
23031 for(i = 0; i < currentElement.attributes.length;i++) {
23033 var aname = currentElement.attributes.item(i).name;
23034 if (!currentElement.attributes.item(i).value.length) {
23037 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23040 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23049 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23052 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23057 // Traverse the tree
23059 var currentElementChild = currentElement.childNodes.item(i);
23060 var allText = true;
23061 var innerHTML = '';
23063 while (currentElementChild) {
23064 // Formatting code (indent the tree so it looks nice on the screen)
23065 var nopad = nopadtext;
23066 if (lastnode == 'SPAN') {
23070 if (currentElementChild.nodeName == '#text') {
23071 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23072 toadd = nopadtext ? toadd : toadd.trim();
23073 if (!nopad && toadd.length > 80) {
23074 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23076 innerHTML += toadd;
23079 currentElementChild = currentElement.childNodes.item(i);
23085 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23087 // Recursively traverse the tree structure of the child node
23088 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23089 lastnode = currentElementChild.nodeName;
23091 currentElementChild=currentElement.childNodes.item(i);
23097 // The remaining code is mostly for formatting the tree
23098 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23103 ret+= "</"+tagName+">";
23109 applyBlacklists : function()
23111 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23112 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23116 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23117 if (b.indexOf(tag) > -1) {
23120 this.white.push(tag);
23124 Roo.each(w, function(tag) {
23125 if (b.indexOf(tag) > -1) {
23128 if (this.white.indexOf(tag) > -1) {
23131 this.white.push(tag);
23136 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23137 if (w.indexOf(tag) > -1) {
23140 this.black.push(tag);
23144 Roo.each(b, function(tag) {
23145 if (w.indexOf(tag) > -1) {
23148 if (this.black.indexOf(tag) > -1) {
23151 this.black.push(tag);
23156 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23157 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23161 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23162 if (b.indexOf(tag) > -1) {
23165 this.cwhite.push(tag);
23169 Roo.each(w, function(tag) {
23170 if (b.indexOf(tag) > -1) {
23173 if (this.cwhite.indexOf(tag) > -1) {
23176 this.cwhite.push(tag);
23181 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23182 if (w.indexOf(tag) > -1) {
23185 this.cblack.push(tag);
23189 Roo.each(b, function(tag) {
23190 if (w.indexOf(tag) > -1) {
23193 if (this.cblack.indexOf(tag) > -1) {
23196 this.cblack.push(tag);
23201 setStylesheets : function(stylesheets)
23203 if(typeof(stylesheets) == 'string'){
23204 Roo.get(this.iframe.contentDocument.head).createChild({
23206 rel : 'stylesheet',
23215 Roo.each(stylesheets, function(s) {
23220 Roo.get(_this.iframe.contentDocument.head).createChild({
23222 rel : 'stylesheet',
23231 removeStylesheets : function()
23235 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23240 setStyle : function(style)
23242 Roo.get(this.iframe.contentDocument.head).createChild({
23251 // hide stuff that is not compatible
23265 * @event specialkey
23269 * @cfg {String} fieldClass @hide
23272 * @cfg {String} focusClass @hide
23275 * @cfg {String} autoCreate @hide
23278 * @cfg {String} inputType @hide
23281 * @cfg {String} invalidClass @hide
23284 * @cfg {String} invalidText @hide
23287 * @cfg {String} msgFx @hide
23290 * @cfg {String} validateOnBlur @hide
23294 Roo.HtmlEditorCore.white = [
23295 'area', 'br', 'img', 'input', 'hr', 'wbr',
23297 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23298 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23299 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23300 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23301 'table', 'ul', 'xmp',
23303 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23306 'dir', 'menu', 'ol', 'ul', 'dl',
23312 Roo.HtmlEditorCore.black = [
23313 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23315 'base', 'basefont', 'bgsound', 'blink', 'body',
23316 'frame', 'frameset', 'head', 'html', 'ilayer',
23317 'iframe', 'layer', 'link', 'meta', 'object',
23318 'script', 'style' ,'title', 'xml' // clean later..
23320 Roo.HtmlEditorCore.clean = [
23321 'script', 'style', 'title', 'xml'
23323 Roo.HtmlEditorCore.remove = [
23328 Roo.HtmlEditorCore.ablack = [
23332 Roo.HtmlEditorCore.aclean = [
23333 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23337 Roo.HtmlEditorCore.pwhite= [
23338 'http', 'https', 'mailto'
23341 // white listed style attributes.
23342 Roo.HtmlEditorCore.cwhite= [
23343 // 'text-align', /// default is to allow most things..
23349 // black listed style attributes.
23350 Roo.HtmlEditorCore.cblack= [
23351 // 'font-size' -- this can be set by the project
23355 Roo.HtmlEditorCore.swapCodes =[
23374 * @class Roo.bootstrap.HtmlEditor
23375 * @extends Roo.bootstrap.TextArea
23376 * Bootstrap HtmlEditor class
23379 * Create a new HtmlEditor
23380 * @param {Object} config The config object
23383 Roo.bootstrap.HtmlEditor = function(config){
23384 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23385 if (!this.toolbars) {
23386 this.toolbars = [];
23389 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23392 * @event initialize
23393 * Fires when the editor is fully initialized (including the iframe)
23394 * @param {HtmlEditor} this
23399 * Fires when the editor is first receives the focus. Any insertion must wait
23400 * until after this event.
23401 * @param {HtmlEditor} this
23405 * @event beforesync
23406 * Fires before the textarea is updated with content from the editor iframe. Return false
23407 * to cancel the sync.
23408 * @param {HtmlEditor} this
23409 * @param {String} html
23413 * @event beforepush
23414 * Fires before the iframe editor is updated with content from the textarea. Return false
23415 * to cancel the push.
23416 * @param {HtmlEditor} this
23417 * @param {String} html
23422 * Fires when the textarea is updated with content from the editor iframe.
23423 * @param {HtmlEditor} this
23424 * @param {String} html
23429 * Fires when the iframe editor is updated with content from the textarea.
23430 * @param {HtmlEditor} this
23431 * @param {String} html
23435 * @event editmodechange
23436 * Fires when the editor switches edit modes
23437 * @param {HtmlEditor} this
23438 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23440 editmodechange: true,
23442 * @event editorevent
23443 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23444 * @param {HtmlEditor} this
23448 * @event firstfocus
23449 * Fires when on first focus - needed by toolbars..
23450 * @param {HtmlEditor} this
23455 * Auto save the htmlEditor value as a file into Events
23456 * @param {HtmlEditor} this
23460 * @event savedpreview
23461 * preview the saved version of htmlEditor
23462 * @param {HtmlEditor} this
23469 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23473 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23478 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23483 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23488 * @cfg {Number} height (in pixels)
23492 * @cfg {Number} width (in pixels)
23497 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23500 stylesheets: false,
23505 // private properties
23506 validationEvent : false,
23508 initialized : false,
23511 onFocus : Roo.emptyFn,
23513 hideMode:'offsets',
23515 tbContainer : false,
23519 toolbarContainer :function() {
23520 return this.wrap.select('.x-html-editor-tb',true).first();
23524 * Protected method that will not generally be called directly. It
23525 * is called when the editor creates its toolbar. Override this method if you need to
23526 * add custom toolbar buttons.
23527 * @param {HtmlEditor} editor
23529 createToolbar : function(){
23530 Roo.log('renewing');
23531 Roo.log("create toolbars");
23533 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23534 this.toolbars[0].render(this.toolbarContainer());
23538 // if (!editor.toolbars || !editor.toolbars.length) {
23539 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23542 // for (var i =0 ; i < editor.toolbars.length;i++) {
23543 // editor.toolbars[i] = Roo.factory(
23544 // typeof(editor.toolbars[i]) == 'string' ?
23545 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23546 // Roo.bootstrap.HtmlEditor);
23547 // editor.toolbars[i].init(editor);
23553 onRender : function(ct, position)
23555 // Roo.log("Call onRender: " + this.xtype);
23557 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23559 this.wrap = this.inputEl().wrap({
23560 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23563 this.editorcore.onRender(ct, position);
23565 if (this.resizable) {
23566 this.resizeEl = new Roo.Resizable(this.wrap, {
23570 minHeight : this.height,
23571 height: this.height,
23572 handles : this.resizable,
23575 resize : function(r, w, h) {
23576 _t.onResize(w,h); // -something
23582 this.createToolbar(this);
23585 if(!this.width && this.resizable){
23586 this.setSize(this.wrap.getSize());
23588 if (this.resizeEl) {
23589 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23590 // should trigger onReize..
23596 onResize : function(w, h)
23598 Roo.log('resize: ' +w + ',' + h );
23599 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23603 if(this.inputEl() ){
23604 if(typeof w == 'number'){
23605 var aw = w - this.wrap.getFrameWidth('lr');
23606 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23609 if(typeof h == 'number'){
23610 var tbh = -11; // fixme it needs to tool bar size!
23611 for (var i =0; i < this.toolbars.length;i++) {
23612 // fixme - ask toolbars for heights?
23613 tbh += this.toolbars[i].el.getHeight();
23614 //if (this.toolbars[i].footer) {
23615 // tbh += this.toolbars[i].footer.el.getHeight();
23623 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23624 ah -= 5; // knock a few pixes off for look..
23625 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23629 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23630 this.editorcore.onResize(ew,eh);
23635 * Toggles the editor between standard and source edit mode.
23636 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23638 toggleSourceEdit : function(sourceEditMode)
23640 this.editorcore.toggleSourceEdit(sourceEditMode);
23642 if(this.editorcore.sourceEditMode){
23643 Roo.log('editor - showing textarea');
23646 // Roo.log(this.syncValue());
23648 this.inputEl().removeClass(['hide', 'x-hidden']);
23649 this.inputEl().dom.removeAttribute('tabIndex');
23650 this.inputEl().focus();
23652 Roo.log('editor - hiding textarea');
23654 // Roo.log(this.pushValue());
23657 this.inputEl().addClass(['hide', 'x-hidden']);
23658 this.inputEl().dom.setAttribute('tabIndex', -1);
23659 //this.deferFocus();
23662 if(this.resizable){
23663 this.setSize(this.wrap.getSize());
23666 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23669 // private (for BoxComponent)
23670 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23672 // private (for BoxComponent)
23673 getResizeEl : function(){
23677 // private (for BoxComponent)
23678 getPositionEl : function(){
23683 initEvents : function(){
23684 this.originalValue = this.getValue();
23688 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23691 // markInvalid : Roo.emptyFn,
23693 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23696 // clearInvalid : Roo.emptyFn,
23698 setValue : function(v){
23699 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23700 this.editorcore.pushValue();
23705 deferFocus : function(){
23706 this.focus.defer(10, this);
23710 focus : function(){
23711 this.editorcore.focus();
23717 onDestroy : function(){
23723 for (var i =0; i < this.toolbars.length;i++) {
23724 // fixme - ask toolbars for heights?
23725 this.toolbars[i].onDestroy();
23728 this.wrap.dom.innerHTML = '';
23729 this.wrap.remove();
23734 onFirstFocus : function(){
23735 //Roo.log("onFirstFocus");
23736 this.editorcore.onFirstFocus();
23737 for (var i =0; i < this.toolbars.length;i++) {
23738 this.toolbars[i].onFirstFocus();
23744 syncValue : function()
23746 this.editorcore.syncValue();
23749 pushValue : function()
23751 this.editorcore.pushValue();
23755 // hide stuff that is not compatible
23769 * @event specialkey
23773 * @cfg {String} fieldClass @hide
23776 * @cfg {String} focusClass @hide
23779 * @cfg {String} autoCreate @hide
23782 * @cfg {String} inputType @hide
23785 * @cfg {String} invalidClass @hide
23788 * @cfg {String} invalidText @hide
23791 * @cfg {String} msgFx @hide
23794 * @cfg {String} validateOnBlur @hide
23803 Roo.namespace('Roo.bootstrap.htmleditor');
23805 * @class Roo.bootstrap.HtmlEditorToolbar1
23810 new Roo.bootstrap.HtmlEditor({
23813 new Roo.bootstrap.HtmlEditorToolbar1({
23814 disable : { fonts: 1 , format: 1, ..., ... , ...],
23820 * @cfg {Object} disable List of elements to disable..
23821 * @cfg {Array} btns List of additional buttons.
23825 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23828 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23831 Roo.apply(this, config);
23833 // default disabled, based on 'good practice'..
23834 this.disable = this.disable || {};
23835 Roo.applyIf(this.disable, {
23838 specialElements : true
23840 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23842 this.editor = config.editor;
23843 this.editorcore = config.editor.editorcore;
23845 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23847 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23848 // dont call parent... till later.
23850 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23855 editorcore : false,
23860 "h1","h2","h3","h4","h5","h6",
23862 "abbr", "acronym", "address", "cite", "samp", "var",
23866 onRender : function(ct, position)
23868 // Roo.log("Call onRender: " + this.xtype);
23870 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23872 this.el.dom.style.marginBottom = '0';
23874 var editorcore = this.editorcore;
23875 var editor= this.editor;
23878 var btn = function(id,cmd , toggle, handler, html){
23880 var event = toggle ? 'toggle' : 'click';
23885 xns: Roo.bootstrap,
23888 enableToggle:toggle !== false,
23890 pressed : toggle ? false : null,
23893 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23894 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23900 // var cb_box = function...
23905 xns: Roo.bootstrap,
23906 glyphicon : 'font',
23910 xns: Roo.bootstrap,
23914 Roo.each(this.formats, function(f) {
23915 style.menu.items.push({
23917 xns: Roo.bootstrap,
23918 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23923 editorcore.insertTag(this.tagname);
23930 children.push(style);
23932 btn('bold',false,true);
23933 btn('italic',false,true);
23934 btn('align-left', 'justifyleft',true);
23935 btn('align-center', 'justifycenter',true);
23936 btn('align-right' , 'justifyright',true);
23937 btn('link', false, false, function(btn) {
23938 //Roo.log("create link?");
23939 var url = prompt(this.createLinkText, this.defaultLinkValue);
23940 if(url && url != 'http:/'+'/'){
23941 this.editorcore.relayCmd('createlink', url);
23944 btn('list','insertunorderedlist',true);
23945 btn('pencil', false,true, function(btn){
23947 this.toggleSourceEdit(btn.pressed);
23950 if (this.editor.btns.length > 0) {
23951 for (var i = 0; i<this.editor.btns.length; i++) {
23952 children.push(this.editor.btns[i]);
23960 xns: Roo.bootstrap,
23965 xns: Roo.bootstrap,
23970 cog.menu.items.push({
23972 xns: Roo.bootstrap,
23973 html : Clean styles,
23978 editorcore.insertTag(this.tagname);
23987 this.xtype = 'NavSimplebar';
23989 for(var i=0;i< children.length;i++) {
23991 this.buttons.add(this.addxtypeChild(children[i]));
23995 editor.on('editorevent', this.updateToolbar, this);
23997 onBtnClick : function(id)
23999 this.editorcore.relayCmd(id);
24000 this.editorcore.focus();
24004 * Protected method that will not generally be called directly. It triggers
24005 * a toolbar update by reading the markup state of the current selection in the editor.
24007 updateToolbar: function(){
24009 if(!this.editorcore.activated){
24010 this.editor.onFirstFocus(); // is this neeed?
24014 var btns = this.buttons;
24015 var doc = this.editorcore.doc;
24016 btns.get('bold').setActive(doc.queryCommandState('bold'));
24017 btns.get('italic').setActive(doc.queryCommandState('italic'));
24018 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24020 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24021 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24022 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24024 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24025 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24028 var ans = this.editorcore.getAllAncestors();
24029 if (this.formatCombo) {
24032 var store = this.formatCombo.store;
24033 this.formatCombo.setValue("");
24034 for (var i =0; i < ans.length;i++) {
24035 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24037 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24045 // hides menus... - so this cant be on a menu...
24046 Roo.bootstrap.MenuMgr.hideAll();
24048 Roo.bootstrap.MenuMgr.hideAll();
24049 //this.editorsyncValue();
24051 onFirstFocus: function() {
24052 this.buttons.each(function(item){
24056 toggleSourceEdit : function(sourceEditMode){
24059 if(sourceEditMode){
24060 Roo.log("disabling buttons");
24061 this.buttons.each( function(item){
24062 if(item.cmd != 'pencil'){
24068 Roo.log("enabling buttons");
24069 if(this.editorcore.initialized){
24070 this.buttons.each( function(item){
24076 Roo.log("calling toggole on editor");
24077 // tell the editor that it's been pressed..
24078 this.editor.toggleSourceEdit(sourceEditMode);
24088 * @class Roo.bootstrap.Table.AbstractSelectionModel
24089 * @extends Roo.util.Observable
24090 * Abstract base class for grid SelectionModels. It provides the interface that should be
24091 * implemented by descendant classes. This class should not be directly instantiated.
24094 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24095 this.locked = false;
24096 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24100 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24101 /** @ignore Called by the grid automatically. Do not call directly. */
24102 init : function(grid){
24108 * Locks the selections.
24111 this.locked = true;
24115 * Unlocks the selections.
24117 unlock : function(){
24118 this.locked = false;
24122 * Returns true if the selections are locked.
24123 * @return {Boolean}
24125 isLocked : function(){
24126 return this.locked;
24130 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24131 * @class Roo.bootstrap.Table.RowSelectionModel
24132 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24133 * It supports multiple selections and keyboard selection/navigation.
24135 * @param {Object} config
24138 Roo.bootstrap.Table.RowSelectionModel = function(config){
24139 Roo.apply(this, config);
24140 this.selections = new Roo.util.MixedCollection(false, function(o){
24145 this.lastActive = false;
24149 * @event selectionchange
24150 * Fires when the selection changes
24151 * @param {SelectionModel} this
24153 "selectionchange" : true,
24155 * @event afterselectionchange
24156 * Fires after the selection changes (eg. by key press or clicking)
24157 * @param {SelectionModel} this
24159 "afterselectionchange" : true,
24161 * @event beforerowselect
24162 * Fires when a row is selected being selected, return false to cancel.
24163 * @param {SelectionModel} this
24164 * @param {Number} rowIndex The selected index
24165 * @param {Boolean} keepExisting False if other selections will be cleared
24167 "beforerowselect" : true,
24170 * Fires when a row is selected.
24171 * @param {SelectionModel} this
24172 * @param {Number} rowIndex The selected index
24173 * @param {Roo.data.Record} r The record
24175 "rowselect" : true,
24177 * @event rowdeselect
24178 * Fires when a row is deselected.
24179 * @param {SelectionModel} this
24180 * @param {Number} rowIndex The selected index
24182 "rowdeselect" : true
24184 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24185 this.locked = false;
24188 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24190 * @cfg {Boolean} singleSelect
24191 * True to allow selection of only one row at a time (defaults to false)
24193 singleSelect : false,
24196 initEvents : function()
24199 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24200 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24201 //}else{ // allow click to work like normal
24202 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24204 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24205 this.grid.on("rowclick", this.handleMouseDown, this);
24207 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24208 "up" : function(e){
24210 this.selectPrevious(e.shiftKey);
24211 }else if(this.last !== false && this.lastActive !== false){
24212 var last = this.last;
24213 this.selectRange(this.last, this.lastActive-1);
24214 this.grid.getView().focusRow(this.lastActive);
24215 if(last !== false){
24219 this.selectFirstRow();
24221 this.fireEvent("afterselectionchange", this);
24223 "down" : function(e){
24225 this.selectNext(e.shiftKey);
24226 }else if(this.last !== false && this.lastActive !== false){
24227 var last = this.last;
24228 this.selectRange(this.last, this.lastActive+1);
24229 this.grid.getView().focusRow(this.lastActive);
24230 if(last !== false){
24234 this.selectFirstRow();
24236 this.fireEvent("afterselectionchange", this);
24240 this.grid.store.on('load', function(){
24241 this.selections.clear();
24244 var view = this.grid.view;
24245 view.on("refresh", this.onRefresh, this);
24246 view.on("rowupdated", this.onRowUpdated, this);
24247 view.on("rowremoved", this.onRemove, this);
24252 onRefresh : function()
24254 var ds = this.grid.store, i, v = this.grid.view;
24255 var s = this.selections;
24256 s.each(function(r){
24257 if((i = ds.indexOfId(r.id)) != -1){
24266 onRemove : function(v, index, r){
24267 this.selections.remove(r);
24271 onRowUpdated : function(v, index, r){
24272 if(this.isSelected(r)){
24273 v.onRowSelect(index);
24279 * @param {Array} records The records to select
24280 * @param {Boolean} keepExisting (optional) True to keep existing selections
24282 selectRecords : function(records, keepExisting)
24285 this.clearSelections();
24287 var ds = this.grid.store;
24288 for(var i = 0, len = records.length; i < len; i++){
24289 this.selectRow(ds.indexOf(records[i]), true);
24294 * Gets the number of selected rows.
24297 getCount : function(){
24298 return this.selections.length;
24302 * Selects the first row in the grid.
24304 selectFirstRow : function(){
24309 * Select the last row.
24310 * @param {Boolean} keepExisting (optional) True to keep existing selections
24312 selectLastRow : function(keepExisting){
24313 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24314 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24318 * Selects the row immediately following the last selected row.
24319 * @param {Boolean} keepExisting (optional) True to keep existing selections
24321 selectNext : function(keepExisting)
24323 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24324 this.selectRow(this.last+1, keepExisting);
24325 this.grid.getView().focusRow(this.last);
24330 * Selects the row that precedes the last selected row.
24331 * @param {Boolean} keepExisting (optional) True to keep existing selections
24333 selectPrevious : function(keepExisting){
24335 this.selectRow(this.last-1, keepExisting);
24336 this.grid.getView().focusRow(this.last);
24341 * Returns the selected records
24342 * @return {Array} Array of selected records
24344 getSelections : function(){
24345 return [].concat(this.selections.items);
24349 * Returns the first selected record.
24352 getSelected : function(){
24353 return this.selections.itemAt(0);
24358 * Clears all selections.
24360 clearSelections : function(fast)
24366 var ds = this.grid.store;
24367 var s = this.selections;
24368 s.each(function(r){
24369 this.deselectRow(ds.indexOfId(r.id));
24373 this.selections.clear();
24380 * Selects all rows.
24382 selectAll : function(){
24386 this.selections.clear();
24387 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24388 this.selectRow(i, true);
24393 * Returns True if there is a selection.
24394 * @return {Boolean}
24396 hasSelection : function(){
24397 return this.selections.length > 0;
24401 * Returns True if the specified row is selected.
24402 * @param {Number/Record} record The record or index of the record to check
24403 * @return {Boolean}
24405 isSelected : function(index){
24406 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24407 return (r && this.selections.key(r.id) ? true : false);
24411 * Returns True if the specified record id is selected.
24412 * @param {String} id The id of record to check
24413 * @return {Boolean}
24415 isIdSelected : function(id){
24416 return (this.selections.key(id) ? true : false);
24421 handleMouseDBClick : function(e, t){
24425 handleMouseDown : function(e, t)
24427 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24428 if(this.isLocked() || rowIndex < 0 ){
24431 if(e.shiftKey && this.last !== false){
24432 var last = this.last;
24433 this.selectRange(last, rowIndex, e.ctrlKey);
24434 this.last = last; // reset the last
24438 var isSelected = this.isSelected(rowIndex);
24439 //Roo.log("select row:" + rowIndex);
24441 this.deselectRow(rowIndex);
24443 this.selectRow(rowIndex, true);
24447 if(e.button !== 0 && isSelected){
24448 alert('rowIndex 2: ' + rowIndex);
24449 view.focusRow(rowIndex);
24450 }else if(e.ctrlKey && isSelected){
24451 this.deselectRow(rowIndex);
24452 }else if(!isSelected){
24453 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24454 view.focusRow(rowIndex);
24458 this.fireEvent("afterselectionchange", this);
24461 handleDragableRowClick : function(grid, rowIndex, e)
24463 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24464 this.selectRow(rowIndex, false);
24465 grid.view.focusRow(rowIndex);
24466 this.fireEvent("afterselectionchange", this);
24471 * Selects multiple rows.
24472 * @param {Array} rows Array of the indexes of the row to select
24473 * @param {Boolean} keepExisting (optional) True to keep existing selections
24475 selectRows : function(rows, keepExisting){
24477 this.clearSelections();
24479 for(var i = 0, len = rows.length; i < len; i++){
24480 this.selectRow(rows[i], true);
24485 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24486 * @param {Number} startRow The index of the first row in the range
24487 * @param {Number} endRow The index of the last row in the range
24488 * @param {Boolean} keepExisting (optional) True to retain existing selections
24490 selectRange : function(startRow, endRow, keepExisting){
24495 this.clearSelections();
24497 if(startRow <= endRow){
24498 for(var i = startRow; i <= endRow; i++){
24499 this.selectRow(i, true);
24502 for(var i = startRow; i >= endRow; i--){
24503 this.selectRow(i, true);
24509 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24510 * @param {Number} startRow The index of the first row in the range
24511 * @param {Number} endRow The index of the last row in the range
24513 deselectRange : function(startRow, endRow, preventViewNotify){
24517 for(var i = startRow; i <= endRow; i++){
24518 this.deselectRow(i, preventViewNotify);
24524 * @param {Number} row The index of the row to select
24525 * @param {Boolean} keepExisting (optional) True to keep existing selections
24527 selectRow : function(index, keepExisting, preventViewNotify)
24529 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24532 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24533 if(!keepExisting || this.singleSelect){
24534 this.clearSelections();
24537 var r = this.grid.store.getAt(index);
24538 //console.log('selectRow - record id :' + r.id);
24540 this.selections.add(r);
24541 this.last = this.lastActive = index;
24542 if(!preventViewNotify){
24543 var proxy = new Roo.Element(
24544 this.grid.getRowDom(index)
24546 proxy.addClass('bg-info info');
24548 this.fireEvent("rowselect", this, index, r);
24549 this.fireEvent("selectionchange", this);
24555 * @param {Number} row The index of the row to deselect
24557 deselectRow : function(index, preventViewNotify)
24562 if(this.last == index){
24565 if(this.lastActive == index){
24566 this.lastActive = false;
24569 var r = this.grid.store.getAt(index);
24574 this.selections.remove(r);
24575 //.console.log('deselectRow - record id :' + r.id);
24576 if(!preventViewNotify){
24578 var proxy = new Roo.Element(
24579 this.grid.getRowDom(index)
24581 proxy.removeClass('bg-info info');
24583 this.fireEvent("rowdeselect", this, index);
24584 this.fireEvent("selectionchange", this);
24588 restoreLast : function(){
24590 this.last = this._last;
24595 acceptsNav : function(row, col, cm){
24596 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24600 onEditorKey : function(field, e){
24601 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24606 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24608 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24610 }else if(k == e.ENTER && !e.ctrlKey){
24614 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24616 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24618 }else if(k == e.ESC){
24622 g.startEditing(newCell[0], newCell[1]);
24628 * Ext JS Library 1.1.1
24629 * Copyright(c) 2006-2007, Ext JS, LLC.
24631 * Originally Released Under LGPL - original licence link has changed is not relivant.
24634 * <script type="text/javascript">
24638 * @class Roo.bootstrap.PagingToolbar
24639 * @extends Roo.bootstrap.NavSimplebar
24640 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24642 * Create a new PagingToolbar
24643 * @param {Object} config The config object
24644 * @param {Roo.data.Store} store
24646 Roo.bootstrap.PagingToolbar = function(config)
24648 // old args format still supported... - xtype is prefered..
24649 // created from xtype...
24651 this.ds = config.dataSource;
24653 if (config.store && !this.ds) {
24654 this.store= Roo.factory(config.store, Roo.data);
24655 this.ds = this.store;
24656 this.ds.xmodule = this.xmodule || false;
24659 this.toolbarItems = [];
24660 if (config.items) {
24661 this.toolbarItems = config.items;
24664 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24669 this.bind(this.ds);
24672 if (Roo.bootstrap.version == 4) {
24673 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24675 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24680 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24682 * @cfg {Roo.data.Store} dataSource
24683 * The underlying data store providing the paged data
24686 * @cfg {String/HTMLElement/Element} container
24687 * container The id or element that will contain the toolbar
24690 * @cfg {Boolean} displayInfo
24691 * True to display the displayMsg (defaults to false)
24694 * @cfg {Number} pageSize
24695 * The number of records to display per page (defaults to 20)
24699 * @cfg {String} displayMsg
24700 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24702 displayMsg : 'Displaying {0} - {1} of {2}',
24704 * @cfg {String} emptyMsg
24705 * The message to display when no records are found (defaults to "No data to display")
24707 emptyMsg : 'No data to display',
24709 * Customizable piece of the default paging text (defaults to "Page")
24712 beforePageText : "Page",
24714 * Customizable piece of the default paging text (defaults to "of %0")
24717 afterPageText : "of {0}",
24719 * Customizable piece of the default paging text (defaults to "First Page")
24722 firstText : "First Page",
24724 * Customizable piece of the default paging text (defaults to "Previous Page")
24727 prevText : "Previous Page",
24729 * Customizable piece of the default paging text (defaults to "Next Page")
24732 nextText : "Next Page",
24734 * Customizable piece of the default paging text (defaults to "Last Page")
24737 lastText : "Last Page",
24739 * Customizable piece of the default paging text (defaults to "Refresh")
24742 refreshText : "Refresh",
24746 onRender : function(ct, position)
24748 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24749 this.navgroup.parentId = this.id;
24750 this.navgroup.onRender(this.el, null);
24751 // add the buttons to the navgroup
24753 if(this.displayInfo){
24754 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24755 this.displayEl = this.el.select('.x-paging-info', true).first();
24756 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24757 // this.displayEl = navel.el.select('span',true).first();
24763 Roo.each(_this.buttons, function(e){ // this might need to use render????
24764 Roo.factory(e).render(_this.el);
24768 Roo.each(_this.toolbarItems, function(e) {
24769 _this.navgroup.addItem(e);
24773 this.first = this.navgroup.addItem({
24774 tooltip: this.firstText,
24775 cls: "prev btn-outline-secondary",
24776 html : ' <i class="fa fa-step-backward"></i>',
24778 preventDefault: true,
24779 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24782 this.prev = this.navgroup.addItem({
24783 tooltip: this.prevText,
24784 cls: "prev btn-outline-secondary",
24785 html : ' <i class="fa fa-backward"></i>',
24787 preventDefault: true,
24788 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24790 //this.addSeparator();
24793 var field = this.navgroup.addItem( {
24795 cls : 'x-paging-position btn-outline-secondary',
24797 html : this.beforePageText +
24798 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24799 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24802 this.field = field.el.select('input', true).first();
24803 this.field.on("keydown", this.onPagingKeydown, this);
24804 this.field.on("focus", function(){this.dom.select();});
24807 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24808 //this.field.setHeight(18);
24809 //this.addSeparator();
24810 this.next = this.navgroup.addItem({
24811 tooltip: this.nextText,
24812 cls: "next btn-outline-secondary",
24813 html : ' <i class="fa fa-forward"></i>',
24815 preventDefault: true,
24816 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24818 this.last = this.navgroup.addItem({
24819 tooltip: this.lastText,
24820 html : ' <i class="fa fa-step-forward"></i>',
24821 cls: "next btn-outline-secondary",
24823 preventDefault: true,
24824 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24826 //this.addSeparator();
24827 this.loading = this.navgroup.addItem({
24828 tooltip: this.refreshText,
24829 cls: "btn-outline-secondary",
24830 html : ' <i class="fa fa-refresh"></i>',
24831 preventDefault: true,
24832 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24838 updateInfo : function(){
24839 if(this.displayEl){
24840 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24841 var msg = count == 0 ?
24845 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24847 this.displayEl.update(msg);
24852 onLoad : function(ds, r, o)
24854 this.cursor = o.params.start ? o.params.start : 0;
24856 var d = this.getPageData(),
24861 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24862 this.field.dom.value = ap;
24863 this.first.setDisabled(ap == 1);
24864 this.prev.setDisabled(ap == 1);
24865 this.next.setDisabled(ap == ps);
24866 this.last.setDisabled(ap == ps);
24867 this.loading.enable();
24872 getPageData : function(){
24873 var total = this.ds.getTotalCount();
24876 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24877 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24882 onLoadError : function(){
24883 this.loading.enable();
24887 onPagingKeydown : function(e){
24888 var k = e.getKey();
24889 var d = this.getPageData();
24891 var v = this.field.dom.value, pageNum;
24892 if(!v || isNaN(pageNum = parseInt(v, 10))){
24893 this.field.dom.value = d.activePage;
24896 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24897 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24900 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))
24902 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24903 this.field.dom.value = pageNum;
24904 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24907 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24909 var v = this.field.dom.value, pageNum;
24910 var increment = (e.shiftKey) ? 10 : 1;
24911 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24914 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24915 this.field.dom.value = d.activePage;
24918 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24920 this.field.dom.value = parseInt(v, 10) + increment;
24921 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24922 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24929 beforeLoad : function(){
24931 this.loading.disable();
24936 onClick : function(which){
24945 ds.load({params:{start: 0, limit: this.pageSize}});
24948 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24951 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24954 var total = ds.getTotalCount();
24955 var extra = total % this.pageSize;
24956 var lastStart = extra ? (total - extra) : total-this.pageSize;
24957 ds.load({params:{start: lastStart, limit: this.pageSize}});
24960 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24966 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24967 * @param {Roo.data.Store} store The data store to unbind
24969 unbind : function(ds){
24970 ds.un("beforeload", this.beforeLoad, this);
24971 ds.un("load", this.onLoad, this);
24972 ds.un("loadexception", this.onLoadError, this);
24973 ds.un("remove", this.updateInfo, this);
24974 ds.un("add", this.updateInfo, this);
24975 this.ds = undefined;
24979 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24980 * @param {Roo.data.Store} store The data store to bind
24982 bind : function(ds){
24983 ds.on("beforeload", this.beforeLoad, this);
24984 ds.on("load", this.onLoad, this);
24985 ds.on("loadexception", this.onLoadError, this);
24986 ds.on("remove", this.updateInfo, this);
24987 ds.on("add", this.updateInfo, this);
24998 * @class Roo.bootstrap.MessageBar
24999 * @extends Roo.bootstrap.Component
25000 * Bootstrap MessageBar class
25001 * @cfg {String} html contents of the MessageBar
25002 * @cfg {String} weight (info | success | warning | danger) default info
25003 * @cfg {String} beforeClass insert the bar before the given class
25004 * @cfg {Boolean} closable (true | false) default false
25005 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25008 * Create a new Element
25009 * @param {Object} config The config object
25012 Roo.bootstrap.MessageBar = function(config){
25013 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25016 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25022 beforeClass: 'bootstrap-sticky-wrap',
25024 getAutoCreate : function(){
25028 cls: 'alert alert-dismissable alert-' + this.weight,
25033 html: this.html || ''
25039 cfg.cls += ' alert-messages-fixed';
25053 onRender : function(ct, position)
25055 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25058 var cfg = Roo.apply({}, this.getAutoCreate());
25062 cfg.cls += ' ' + this.cls;
25065 cfg.style = this.style;
25067 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25069 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25072 this.el.select('>button.close').on('click', this.hide, this);
25078 if (!this.rendered) {
25084 this.fireEvent('show', this);
25090 if (!this.rendered) {
25096 this.fireEvent('hide', this);
25099 update : function()
25101 // var e = this.el.dom.firstChild;
25103 // if(this.closable){
25104 // e = e.nextSibling;
25107 // e.data = this.html || '';
25109 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25125 * @class Roo.bootstrap.Graph
25126 * @extends Roo.bootstrap.Component
25127 * Bootstrap Graph class
25131 @cfg {String} graphtype bar | vbar | pie
25132 @cfg {number} g_x coodinator | centre x (pie)
25133 @cfg {number} g_y coodinator | centre y (pie)
25134 @cfg {number} g_r radius (pie)
25135 @cfg {number} g_height height of the chart (respected by all elements in the set)
25136 @cfg {number} g_width width of the chart (respected by all elements in the set)
25137 @cfg {Object} title The title of the chart
25140 -opts (object) options for the chart
25142 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25143 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25145 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.
25146 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25148 o stretch (boolean)
25150 -opts (object) options for the pie
25153 o startAngle (number)
25154 o endAngle (number)
25158 * Create a new Input
25159 * @param {Object} config The config object
25162 Roo.bootstrap.Graph = function(config){
25163 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25169 * The img click event for the img.
25170 * @param {Roo.EventObject} e
25176 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25187 //g_colors: this.colors,
25194 getAutoCreate : function(){
25205 onRender : function(ct,position){
25208 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25210 if (typeof(Raphael) == 'undefined') {
25211 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25215 this.raphael = Raphael(this.el.dom);
25217 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25218 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25219 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25220 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25222 r.text(160, 10, "Single Series Chart").attr(txtattr);
25223 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25224 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25225 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25227 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25228 r.barchart(330, 10, 300, 220, data1);
25229 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25230 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25233 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25234 // r.barchart(30, 30, 560, 250, xdata, {
25235 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25236 // axis : "0 0 1 1",
25237 // axisxlabels : xdata
25238 // //yvalues : cols,
25241 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25243 // this.load(null,xdata,{
25244 // axis : "0 0 1 1",
25245 // axisxlabels : xdata
25250 load : function(graphtype,xdata,opts)
25252 this.raphael.clear();
25254 graphtype = this.graphtype;
25259 var r = this.raphael,
25260 fin = function () {
25261 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25263 fout = function () {
25264 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25266 pfin = function() {
25267 this.sector.stop();
25268 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25271 this.label[0].stop();
25272 this.label[0].attr({ r: 7.5 });
25273 this.label[1].attr({ "font-weight": 800 });
25276 pfout = function() {
25277 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25280 this.label[0].animate({ r: 5 }, 500, "bounce");
25281 this.label[1].attr({ "font-weight": 400 });
25287 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25290 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25293 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25294 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25296 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25303 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25308 setTitle: function(o)
25313 initEvents: function() {
25316 this.el.on('click', this.onClick, this);
25320 onClick : function(e)
25322 Roo.log('img onclick');
25323 this.fireEvent('click', this, e);
25335 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25338 * @class Roo.bootstrap.dash.NumberBox
25339 * @extends Roo.bootstrap.Component
25340 * Bootstrap NumberBox class
25341 * @cfg {String} headline Box headline
25342 * @cfg {String} content Box content
25343 * @cfg {String} icon Box icon
25344 * @cfg {String} footer Footer text
25345 * @cfg {String} fhref Footer href
25348 * Create a new NumberBox
25349 * @param {Object} config The config object
25353 Roo.bootstrap.dash.NumberBox = function(config){
25354 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25358 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25367 getAutoCreate : function(){
25371 cls : 'small-box ',
25379 cls : 'roo-headline',
25380 html : this.headline
25384 cls : 'roo-content',
25385 html : this.content
25399 cls : 'ion ' + this.icon
25408 cls : 'small-box-footer',
25409 href : this.fhref || '#',
25413 cfg.cn.push(footer);
25420 onRender : function(ct,position){
25421 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25428 setHeadline: function (value)
25430 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25433 setFooter: function (value, href)
25435 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25438 this.el.select('a.small-box-footer',true).first().attr('href', href);
25443 setContent: function (value)
25445 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25448 initEvents: function()
25462 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25465 * @class Roo.bootstrap.dash.TabBox
25466 * @extends Roo.bootstrap.Component
25467 * Bootstrap TabBox class
25468 * @cfg {String} title Title of the TabBox
25469 * @cfg {String} icon Icon of the TabBox
25470 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25471 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25474 * Create a new TabBox
25475 * @param {Object} config The config object
25479 Roo.bootstrap.dash.TabBox = function(config){
25480 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25485 * When a pane is added
25486 * @param {Roo.bootstrap.dash.TabPane} pane
25490 * @event activatepane
25491 * When a pane is activated
25492 * @param {Roo.bootstrap.dash.TabPane} pane
25494 "activatepane" : true
25502 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25507 tabScrollable : false,
25509 getChildContainer : function()
25511 return this.el.select('.tab-content', true).first();
25514 getAutoCreate : function(){
25518 cls: 'pull-left header',
25526 cls: 'fa ' + this.icon
25532 cls: 'nav nav-tabs pull-right',
25538 if(this.tabScrollable){
25545 cls: 'nav nav-tabs pull-right',
25556 cls: 'nav-tabs-custom',
25561 cls: 'tab-content no-padding',
25569 initEvents : function()
25571 //Roo.log('add add pane handler');
25572 this.on('addpane', this.onAddPane, this);
25575 * Updates the box title
25576 * @param {String} html to set the title to.
25578 setTitle : function(value)
25580 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25582 onAddPane : function(pane)
25584 this.panes.push(pane);
25585 //Roo.log('addpane');
25587 // tabs are rendere left to right..
25588 if(!this.showtabs){
25592 var ctr = this.el.select('.nav-tabs', true).first();
25595 var existing = ctr.select('.nav-tab',true);
25596 var qty = existing.getCount();;
25599 var tab = ctr.createChild({
25601 cls : 'nav-tab' + (qty ? '' : ' active'),
25609 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25612 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25614 pane.el.addClass('active');
25619 onTabClick : function(ev,un,ob,pane)
25621 //Roo.log('tab - prev default');
25622 ev.preventDefault();
25625 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25626 pane.tab.addClass('active');
25627 //Roo.log(pane.title);
25628 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25629 // technically we should have a deactivate event.. but maybe add later.
25630 // and it should not de-activate the selected tab...
25631 this.fireEvent('activatepane', pane);
25632 pane.el.addClass('active');
25633 pane.fireEvent('activate');
25638 getActivePane : function()
25641 Roo.each(this.panes, function(p) {
25642 if(p.el.hasClass('active')){
25663 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25665 * @class Roo.bootstrap.TabPane
25666 * @extends Roo.bootstrap.Component
25667 * Bootstrap TabPane class
25668 * @cfg {Boolean} active (false | true) Default false
25669 * @cfg {String} title title of panel
25673 * Create a new TabPane
25674 * @param {Object} config The config object
25677 Roo.bootstrap.dash.TabPane = function(config){
25678 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25684 * When a pane is activated
25685 * @param {Roo.bootstrap.dash.TabPane} pane
25692 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25697 // the tabBox that this is attached to.
25700 getAutoCreate : function()
25708 cfg.cls += ' active';
25713 initEvents : function()
25715 //Roo.log('trigger add pane handler');
25716 this.parent().fireEvent('addpane', this)
25720 * Updates the tab title
25721 * @param {String} html to set the title to.
25723 setTitle: function(str)
25729 this.tab.select('a', true).first().dom.innerHTML = str;
25746 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25749 * @class Roo.bootstrap.menu.Menu
25750 * @extends Roo.bootstrap.Component
25751 * Bootstrap Menu class - container for Menu
25752 * @cfg {String} html Text of the menu
25753 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25754 * @cfg {String} icon Font awesome icon
25755 * @cfg {String} pos Menu align to (top | bottom) default bottom
25759 * Create a new Menu
25760 * @param {Object} config The config object
25764 Roo.bootstrap.menu.Menu = function(config){
25765 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25769 * @event beforeshow
25770 * Fires before this menu is displayed
25771 * @param {Roo.bootstrap.menu.Menu} this
25775 * @event beforehide
25776 * Fires before this menu is hidden
25777 * @param {Roo.bootstrap.menu.Menu} this
25782 * Fires after this menu is displayed
25783 * @param {Roo.bootstrap.menu.Menu} this
25788 * Fires after this menu is hidden
25789 * @param {Roo.bootstrap.menu.Menu} this
25794 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25795 * @param {Roo.bootstrap.menu.Menu} this
25796 * @param {Roo.EventObject} e
25803 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25807 weight : 'default',
25812 getChildContainer : function() {
25813 if(this.isSubMenu){
25817 return this.el.select('ul.dropdown-menu', true).first();
25820 getAutoCreate : function()
25825 cls : 'roo-menu-text',
25833 cls : 'fa ' + this.icon
25844 cls : 'dropdown-button btn btn-' + this.weight,
25849 cls : 'dropdown-toggle btn btn-' + this.weight,
25859 cls : 'dropdown-menu'
25865 if(this.pos == 'top'){
25866 cfg.cls += ' dropup';
25869 if(this.isSubMenu){
25872 cls : 'dropdown-menu'
25879 onRender : function(ct, position)
25881 this.isSubMenu = ct.hasClass('dropdown-submenu');
25883 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25886 initEvents : function()
25888 if(this.isSubMenu){
25892 this.hidden = true;
25894 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25895 this.triggerEl.on('click', this.onTriggerPress, this);
25897 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25898 this.buttonEl.on('click', this.onClick, this);
25904 if(this.isSubMenu){
25908 return this.el.select('ul.dropdown-menu', true).first();
25911 onClick : function(e)
25913 this.fireEvent("click", this, e);
25916 onTriggerPress : function(e)
25918 if (this.isVisible()) {
25925 isVisible : function(){
25926 return !this.hidden;
25931 this.fireEvent("beforeshow", this);
25933 this.hidden = false;
25934 this.el.addClass('open');
25936 Roo.get(document).on("mouseup", this.onMouseUp, this);
25938 this.fireEvent("show", this);
25945 this.fireEvent("beforehide", this);
25947 this.hidden = true;
25948 this.el.removeClass('open');
25950 Roo.get(document).un("mouseup", this.onMouseUp);
25952 this.fireEvent("hide", this);
25955 onMouseUp : function()
25969 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25972 * @class Roo.bootstrap.menu.Item
25973 * @extends Roo.bootstrap.Component
25974 * Bootstrap MenuItem class
25975 * @cfg {Boolean} submenu (true | false) default false
25976 * @cfg {String} html text of the item
25977 * @cfg {String} href the link
25978 * @cfg {Boolean} disable (true | false) default false
25979 * @cfg {Boolean} preventDefault (true | false) default true
25980 * @cfg {String} icon Font awesome icon
25981 * @cfg {String} pos Submenu align to (left | right) default right
25985 * Create a new Item
25986 * @param {Object} config The config object
25990 Roo.bootstrap.menu.Item = function(config){
25991 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25995 * Fires when the mouse is hovering over this menu
25996 * @param {Roo.bootstrap.menu.Item} this
25997 * @param {Roo.EventObject} e
26002 * Fires when the mouse exits this menu
26003 * @param {Roo.bootstrap.menu.Item} this
26004 * @param {Roo.EventObject} e
26010 * The raw click event for the entire grid.
26011 * @param {Roo.EventObject} e
26017 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26022 preventDefault: true,
26027 getAutoCreate : function()
26032 cls : 'roo-menu-item-text',
26040 cls : 'fa ' + this.icon
26049 href : this.href || '#',
26056 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26060 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26062 if(this.pos == 'left'){
26063 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26070 initEvents : function()
26072 this.el.on('mouseover', this.onMouseOver, this);
26073 this.el.on('mouseout', this.onMouseOut, this);
26075 this.el.select('a', true).first().on('click', this.onClick, this);
26079 onClick : function(e)
26081 if(this.preventDefault){
26082 e.preventDefault();
26085 this.fireEvent("click", this, e);
26088 onMouseOver : function(e)
26090 if(this.submenu && this.pos == 'left'){
26091 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26094 this.fireEvent("mouseover", this, e);
26097 onMouseOut : function(e)
26099 this.fireEvent("mouseout", this, e);
26111 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26114 * @class Roo.bootstrap.menu.Separator
26115 * @extends Roo.bootstrap.Component
26116 * Bootstrap Separator class
26119 * Create a new Separator
26120 * @param {Object} config The config object
26124 Roo.bootstrap.menu.Separator = function(config){
26125 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26128 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26130 getAutoCreate : function(){
26151 * @class Roo.bootstrap.Tooltip
26152 * Bootstrap Tooltip class
26153 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26154 * to determine which dom element triggers the tooltip.
26156 * It needs to add support for additional attributes like tooltip-position
26159 * Create a new Toolti
26160 * @param {Object} config The config object
26163 Roo.bootstrap.Tooltip = function(config){
26164 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26166 this.alignment = Roo.bootstrap.Tooltip.alignment;
26168 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26169 this.alignment = config.alignment;
26174 Roo.apply(Roo.bootstrap.Tooltip, {
26176 * @function init initialize tooltip monitoring.
26180 currentTip : false,
26181 currentRegion : false,
26187 Roo.get(document).on('mouseover', this.enter ,this);
26188 Roo.get(document).on('mouseout', this.leave, this);
26191 this.currentTip = new Roo.bootstrap.Tooltip();
26194 enter : function(ev)
26196 var dom = ev.getTarget();
26198 //Roo.log(['enter',dom]);
26199 var el = Roo.fly(dom);
26200 if (this.currentEl) {
26202 //Roo.log(this.currentEl);
26203 //Roo.log(this.currentEl.contains(dom));
26204 if (this.currentEl == el) {
26207 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26213 if (this.currentTip.el) {
26214 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26218 if(!el || el.dom == document){
26224 // you can not look for children, as if el is the body.. then everythign is the child..
26225 if (!el.attr('tooltip')) { //
26226 if (!el.select("[tooltip]").elements.length) {
26229 // is the mouse over this child...?
26230 bindEl = el.select("[tooltip]").first();
26231 var xy = ev.getXY();
26232 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26233 //Roo.log("not in region.");
26236 //Roo.log("child element over..");
26239 this.currentEl = bindEl;
26240 this.currentTip.bind(bindEl);
26241 this.currentRegion = Roo.lib.Region.getRegion(dom);
26242 this.currentTip.enter();
26245 leave : function(ev)
26247 var dom = ev.getTarget();
26248 //Roo.log(['leave',dom]);
26249 if (!this.currentEl) {
26254 if (dom != this.currentEl.dom) {
26257 var xy = ev.getXY();
26258 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26261 // only activate leave if mouse cursor is outside... bounding box..
26266 if (this.currentTip) {
26267 this.currentTip.leave();
26269 //Roo.log('clear currentEl');
26270 this.currentEl = false;
26275 'left' : ['r-l', [-2,0], 'right'],
26276 'right' : ['l-r', [2,0], 'left'],
26277 'bottom' : ['t-b', [0,2], 'top'],
26278 'top' : [ 'b-t', [0,-2], 'bottom']
26284 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26289 delay : null, // can be { show : 300 , hide: 500}
26293 hoverState : null, //???
26295 placement : 'bottom',
26299 getAutoCreate : function(){
26306 cls : 'tooltip-arrow'
26309 cls : 'tooltip-inner'
26316 bind : function(el)
26322 enter : function () {
26324 if (this.timeout != null) {
26325 clearTimeout(this.timeout);
26328 this.hoverState = 'in';
26329 //Roo.log("enter - show");
26330 if (!this.delay || !this.delay.show) {
26335 this.timeout = setTimeout(function () {
26336 if (_t.hoverState == 'in') {
26339 }, this.delay.show);
26343 clearTimeout(this.timeout);
26345 this.hoverState = 'out';
26346 if (!this.delay || !this.delay.hide) {
26352 this.timeout = setTimeout(function () {
26353 //Roo.log("leave - timeout");
26355 if (_t.hoverState == 'out') {
26357 Roo.bootstrap.Tooltip.currentEl = false;
26362 show : function (msg)
26365 this.render(document.body);
26368 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26370 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26372 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26374 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26376 var placement = typeof this.placement == 'function' ?
26377 this.placement.call(this, this.el, on_el) :
26380 var autoToken = /\s?auto?\s?/i;
26381 var autoPlace = autoToken.test(placement);
26383 placement = placement.replace(autoToken, '') || 'top';
26387 //this.el.setXY([0,0]);
26389 //this.el.dom.style.display='block';
26391 //this.el.appendTo(on_el);
26393 var p = this.getPosition();
26394 var box = this.el.getBox();
26400 var align = this.alignment[placement];
26402 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26404 if(placement == 'top' || placement == 'bottom'){
26406 placement = 'right';
26409 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26410 placement = 'left';
26413 var scroll = Roo.select('body', true).first().getScroll();
26415 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26419 align = this.alignment[placement];
26422 this.el.alignTo(this.bindEl, align[0],align[1]);
26423 //var arrow = this.el.select('.arrow',true).first();
26424 //arrow.set(align[2],
26426 this.el.addClass(placement);
26428 this.el.addClass('in fade');
26430 this.hoverState = null;
26432 if (this.el.hasClass('fade')) {
26443 //this.el.setXY([0,0]);
26444 this.el.removeClass('in');
26460 * @class Roo.bootstrap.LocationPicker
26461 * @extends Roo.bootstrap.Component
26462 * Bootstrap LocationPicker class
26463 * @cfg {Number} latitude Position when init default 0
26464 * @cfg {Number} longitude Position when init default 0
26465 * @cfg {Number} zoom default 15
26466 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26467 * @cfg {Boolean} mapTypeControl default false
26468 * @cfg {Boolean} disableDoubleClickZoom default false
26469 * @cfg {Boolean} scrollwheel default true
26470 * @cfg {Boolean} streetViewControl default false
26471 * @cfg {Number} radius default 0
26472 * @cfg {String} locationName
26473 * @cfg {Boolean} draggable default true
26474 * @cfg {Boolean} enableAutocomplete default false
26475 * @cfg {Boolean} enableReverseGeocode default true
26476 * @cfg {String} markerTitle
26479 * Create a new LocationPicker
26480 * @param {Object} config The config object
26484 Roo.bootstrap.LocationPicker = function(config){
26486 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26491 * Fires when the picker initialized.
26492 * @param {Roo.bootstrap.LocationPicker} this
26493 * @param {Google Location} location
26497 * @event positionchanged
26498 * Fires when the picker position changed.
26499 * @param {Roo.bootstrap.LocationPicker} this
26500 * @param {Google Location} location
26502 positionchanged : true,
26505 * Fires when the map resize.
26506 * @param {Roo.bootstrap.LocationPicker} this
26511 * Fires when the map show.
26512 * @param {Roo.bootstrap.LocationPicker} this
26517 * Fires when the map hide.
26518 * @param {Roo.bootstrap.LocationPicker} this
26523 * Fires when click the map.
26524 * @param {Roo.bootstrap.LocationPicker} this
26525 * @param {Map event} e
26529 * @event mapRightClick
26530 * Fires when right click the map.
26531 * @param {Roo.bootstrap.LocationPicker} this
26532 * @param {Map event} e
26534 mapRightClick : true,
26536 * @event markerClick
26537 * Fires when click the marker.
26538 * @param {Roo.bootstrap.LocationPicker} this
26539 * @param {Map event} e
26541 markerClick : true,
26543 * @event markerRightClick
26544 * Fires when right click the marker.
26545 * @param {Roo.bootstrap.LocationPicker} this
26546 * @param {Map event} e
26548 markerRightClick : true,
26550 * @event OverlayViewDraw
26551 * Fires when OverlayView Draw
26552 * @param {Roo.bootstrap.LocationPicker} this
26554 OverlayViewDraw : true,
26556 * @event OverlayViewOnAdd
26557 * Fires when OverlayView Draw
26558 * @param {Roo.bootstrap.LocationPicker} this
26560 OverlayViewOnAdd : true,
26562 * @event OverlayViewOnRemove
26563 * Fires when OverlayView Draw
26564 * @param {Roo.bootstrap.LocationPicker} this
26566 OverlayViewOnRemove : true,
26568 * @event OverlayViewShow
26569 * Fires when OverlayView Draw
26570 * @param {Roo.bootstrap.LocationPicker} this
26571 * @param {Pixel} cpx
26573 OverlayViewShow : true,
26575 * @event OverlayViewHide
26576 * Fires when OverlayView Draw
26577 * @param {Roo.bootstrap.LocationPicker} this
26579 OverlayViewHide : true,
26581 * @event loadexception
26582 * Fires when load google lib failed.
26583 * @param {Roo.bootstrap.LocationPicker} this
26585 loadexception : true
26590 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26592 gMapContext: false,
26598 mapTypeControl: false,
26599 disableDoubleClickZoom: false,
26601 streetViewControl: false,
26605 enableAutocomplete: false,
26606 enableReverseGeocode: true,
26609 getAutoCreate: function()
26614 cls: 'roo-location-picker'
26620 initEvents: function(ct, position)
26622 if(!this.el.getWidth() || this.isApplied()){
26626 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26631 initial: function()
26633 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26634 this.fireEvent('loadexception', this);
26638 if(!this.mapTypeId){
26639 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26642 this.gMapContext = this.GMapContext();
26644 this.initOverlayView();
26646 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26650 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26651 _this.setPosition(_this.gMapContext.marker.position);
26654 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26655 _this.fireEvent('mapClick', this, event);
26659 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26660 _this.fireEvent('mapRightClick', this, event);
26664 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26665 _this.fireEvent('markerClick', this, event);
26669 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26670 _this.fireEvent('markerRightClick', this, event);
26674 this.setPosition(this.gMapContext.location);
26676 this.fireEvent('initial', this, this.gMapContext.location);
26679 initOverlayView: function()
26683 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26687 _this.fireEvent('OverlayViewDraw', _this);
26692 _this.fireEvent('OverlayViewOnAdd', _this);
26695 onRemove: function()
26697 _this.fireEvent('OverlayViewOnRemove', _this);
26700 show: function(cpx)
26702 _this.fireEvent('OverlayViewShow', _this, cpx);
26707 _this.fireEvent('OverlayViewHide', _this);
26713 fromLatLngToContainerPixel: function(event)
26715 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26718 isApplied: function()
26720 return this.getGmapContext() == false ? false : true;
26723 getGmapContext: function()
26725 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26728 GMapContext: function()
26730 var position = new google.maps.LatLng(this.latitude, this.longitude);
26732 var _map = new google.maps.Map(this.el.dom, {
26735 mapTypeId: this.mapTypeId,
26736 mapTypeControl: this.mapTypeControl,
26737 disableDoubleClickZoom: this.disableDoubleClickZoom,
26738 scrollwheel: this.scrollwheel,
26739 streetViewControl: this.streetViewControl,
26740 locationName: this.locationName,
26741 draggable: this.draggable,
26742 enableAutocomplete: this.enableAutocomplete,
26743 enableReverseGeocode: this.enableReverseGeocode
26746 var _marker = new google.maps.Marker({
26747 position: position,
26749 title: this.markerTitle,
26750 draggable: this.draggable
26757 location: position,
26758 radius: this.radius,
26759 locationName: this.locationName,
26760 addressComponents: {
26761 formatted_address: null,
26762 addressLine1: null,
26763 addressLine2: null,
26765 streetNumber: null,
26769 stateOrProvince: null
26772 domContainer: this.el.dom,
26773 geodecoder: new google.maps.Geocoder()
26777 drawCircle: function(center, radius, options)
26779 if (this.gMapContext.circle != null) {
26780 this.gMapContext.circle.setMap(null);
26784 options = Roo.apply({}, options, {
26785 strokeColor: "#0000FF",
26786 strokeOpacity: .35,
26788 fillColor: "#0000FF",
26792 options.map = this.gMapContext.map;
26793 options.radius = radius;
26794 options.center = center;
26795 this.gMapContext.circle = new google.maps.Circle(options);
26796 return this.gMapContext.circle;
26802 setPosition: function(location)
26804 this.gMapContext.location = location;
26805 this.gMapContext.marker.setPosition(location);
26806 this.gMapContext.map.panTo(location);
26807 this.drawCircle(location, this.gMapContext.radius, {});
26811 if (this.gMapContext.settings.enableReverseGeocode) {
26812 this.gMapContext.geodecoder.geocode({
26813 latLng: this.gMapContext.location
26814 }, function(results, status) {
26816 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26817 _this.gMapContext.locationName = results[0].formatted_address;
26818 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26820 _this.fireEvent('positionchanged', this, location);
26827 this.fireEvent('positionchanged', this, location);
26832 google.maps.event.trigger(this.gMapContext.map, "resize");
26834 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26836 this.fireEvent('resize', this);
26839 setPositionByLatLng: function(latitude, longitude)
26841 this.setPosition(new google.maps.LatLng(latitude, longitude));
26844 getCurrentPosition: function()
26847 latitude: this.gMapContext.location.lat(),
26848 longitude: this.gMapContext.location.lng()
26852 getAddressName: function()
26854 return this.gMapContext.locationName;
26857 getAddressComponents: function()
26859 return this.gMapContext.addressComponents;
26862 address_component_from_google_geocode: function(address_components)
26866 for (var i = 0; i < address_components.length; i++) {
26867 var component = address_components[i];
26868 if (component.types.indexOf("postal_code") >= 0) {
26869 result.postalCode = component.short_name;
26870 } else if (component.types.indexOf("street_number") >= 0) {
26871 result.streetNumber = component.short_name;
26872 } else if (component.types.indexOf("route") >= 0) {
26873 result.streetName = component.short_name;
26874 } else if (component.types.indexOf("neighborhood") >= 0) {
26875 result.city = component.short_name;
26876 } else if (component.types.indexOf("locality") >= 0) {
26877 result.city = component.short_name;
26878 } else if (component.types.indexOf("sublocality") >= 0) {
26879 result.district = component.short_name;
26880 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26881 result.stateOrProvince = component.short_name;
26882 } else if (component.types.indexOf("country") >= 0) {
26883 result.country = component.short_name;
26887 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26888 result.addressLine2 = "";
26892 setZoomLevel: function(zoom)
26894 this.gMapContext.map.setZoom(zoom);
26907 this.fireEvent('show', this);
26918 this.fireEvent('hide', this);
26923 Roo.apply(Roo.bootstrap.LocationPicker, {
26925 OverlayView : function(map, options)
26927 options = options || {};
26941 * @class Roo.bootstrap.Alert
26942 * @extends Roo.bootstrap.Component
26943 * Bootstrap Alert class
26944 * @cfg {String} title The title of alert
26945 * @cfg {String} html The content of alert
26946 * @cfg {String} weight ( success | info | warning | danger )
26947 * @cfg {String} faicon font-awesomeicon
26950 * Create a new alert
26951 * @param {Object} config The config object
26955 Roo.bootstrap.Alert = function(config){
26956 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26960 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26967 getAutoCreate : function()
26976 cls : 'roo-alert-icon'
26981 cls : 'roo-alert-title',
26986 cls : 'roo-alert-text',
26993 cfg.cn[0].cls += ' fa ' + this.faicon;
26997 cfg.cls += ' alert-' + this.weight;
27003 initEvents: function()
27005 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27008 setTitle : function(str)
27010 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27013 setText : function(str)
27015 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27018 setWeight : function(weight)
27021 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27024 this.weight = weight;
27026 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27029 setIcon : function(icon)
27032 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27035 this.faicon = icon;
27037 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27058 * @class Roo.bootstrap.UploadCropbox
27059 * @extends Roo.bootstrap.Component
27060 * Bootstrap UploadCropbox class
27061 * @cfg {String} emptyText show when image has been loaded
27062 * @cfg {String} rotateNotify show when image too small to rotate
27063 * @cfg {Number} errorTimeout default 3000
27064 * @cfg {Number} minWidth default 300
27065 * @cfg {Number} minHeight default 300
27066 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27067 * @cfg {Boolean} isDocument (true|false) default false
27068 * @cfg {String} url action url
27069 * @cfg {String} paramName default 'imageUpload'
27070 * @cfg {String} method default POST
27071 * @cfg {Boolean} loadMask (true|false) default true
27072 * @cfg {Boolean} loadingText default 'Loading...'
27075 * Create a new UploadCropbox
27076 * @param {Object} config The config object
27079 Roo.bootstrap.UploadCropbox = function(config){
27080 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27084 * @event beforeselectfile
27085 * Fire before select file
27086 * @param {Roo.bootstrap.UploadCropbox} this
27088 "beforeselectfile" : true,
27091 * Fire after initEvent
27092 * @param {Roo.bootstrap.UploadCropbox} this
27097 * Fire after initEvent
27098 * @param {Roo.bootstrap.UploadCropbox} this
27099 * @param {String} data
27104 * Fire when preparing the file data
27105 * @param {Roo.bootstrap.UploadCropbox} this
27106 * @param {Object} file
27111 * Fire when get exception
27112 * @param {Roo.bootstrap.UploadCropbox} this
27113 * @param {XMLHttpRequest} xhr
27115 "exception" : true,
27117 * @event beforeloadcanvas
27118 * Fire before load the canvas
27119 * @param {Roo.bootstrap.UploadCropbox} this
27120 * @param {String} src
27122 "beforeloadcanvas" : true,
27125 * Fire when trash image
27126 * @param {Roo.bootstrap.UploadCropbox} this
27131 * Fire when download the image
27132 * @param {Roo.bootstrap.UploadCropbox} this
27136 * @event footerbuttonclick
27137 * Fire when footerbuttonclick
27138 * @param {Roo.bootstrap.UploadCropbox} this
27139 * @param {String} type
27141 "footerbuttonclick" : true,
27145 * @param {Roo.bootstrap.UploadCropbox} this
27150 * Fire when rotate the image
27151 * @param {Roo.bootstrap.UploadCropbox} this
27152 * @param {String} pos
27157 * Fire when inspect the file
27158 * @param {Roo.bootstrap.UploadCropbox} this
27159 * @param {Object} file
27164 * Fire when xhr upload the file
27165 * @param {Roo.bootstrap.UploadCropbox} this
27166 * @param {Object} data
27171 * Fire when arrange the file data
27172 * @param {Roo.bootstrap.UploadCropbox} this
27173 * @param {Object} formData
27178 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27181 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27183 emptyText : 'Click to upload image',
27184 rotateNotify : 'Image is too small to rotate',
27185 errorTimeout : 3000,
27199 cropType : 'image/jpeg',
27201 canvasLoaded : false,
27202 isDocument : false,
27204 paramName : 'imageUpload',
27206 loadingText : 'Loading...',
27209 getAutoCreate : function()
27213 cls : 'roo-upload-cropbox',
27217 cls : 'roo-upload-cropbox-selector',
27222 cls : 'roo-upload-cropbox-body',
27223 style : 'cursor:pointer',
27227 cls : 'roo-upload-cropbox-preview'
27231 cls : 'roo-upload-cropbox-thumb'
27235 cls : 'roo-upload-cropbox-empty-notify',
27236 html : this.emptyText
27240 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27241 html : this.rotateNotify
27247 cls : 'roo-upload-cropbox-footer',
27250 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27260 onRender : function(ct, position)
27262 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27264 if (this.buttons.length) {
27266 Roo.each(this.buttons, function(bb) {
27268 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27270 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27276 this.maskEl = this.el;
27280 initEvents : function()
27282 this.urlAPI = (window.createObjectURL && window) ||
27283 (window.URL && URL.revokeObjectURL && URL) ||
27284 (window.webkitURL && webkitURL);
27286 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27287 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27289 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27290 this.selectorEl.hide();
27292 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27293 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27295 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27296 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27297 this.thumbEl.hide();
27299 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27300 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27302 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27303 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27304 this.errorEl.hide();
27306 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27307 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27308 this.footerEl.hide();
27310 this.setThumbBoxSize();
27316 this.fireEvent('initial', this);
27323 window.addEventListener("resize", function() { _this.resize(); } );
27325 this.bodyEl.on('click', this.beforeSelectFile, this);
27328 this.bodyEl.on('touchstart', this.onTouchStart, this);
27329 this.bodyEl.on('touchmove', this.onTouchMove, this);
27330 this.bodyEl.on('touchend', this.onTouchEnd, this);
27334 this.bodyEl.on('mousedown', this.onMouseDown, this);
27335 this.bodyEl.on('mousemove', this.onMouseMove, this);
27336 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27337 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27338 Roo.get(document).on('mouseup', this.onMouseUp, this);
27341 this.selectorEl.on('change', this.onFileSelected, this);
27347 this.baseScale = 1;
27349 this.baseRotate = 1;
27350 this.dragable = false;
27351 this.pinching = false;
27354 this.cropData = false;
27355 this.notifyEl.dom.innerHTML = this.emptyText;
27357 this.selectorEl.dom.value = '';
27361 resize : function()
27363 if(this.fireEvent('resize', this) != false){
27364 this.setThumbBoxPosition();
27365 this.setCanvasPosition();
27369 onFooterButtonClick : function(e, el, o, type)
27372 case 'rotate-left' :
27373 this.onRotateLeft(e);
27375 case 'rotate-right' :
27376 this.onRotateRight(e);
27379 this.beforeSelectFile(e);
27394 this.fireEvent('footerbuttonclick', this, type);
27397 beforeSelectFile : function(e)
27399 e.preventDefault();
27401 if(this.fireEvent('beforeselectfile', this) != false){
27402 this.selectorEl.dom.click();
27406 onFileSelected : function(e)
27408 e.preventDefault();
27410 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27414 var file = this.selectorEl.dom.files[0];
27416 if(this.fireEvent('inspect', this, file) != false){
27417 this.prepare(file);
27422 trash : function(e)
27424 this.fireEvent('trash', this);
27427 download : function(e)
27429 this.fireEvent('download', this);
27432 loadCanvas : function(src)
27434 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27438 this.imageEl = document.createElement('img');
27442 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27444 this.imageEl.src = src;
27448 onLoadCanvas : function()
27450 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27451 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27453 this.bodyEl.un('click', this.beforeSelectFile, this);
27455 this.notifyEl.hide();
27456 this.thumbEl.show();
27457 this.footerEl.show();
27459 this.baseRotateLevel();
27461 if(this.isDocument){
27462 this.setThumbBoxSize();
27465 this.setThumbBoxPosition();
27467 this.baseScaleLevel();
27473 this.canvasLoaded = true;
27476 this.maskEl.unmask();
27481 setCanvasPosition : function()
27483 if(!this.canvasEl){
27487 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27488 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27490 this.previewEl.setLeft(pw);
27491 this.previewEl.setTop(ph);
27495 onMouseDown : function(e)
27499 this.dragable = true;
27500 this.pinching = false;
27502 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27503 this.dragable = false;
27507 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27508 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27512 onMouseMove : function(e)
27516 if(!this.canvasLoaded){
27520 if (!this.dragable){
27524 var minX = Math.ceil(this.thumbEl.getLeft(true));
27525 var minY = Math.ceil(this.thumbEl.getTop(true));
27527 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27528 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27530 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27531 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27533 x = x - this.mouseX;
27534 y = y - this.mouseY;
27536 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27537 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27539 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27540 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27542 this.previewEl.setLeft(bgX);
27543 this.previewEl.setTop(bgY);
27545 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27546 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27549 onMouseUp : function(e)
27553 this.dragable = false;
27556 onMouseWheel : function(e)
27560 this.startScale = this.scale;
27562 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27564 if(!this.zoomable()){
27565 this.scale = this.startScale;
27574 zoomable : function()
27576 var minScale = this.thumbEl.getWidth() / this.minWidth;
27578 if(this.minWidth < this.minHeight){
27579 minScale = this.thumbEl.getHeight() / this.minHeight;
27582 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27583 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27587 (this.rotate == 0 || this.rotate == 180) &&
27589 width > this.imageEl.OriginWidth ||
27590 height > this.imageEl.OriginHeight ||
27591 (width < this.minWidth && height < this.minHeight)
27599 (this.rotate == 90 || this.rotate == 270) &&
27601 width > this.imageEl.OriginWidth ||
27602 height > this.imageEl.OriginHeight ||
27603 (width < this.minHeight && height < this.minWidth)
27610 !this.isDocument &&
27611 (this.rotate == 0 || this.rotate == 180) &&
27613 width < this.minWidth ||
27614 width > this.imageEl.OriginWidth ||
27615 height < this.minHeight ||
27616 height > this.imageEl.OriginHeight
27623 !this.isDocument &&
27624 (this.rotate == 90 || this.rotate == 270) &&
27626 width < this.minHeight ||
27627 width > this.imageEl.OriginWidth ||
27628 height < this.minWidth ||
27629 height > this.imageEl.OriginHeight
27639 onRotateLeft : function(e)
27641 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27643 var minScale = this.thumbEl.getWidth() / this.minWidth;
27645 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27646 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27648 this.startScale = this.scale;
27650 while (this.getScaleLevel() < minScale){
27652 this.scale = this.scale + 1;
27654 if(!this.zoomable()){
27659 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27660 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27665 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27672 this.scale = this.startScale;
27674 this.onRotateFail();
27679 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27681 if(this.isDocument){
27682 this.setThumbBoxSize();
27683 this.setThumbBoxPosition();
27684 this.setCanvasPosition();
27689 this.fireEvent('rotate', this, 'left');
27693 onRotateRight : function(e)
27695 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27697 var minScale = this.thumbEl.getWidth() / this.minWidth;
27699 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27700 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27702 this.startScale = this.scale;
27704 while (this.getScaleLevel() < minScale){
27706 this.scale = this.scale + 1;
27708 if(!this.zoomable()){
27713 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27714 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27719 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27726 this.scale = this.startScale;
27728 this.onRotateFail();
27733 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27735 if(this.isDocument){
27736 this.setThumbBoxSize();
27737 this.setThumbBoxPosition();
27738 this.setCanvasPosition();
27743 this.fireEvent('rotate', this, 'right');
27746 onRotateFail : function()
27748 this.errorEl.show(true);
27752 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27757 this.previewEl.dom.innerHTML = '';
27759 var canvasEl = document.createElement("canvas");
27761 var contextEl = canvasEl.getContext("2d");
27763 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27764 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27765 var center = this.imageEl.OriginWidth / 2;
27767 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27768 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27769 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27770 center = this.imageEl.OriginHeight / 2;
27773 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27775 contextEl.translate(center, center);
27776 contextEl.rotate(this.rotate * Math.PI / 180);
27778 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27780 this.canvasEl = document.createElement("canvas");
27782 this.contextEl = this.canvasEl.getContext("2d");
27784 switch (this.rotate) {
27787 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27788 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27790 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27795 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27796 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27798 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27799 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);
27803 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27808 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27809 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27811 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27812 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);
27816 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);
27821 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27822 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27824 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27825 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27829 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);
27836 this.previewEl.appendChild(this.canvasEl);
27838 this.setCanvasPosition();
27843 if(!this.canvasLoaded){
27847 var imageCanvas = document.createElement("canvas");
27849 var imageContext = imageCanvas.getContext("2d");
27851 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27852 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27854 var center = imageCanvas.width / 2;
27856 imageContext.translate(center, center);
27858 imageContext.rotate(this.rotate * Math.PI / 180);
27860 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27862 var canvas = document.createElement("canvas");
27864 var context = canvas.getContext("2d");
27866 canvas.width = this.minWidth;
27867 canvas.height = this.minHeight;
27869 switch (this.rotate) {
27872 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27873 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27875 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27876 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27878 var targetWidth = this.minWidth - 2 * x;
27879 var targetHeight = this.minHeight - 2 * y;
27883 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27884 scale = targetWidth / width;
27887 if(x > 0 && y == 0){
27888 scale = targetHeight / height;
27891 if(x > 0 && y > 0){
27892 scale = targetWidth / width;
27894 if(width < height){
27895 scale = targetHeight / height;
27899 context.scale(scale, scale);
27901 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27902 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27904 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27905 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27907 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27912 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27913 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27915 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27916 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27918 var targetWidth = this.minWidth - 2 * x;
27919 var targetHeight = this.minHeight - 2 * y;
27923 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27924 scale = targetWidth / width;
27927 if(x > 0 && y == 0){
27928 scale = targetHeight / height;
27931 if(x > 0 && y > 0){
27932 scale = targetWidth / width;
27934 if(width < height){
27935 scale = targetHeight / height;
27939 context.scale(scale, scale);
27941 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27942 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27944 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27945 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27947 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27949 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27954 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27955 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27957 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27958 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27960 var targetWidth = this.minWidth - 2 * x;
27961 var targetHeight = this.minHeight - 2 * y;
27965 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27966 scale = targetWidth / width;
27969 if(x > 0 && y == 0){
27970 scale = targetHeight / height;
27973 if(x > 0 && y > 0){
27974 scale = targetWidth / width;
27976 if(width < height){
27977 scale = targetHeight / height;
27981 context.scale(scale, scale);
27983 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27984 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27986 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27987 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27989 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27990 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27992 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27997 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27998 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28000 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28001 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28003 var targetWidth = this.minWidth - 2 * x;
28004 var targetHeight = this.minHeight - 2 * y;
28008 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28009 scale = targetWidth / width;
28012 if(x > 0 && y == 0){
28013 scale = targetHeight / height;
28016 if(x > 0 && y > 0){
28017 scale = targetWidth / width;
28019 if(width < height){
28020 scale = targetHeight / height;
28024 context.scale(scale, scale);
28026 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28027 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28029 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28030 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28032 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28034 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28041 this.cropData = canvas.toDataURL(this.cropType);
28043 if(this.fireEvent('crop', this, this.cropData) !== false){
28044 this.process(this.file, this.cropData);
28051 setThumbBoxSize : function()
28055 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28056 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28057 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28059 this.minWidth = width;
28060 this.minHeight = height;
28062 if(this.rotate == 90 || this.rotate == 270){
28063 this.minWidth = height;
28064 this.minHeight = width;
28069 width = Math.ceil(this.minWidth * height / this.minHeight);
28071 if(this.minWidth > this.minHeight){
28073 height = Math.ceil(this.minHeight * width / this.minWidth);
28076 this.thumbEl.setStyle({
28077 width : width + 'px',
28078 height : height + 'px'
28085 setThumbBoxPosition : function()
28087 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28088 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28090 this.thumbEl.setLeft(x);
28091 this.thumbEl.setTop(y);
28095 baseRotateLevel : function()
28097 this.baseRotate = 1;
28100 typeof(this.exif) != 'undefined' &&
28101 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28102 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28104 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28107 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28111 baseScaleLevel : function()
28115 if(this.isDocument){
28117 if(this.baseRotate == 6 || this.baseRotate == 8){
28119 height = this.thumbEl.getHeight();
28120 this.baseScale = height / this.imageEl.OriginWidth;
28122 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28123 width = this.thumbEl.getWidth();
28124 this.baseScale = width / this.imageEl.OriginHeight;
28130 height = this.thumbEl.getHeight();
28131 this.baseScale = height / this.imageEl.OriginHeight;
28133 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28134 width = this.thumbEl.getWidth();
28135 this.baseScale = width / this.imageEl.OriginWidth;
28141 if(this.baseRotate == 6 || this.baseRotate == 8){
28143 width = this.thumbEl.getHeight();
28144 this.baseScale = width / this.imageEl.OriginHeight;
28146 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28147 height = this.thumbEl.getWidth();
28148 this.baseScale = height / this.imageEl.OriginHeight;
28151 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28152 height = this.thumbEl.getWidth();
28153 this.baseScale = height / this.imageEl.OriginHeight;
28155 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28156 width = this.thumbEl.getHeight();
28157 this.baseScale = width / this.imageEl.OriginWidth;
28164 width = this.thumbEl.getWidth();
28165 this.baseScale = width / this.imageEl.OriginWidth;
28167 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28168 height = this.thumbEl.getHeight();
28169 this.baseScale = height / this.imageEl.OriginHeight;
28172 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28174 height = this.thumbEl.getHeight();
28175 this.baseScale = height / this.imageEl.OriginHeight;
28177 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28178 width = this.thumbEl.getWidth();
28179 this.baseScale = width / this.imageEl.OriginWidth;
28187 getScaleLevel : function()
28189 return this.baseScale * Math.pow(1.1, this.scale);
28192 onTouchStart : function(e)
28194 if(!this.canvasLoaded){
28195 this.beforeSelectFile(e);
28199 var touches = e.browserEvent.touches;
28205 if(touches.length == 1){
28206 this.onMouseDown(e);
28210 if(touches.length != 2){
28216 for(var i = 0, finger; finger = touches[i]; i++){
28217 coords.push(finger.pageX, finger.pageY);
28220 var x = Math.pow(coords[0] - coords[2], 2);
28221 var y = Math.pow(coords[1] - coords[3], 2);
28223 this.startDistance = Math.sqrt(x + y);
28225 this.startScale = this.scale;
28227 this.pinching = true;
28228 this.dragable = false;
28232 onTouchMove : function(e)
28234 if(!this.pinching && !this.dragable){
28238 var touches = e.browserEvent.touches;
28245 this.onMouseMove(e);
28251 for(var i = 0, finger; finger = touches[i]; i++){
28252 coords.push(finger.pageX, finger.pageY);
28255 var x = Math.pow(coords[0] - coords[2], 2);
28256 var y = Math.pow(coords[1] - coords[3], 2);
28258 this.endDistance = Math.sqrt(x + y);
28260 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28262 if(!this.zoomable()){
28263 this.scale = this.startScale;
28271 onTouchEnd : function(e)
28273 this.pinching = false;
28274 this.dragable = false;
28278 process : function(file, crop)
28281 this.maskEl.mask(this.loadingText);
28284 this.xhr = new XMLHttpRequest();
28286 file.xhr = this.xhr;
28288 this.xhr.open(this.method, this.url, true);
28291 "Accept": "application/json",
28292 "Cache-Control": "no-cache",
28293 "X-Requested-With": "XMLHttpRequest"
28296 for (var headerName in headers) {
28297 var headerValue = headers[headerName];
28299 this.xhr.setRequestHeader(headerName, headerValue);
28305 this.xhr.onload = function()
28307 _this.xhrOnLoad(_this.xhr);
28310 this.xhr.onerror = function()
28312 _this.xhrOnError(_this.xhr);
28315 var formData = new FormData();
28317 formData.append('returnHTML', 'NO');
28320 formData.append('crop', crop);
28323 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28324 formData.append(this.paramName, file, file.name);
28327 if(typeof(file.filename) != 'undefined'){
28328 formData.append('filename', file.filename);
28331 if(typeof(file.mimetype) != 'undefined'){
28332 formData.append('mimetype', file.mimetype);
28335 if(this.fireEvent('arrange', this, formData) != false){
28336 this.xhr.send(formData);
28340 xhrOnLoad : function(xhr)
28343 this.maskEl.unmask();
28346 if (xhr.readyState !== 4) {
28347 this.fireEvent('exception', this, xhr);
28351 var response = Roo.decode(xhr.responseText);
28353 if(!response.success){
28354 this.fireEvent('exception', this, xhr);
28358 var response = Roo.decode(xhr.responseText);
28360 this.fireEvent('upload', this, response);
28364 xhrOnError : function()
28367 this.maskEl.unmask();
28370 Roo.log('xhr on error');
28372 var response = Roo.decode(xhr.responseText);
28378 prepare : function(file)
28381 this.maskEl.mask(this.loadingText);
28387 if(typeof(file) === 'string'){
28388 this.loadCanvas(file);
28392 if(!file || !this.urlAPI){
28397 this.cropType = file.type;
28401 if(this.fireEvent('prepare', this, this.file) != false){
28403 var reader = new FileReader();
28405 reader.onload = function (e) {
28406 if (e.target.error) {
28407 Roo.log(e.target.error);
28411 var buffer = e.target.result,
28412 dataView = new DataView(buffer),
28414 maxOffset = dataView.byteLength - 4,
28418 if (dataView.getUint16(0) === 0xffd8) {
28419 while (offset < maxOffset) {
28420 markerBytes = dataView.getUint16(offset);
28422 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28423 markerLength = dataView.getUint16(offset + 2) + 2;
28424 if (offset + markerLength > dataView.byteLength) {
28425 Roo.log('Invalid meta data: Invalid segment size.');
28429 if(markerBytes == 0xffe1){
28430 _this.parseExifData(
28437 offset += markerLength;
28447 var url = _this.urlAPI.createObjectURL(_this.file);
28449 _this.loadCanvas(url);
28454 reader.readAsArrayBuffer(this.file);
28460 parseExifData : function(dataView, offset, length)
28462 var tiffOffset = offset + 10,
28466 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28467 // No Exif data, might be XMP data instead
28471 // Check for the ASCII code for "Exif" (0x45786966):
28472 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28473 // No Exif data, might be XMP data instead
28476 if (tiffOffset + 8 > dataView.byteLength) {
28477 Roo.log('Invalid Exif data: Invalid segment size.');
28480 // Check for the two null bytes:
28481 if (dataView.getUint16(offset + 8) !== 0x0000) {
28482 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28485 // Check the byte alignment:
28486 switch (dataView.getUint16(tiffOffset)) {
28488 littleEndian = true;
28491 littleEndian = false;
28494 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28497 // Check for the TIFF tag marker (0x002A):
28498 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28499 Roo.log('Invalid Exif data: Missing TIFF marker.');
28502 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28503 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28505 this.parseExifTags(
28508 tiffOffset + dirOffset,
28513 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28518 if (dirOffset + 6 > dataView.byteLength) {
28519 Roo.log('Invalid Exif data: Invalid directory offset.');
28522 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28523 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28524 if (dirEndOffset + 4 > dataView.byteLength) {
28525 Roo.log('Invalid Exif data: Invalid directory size.');
28528 for (i = 0; i < tagsNumber; i += 1) {
28532 dirOffset + 2 + 12 * i, // tag offset
28536 // Return the offset to the next directory:
28537 return dataView.getUint32(dirEndOffset, littleEndian);
28540 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28542 var tag = dataView.getUint16(offset, littleEndian);
28544 this.exif[tag] = this.getExifValue(
28548 dataView.getUint16(offset + 2, littleEndian), // tag type
28549 dataView.getUint32(offset + 4, littleEndian), // tag length
28554 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28556 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28565 Roo.log('Invalid Exif data: Invalid tag type.');
28569 tagSize = tagType.size * length;
28570 // Determine if the value is contained in the dataOffset bytes,
28571 // or if the value at the dataOffset is a pointer to the actual data:
28572 dataOffset = tagSize > 4 ?
28573 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28574 if (dataOffset + tagSize > dataView.byteLength) {
28575 Roo.log('Invalid Exif data: Invalid data offset.');
28578 if (length === 1) {
28579 return tagType.getValue(dataView, dataOffset, littleEndian);
28582 for (i = 0; i < length; i += 1) {
28583 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28586 if (tagType.ascii) {
28588 // Concatenate the chars:
28589 for (i = 0; i < values.length; i += 1) {
28591 // Ignore the terminating NULL byte(s):
28592 if (c === '\u0000') {
28604 Roo.apply(Roo.bootstrap.UploadCropbox, {
28606 'Orientation': 0x0112
28610 1: 0, //'top-left',
28612 3: 180, //'bottom-right',
28613 // 4: 'bottom-left',
28615 6: 90, //'right-top',
28616 // 7: 'right-bottom',
28617 8: 270 //'left-bottom'
28621 // byte, 8-bit unsigned int:
28623 getValue: function (dataView, dataOffset) {
28624 return dataView.getUint8(dataOffset);
28628 // ascii, 8-bit byte:
28630 getValue: function (dataView, dataOffset) {
28631 return String.fromCharCode(dataView.getUint8(dataOffset));
28636 // short, 16 bit int:
28638 getValue: function (dataView, dataOffset, littleEndian) {
28639 return dataView.getUint16(dataOffset, littleEndian);
28643 // long, 32 bit int:
28645 getValue: function (dataView, dataOffset, littleEndian) {
28646 return dataView.getUint32(dataOffset, littleEndian);
28650 // rational = two long values, first is numerator, second is denominator:
28652 getValue: function (dataView, dataOffset, littleEndian) {
28653 return dataView.getUint32(dataOffset, littleEndian) /
28654 dataView.getUint32(dataOffset + 4, littleEndian);
28658 // slong, 32 bit signed int:
28660 getValue: function (dataView, dataOffset, littleEndian) {
28661 return dataView.getInt32(dataOffset, littleEndian);
28665 // srational, two slongs, first is numerator, second is denominator:
28667 getValue: function (dataView, dataOffset, littleEndian) {
28668 return dataView.getInt32(dataOffset, littleEndian) /
28669 dataView.getInt32(dataOffset + 4, littleEndian);
28679 cls : 'btn-group roo-upload-cropbox-rotate-left',
28680 action : 'rotate-left',
28684 cls : 'btn btn-default',
28685 html : '<i class="fa fa-undo"></i>'
28691 cls : 'btn-group roo-upload-cropbox-picture',
28692 action : 'picture',
28696 cls : 'btn btn-default',
28697 html : '<i class="fa fa-picture-o"></i>'
28703 cls : 'btn-group roo-upload-cropbox-rotate-right',
28704 action : 'rotate-right',
28708 cls : 'btn btn-default',
28709 html : '<i class="fa fa-repeat"></i>'
28717 cls : 'btn-group roo-upload-cropbox-rotate-left',
28718 action : 'rotate-left',
28722 cls : 'btn btn-default',
28723 html : '<i class="fa fa-undo"></i>'
28729 cls : 'btn-group roo-upload-cropbox-download',
28730 action : 'download',
28734 cls : 'btn btn-default',
28735 html : '<i class="fa fa-download"></i>'
28741 cls : 'btn-group roo-upload-cropbox-crop',
28746 cls : 'btn btn-default',
28747 html : '<i class="fa fa-crop"></i>'
28753 cls : 'btn-group roo-upload-cropbox-trash',
28758 cls : 'btn btn-default',
28759 html : '<i class="fa fa-trash"></i>'
28765 cls : 'btn-group roo-upload-cropbox-rotate-right',
28766 action : 'rotate-right',
28770 cls : 'btn btn-default',
28771 html : '<i class="fa fa-repeat"></i>'
28779 cls : 'btn-group roo-upload-cropbox-rotate-left',
28780 action : 'rotate-left',
28784 cls : 'btn btn-default',
28785 html : '<i class="fa fa-undo"></i>'
28791 cls : 'btn-group roo-upload-cropbox-rotate-right',
28792 action : 'rotate-right',
28796 cls : 'btn btn-default',
28797 html : '<i class="fa fa-repeat"></i>'
28810 * @class Roo.bootstrap.DocumentManager
28811 * @extends Roo.bootstrap.Component
28812 * Bootstrap DocumentManager class
28813 * @cfg {String} paramName default 'imageUpload'
28814 * @cfg {String} toolTipName default 'filename'
28815 * @cfg {String} method default POST
28816 * @cfg {String} url action url
28817 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28818 * @cfg {Boolean} multiple multiple upload default true
28819 * @cfg {Number} thumbSize default 300
28820 * @cfg {String} fieldLabel
28821 * @cfg {Number} labelWidth default 4
28822 * @cfg {String} labelAlign (left|top) default left
28823 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28824 * @cfg {Number} labellg set the width of label (1-12)
28825 * @cfg {Number} labelmd set the width of label (1-12)
28826 * @cfg {Number} labelsm set the width of label (1-12)
28827 * @cfg {Number} labelxs set the width of label (1-12)
28830 * Create a new DocumentManager
28831 * @param {Object} config The config object
28834 Roo.bootstrap.DocumentManager = function(config){
28835 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28838 this.delegates = [];
28843 * Fire when initial the DocumentManager
28844 * @param {Roo.bootstrap.DocumentManager} this
28849 * inspect selected file
28850 * @param {Roo.bootstrap.DocumentManager} this
28851 * @param {File} file
28856 * Fire when xhr load exception
28857 * @param {Roo.bootstrap.DocumentManager} this
28858 * @param {XMLHttpRequest} xhr
28860 "exception" : true,
28862 * @event afterupload
28863 * Fire when xhr load exception
28864 * @param {Roo.bootstrap.DocumentManager} this
28865 * @param {XMLHttpRequest} xhr
28867 "afterupload" : true,
28870 * prepare the form data
28871 * @param {Roo.bootstrap.DocumentManager} this
28872 * @param {Object} formData
28877 * Fire when remove the file
28878 * @param {Roo.bootstrap.DocumentManager} this
28879 * @param {Object} file
28884 * Fire after refresh the file
28885 * @param {Roo.bootstrap.DocumentManager} this
28890 * Fire after click the image
28891 * @param {Roo.bootstrap.DocumentManager} this
28892 * @param {Object} file
28897 * Fire when upload a image and editable set to true
28898 * @param {Roo.bootstrap.DocumentManager} this
28899 * @param {Object} file
28903 * @event beforeselectfile
28904 * Fire before select file
28905 * @param {Roo.bootstrap.DocumentManager} this
28907 "beforeselectfile" : true,
28910 * Fire before process file
28911 * @param {Roo.bootstrap.DocumentManager} this
28912 * @param {Object} file
28916 * @event previewrendered
28917 * Fire when preview rendered
28918 * @param {Roo.bootstrap.DocumentManager} this
28919 * @param {Object} file
28921 "previewrendered" : true,
28924 "previewResize" : true
28929 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28938 paramName : 'imageUpload',
28939 toolTipName : 'filename',
28942 labelAlign : 'left',
28952 getAutoCreate : function()
28954 var managerWidget = {
28956 cls : 'roo-document-manager',
28960 cls : 'roo-document-manager-selector',
28965 cls : 'roo-document-manager-uploader',
28969 cls : 'roo-document-manager-upload-btn',
28970 html : '<i class="fa fa-plus"></i>'
28981 cls : 'column col-md-12',
28986 if(this.fieldLabel.length){
28991 cls : 'column col-md-12',
28992 html : this.fieldLabel
28996 cls : 'column col-md-12',
29001 if(this.labelAlign == 'left'){
29006 html : this.fieldLabel
29015 if(this.labelWidth > 12){
29016 content[0].style = "width: " + this.labelWidth + 'px';
29019 if(this.labelWidth < 13 && this.labelmd == 0){
29020 this.labelmd = this.labelWidth;
29023 if(this.labellg > 0){
29024 content[0].cls += ' col-lg-' + this.labellg;
29025 content[1].cls += ' col-lg-' + (12 - this.labellg);
29028 if(this.labelmd > 0){
29029 content[0].cls += ' col-md-' + this.labelmd;
29030 content[1].cls += ' col-md-' + (12 - this.labelmd);
29033 if(this.labelsm > 0){
29034 content[0].cls += ' col-sm-' + this.labelsm;
29035 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29038 if(this.labelxs > 0){
29039 content[0].cls += ' col-xs-' + this.labelxs;
29040 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29048 cls : 'row clearfix',
29056 initEvents : function()
29058 this.managerEl = this.el.select('.roo-document-manager', true).first();
29059 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29061 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29062 this.selectorEl.hide();
29065 this.selectorEl.attr('multiple', 'multiple');
29068 this.selectorEl.on('change', this.onFileSelected, this);
29070 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29071 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29073 this.uploader.on('click', this.onUploaderClick, this);
29075 this.renderProgressDialog();
29079 window.addEventListener("resize", function() { _this.refresh(); } );
29081 this.fireEvent('initial', this);
29084 renderProgressDialog : function()
29088 this.progressDialog = new Roo.bootstrap.Modal({
29089 cls : 'roo-document-manager-progress-dialog',
29090 allow_close : false,
29100 btnclick : function() {
29101 _this.uploadCancel();
29107 this.progressDialog.render(Roo.get(document.body));
29109 this.progress = new Roo.bootstrap.Progress({
29110 cls : 'roo-document-manager-progress',
29115 this.progress.render(this.progressDialog.getChildContainer());
29117 this.progressBar = new Roo.bootstrap.ProgressBar({
29118 cls : 'roo-document-manager-progress-bar',
29121 aria_valuemax : 12,
29125 this.progressBar.render(this.progress.getChildContainer());
29128 onUploaderClick : function(e)
29130 e.preventDefault();
29132 if(this.fireEvent('beforeselectfile', this) != false){
29133 this.selectorEl.dom.click();
29138 onFileSelected : function(e)
29140 e.preventDefault();
29142 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29146 Roo.each(this.selectorEl.dom.files, function(file){
29147 if(this.fireEvent('inspect', this, file) != false){
29148 this.files.push(file);
29158 this.selectorEl.dom.value = '';
29160 if(!this.files || !this.files.length){
29164 if(this.boxes > 0 && this.files.length > this.boxes){
29165 this.files = this.files.slice(0, this.boxes);
29168 this.uploader.show();
29170 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29171 this.uploader.hide();
29180 Roo.each(this.files, function(file){
29182 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29183 var f = this.renderPreview(file);
29188 if(file.type.indexOf('image') != -1){
29189 this.delegates.push(
29191 _this.process(file);
29192 }).createDelegate(this)
29200 _this.process(file);
29201 }).createDelegate(this)
29206 this.files = files;
29208 this.delegates = this.delegates.concat(docs);
29210 if(!this.delegates.length){
29215 this.progressBar.aria_valuemax = this.delegates.length;
29222 arrange : function()
29224 if(!this.delegates.length){
29225 this.progressDialog.hide();
29230 var delegate = this.delegates.shift();
29232 this.progressDialog.show();
29234 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29236 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29241 refresh : function()
29243 this.uploader.show();
29245 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29246 this.uploader.hide();
29249 Roo.isTouch ? this.closable(false) : this.closable(true);
29251 this.fireEvent('refresh', this);
29254 onRemove : function(e, el, o)
29256 e.preventDefault();
29258 this.fireEvent('remove', this, o);
29262 remove : function(o)
29266 Roo.each(this.files, function(file){
29267 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29276 this.files = files;
29283 Roo.each(this.files, function(file){
29288 file.target.remove();
29297 onClick : function(e, el, o)
29299 e.preventDefault();
29301 this.fireEvent('click', this, o);
29305 closable : function(closable)
29307 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29309 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29321 xhrOnLoad : function(xhr)
29323 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29327 if (xhr.readyState !== 4) {
29329 this.fireEvent('exception', this, xhr);
29333 var response = Roo.decode(xhr.responseText);
29335 if(!response.success){
29337 this.fireEvent('exception', this, xhr);
29341 var file = this.renderPreview(response.data);
29343 this.files.push(file);
29347 this.fireEvent('afterupload', this, xhr);
29351 xhrOnError : function(xhr)
29353 Roo.log('xhr on error');
29355 var response = Roo.decode(xhr.responseText);
29362 process : function(file)
29364 if(this.fireEvent('process', this, file) !== false){
29365 if(this.editable && file.type.indexOf('image') != -1){
29366 this.fireEvent('edit', this, file);
29370 this.uploadStart(file, false);
29377 uploadStart : function(file, crop)
29379 this.xhr = new XMLHttpRequest();
29381 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29386 file.xhr = this.xhr;
29388 this.managerEl.createChild({
29390 cls : 'roo-document-manager-loading',
29394 tooltip : file.name,
29395 cls : 'roo-document-manager-thumb',
29396 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29402 this.xhr.open(this.method, this.url, true);
29405 "Accept": "application/json",
29406 "Cache-Control": "no-cache",
29407 "X-Requested-With": "XMLHttpRequest"
29410 for (var headerName in headers) {
29411 var headerValue = headers[headerName];
29413 this.xhr.setRequestHeader(headerName, headerValue);
29419 this.xhr.onload = function()
29421 _this.xhrOnLoad(_this.xhr);
29424 this.xhr.onerror = function()
29426 _this.xhrOnError(_this.xhr);
29429 var formData = new FormData();
29431 formData.append('returnHTML', 'NO');
29434 formData.append('crop', crop);
29437 formData.append(this.paramName, file, file.name);
29444 if(this.fireEvent('prepare', this, formData, options) != false){
29446 if(options.manually){
29450 this.xhr.send(formData);
29454 this.uploadCancel();
29457 uploadCancel : function()
29463 this.delegates = [];
29465 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29472 renderPreview : function(file)
29474 if(typeof(file.target) != 'undefined' && file.target){
29478 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29480 var previewEl = this.managerEl.createChild({
29482 cls : 'roo-document-manager-preview',
29486 tooltip : file[this.toolTipName],
29487 cls : 'roo-document-manager-thumb',
29488 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29493 html : '<i class="fa fa-times-circle"></i>'
29498 var close = previewEl.select('button.close', true).first();
29500 close.on('click', this.onRemove, this, file);
29502 file.target = previewEl;
29504 var image = previewEl.select('img', true).first();
29508 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29510 image.on('click', this.onClick, this, file);
29512 this.fireEvent('previewrendered', this, file);
29518 onPreviewLoad : function(file, image)
29520 if(typeof(file.target) == 'undefined' || !file.target){
29524 var width = image.dom.naturalWidth || image.dom.width;
29525 var height = image.dom.naturalHeight || image.dom.height;
29527 if(!this.previewResize) {
29531 if(width > height){
29532 file.target.addClass('wide');
29536 file.target.addClass('tall');
29541 uploadFromSource : function(file, crop)
29543 this.xhr = new XMLHttpRequest();
29545 this.managerEl.createChild({
29547 cls : 'roo-document-manager-loading',
29551 tooltip : file.name,
29552 cls : 'roo-document-manager-thumb',
29553 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29559 this.xhr.open(this.method, this.url, true);
29562 "Accept": "application/json",
29563 "Cache-Control": "no-cache",
29564 "X-Requested-With": "XMLHttpRequest"
29567 for (var headerName in headers) {
29568 var headerValue = headers[headerName];
29570 this.xhr.setRequestHeader(headerName, headerValue);
29576 this.xhr.onload = function()
29578 _this.xhrOnLoad(_this.xhr);
29581 this.xhr.onerror = function()
29583 _this.xhrOnError(_this.xhr);
29586 var formData = new FormData();
29588 formData.append('returnHTML', 'NO');
29590 formData.append('crop', crop);
29592 if(typeof(file.filename) != 'undefined'){
29593 formData.append('filename', file.filename);
29596 if(typeof(file.mimetype) != 'undefined'){
29597 formData.append('mimetype', file.mimetype);
29602 if(this.fireEvent('prepare', this, formData) != false){
29603 this.xhr.send(formData);
29613 * @class Roo.bootstrap.DocumentViewer
29614 * @extends Roo.bootstrap.Component
29615 * Bootstrap DocumentViewer class
29616 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29617 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29620 * Create a new DocumentViewer
29621 * @param {Object} config The config object
29624 Roo.bootstrap.DocumentViewer = function(config){
29625 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29630 * Fire after initEvent
29631 * @param {Roo.bootstrap.DocumentViewer} this
29637 * @param {Roo.bootstrap.DocumentViewer} this
29642 * Fire after download button
29643 * @param {Roo.bootstrap.DocumentViewer} this
29648 * Fire after trash button
29649 * @param {Roo.bootstrap.DocumentViewer} this
29656 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29658 showDownload : true,
29662 getAutoCreate : function()
29666 cls : 'roo-document-viewer',
29670 cls : 'roo-document-viewer-body',
29674 cls : 'roo-document-viewer-thumb',
29678 cls : 'roo-document-viewer-image'
29686 cls : 'roo-document-viewer-footer',
29689 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29693 cls : 'btn-group roo-document-viewer-download',
29697 cls : 'btn btn-default',
29698 html : '<i class="fa fa-download"></i>'
29704 cls : 'btn-group roo-document-viewer-trash',
29708 cls : 'btn btn-default',
29709 html : '<i class="fa fa-trash"></i>'
29722 initEvents : function()
29724 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29725 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29727 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29728 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29730 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29731 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29733 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29734 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29736 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29737 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29739 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29740 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29742 this.bodyEl.on('click', this.onClick, this);
29743 this.downloadBtn.on('click', this.onDownload, this);
29744 this.trashBtn.on('click', this.onTrash, this);
29746 this.downloadBtn.hide();
29747 this.trashBtn.hide();
29749 if(this.showDownload){
29750 this.downloadBtn.show();
29753 if(this.showTrash){
29754 this.trashBtn.show();
29757 if(!this.showDownload && !this.showTrash) {
29758 this.footerEl.hide();
29763 initial : function()
29765 this.fireEvent('initial', this);
29769 onClick : function(e)
29771 e.preventDefault();
29773 this.fireEvent('click', this);
29776 onDownload : function(e)
29778 e.preventDefault();
29780 this.fireEvent('download', this);
29783 onTrash : function(e)
29785 e.preventDefault();
29787 this.fireEvent('trash', this);
29799 * @class Roo.bootstrap.NavProgressBar
29800 * @extends Roo.bootstrap.Component
29801 * Bootstrap NavProgressBar class
29804 * Create a new nav progress bar
29805 * @param {Object} config The config object
29808 Roo.bootstrap.NavProgressBar = function(config){
29809 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29811 this.bullets = this.bullets || [];
29813 // Roo.bootstrap.NavProgressBar.register(this);
29817 * Fires when the active item changes
29818 * @param {Roo.bootstrap.NavProgressBar} this
29819 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29820 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29827 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29832 getAutoCreate : function()
29834 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29838 cls : 'roo-navigation-bar-group',
29842 cls : 'roo-navigation-top-bar'
29846 cls : 'roo-navigation-bullets-bar',
29850 cls : 'roo-navigation-bar'
29857 cls : 'roo-navigation-bottom-bar'
29867 initEvents: function()
29872 onRender : function(ct, position)
29874 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29876 if(this.bullets.length){
29877 Roo.each(this.bullets, function(b){
29886 addItem : function(cfg)
29888 var item = new Roo.bootstrap.NavProgressItem(cfg);
29890 item.parentId = this.id;
29891 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29894 var top = new Roo.bootstrap.Element({
29896 cls : 'roo-navigation-bar-text'
29899 var bottom = new Roo.bootstrap.Element({
29901 cls : 'roo-navigation-bar-text'
29904 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29905 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29907 var topText = new Roo.bootstrap.Element({
29909 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29912 var bottomText = new Roo.bootstrap.Element({
29914 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29917 topText.onRender(top.el, null);
29918 bottomText.onRender(bottom.el, null);
29921 item.bottomEl = bottom;
29924 this.barItems.push(item);
29929 getActive : function()
29931 var active = false;
29933 Roo.each(this.barItems, function(v){
29935 if (!v.isActive()) {
29947 setActiveItem : function(item)
29951 Roo.each(this.barItems, function(v){
29952 if (v.rid == item.rid) {
29956 if (v.isActive()) {
29957 v.setActive(false);
29962 item.setActive(true);
29964 this.fireEvent('changed', this, item, prev);
29967 getBarItem: function(rid)
29971 Roo.each(this.barItems, function(e) {
29972 if (e.rid != rid) {
29983 indexOfItem : function(item)
29987 Roo.each(this.barItems, function(v, i){
29989 if (v.rid != item.rid) {
30000 setActiveNext : function()
30002 var i = this.indexOfItem(this.getActive());
30004 if (i > this.barItems.length) {
30008 this.setActiveItem(this.barItems[i+1]);
30011 setActivePrev : function()
30013 var i = this.indexOfItem(this.getActive());
30019 this.setActiveItem(this.barItems[i-1]);
30022 format : function()
30024 if(!this.barItems.length){
30028 var width = 100 / this.barItems.length;
30030 Roo.each(this.barItems, function(i){
30031 i.el.setStyle('width', width + '%');
30032 i.topEl.el.setStyle('width', width + '%');
30033 i.bottomEl.el.setStyle('width', width + '%');
30042 * Nav Progress Item
30047 * @class Roo.bootstrap.NavProgressItem
30048 * @extends Roo.bootstrap.Component
30049 * Bootstrap NavProgressItem class
30050 * @cfg {String} rid the reference id
30051 * @cfg {Boolean} active (true|false) Is item active default false
30052 * @cfg {Boolean} disabled (true|false) Is item active default false
30053 * @cfg {String} html
30054 * @cfg {String} position (top|bottom) text position default bottom
30055 * @cfg {String} icon show icon instead of number
30058 * Create a new NavProgressItem
30059 * @param {Object} config The config object
30061 Roo.bootstrap.NavProgressItem = function(config){
30062 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30067 * The raw click event for the entire grid.
30068 * @param {Roo.bootstrap.NavProgressItem} this
30069 * @param {Roo.EventObject} e
30076 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30082 position : 'bottom',
30085 getAutoCreate : function()
30087 var iconCls = 'roo-navigation-bar-item-icon';
30089 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30093 cls: 'roo-navigation-bar-item',
30103 cfg.cls += ' active';
30106 cfg.cls += ' disabled';
30112 disable : function()
30114 this.setDisabled(true);
30117 enable : function()
30119 this.setDisabled(false);
30122 initEvents: function()
30124 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30126 this.iconEl.on('click', this.onClick, this);
30129 onClick : function(e)
30131 e.preventDefault();
30137 if(this.fireEvent('click', this, e) === false){
30141 this.parent().setActiveItem(this);
30144 isActive: function ()
30146 return this.active;
30149 setActive : function(state)
30151 if(this.active == state){
30155 this.active = state;
30158 this.el.addClass('active');
30162 this.el.removeClass('active');
30167 setDisabled : function(state)
30169 if(this.disabled == state){
30173 this.disabled = state;
30176 this.el.addClass('disabled');
30180 this.el.removeClass('disabled');
30183 tooltipEl : function()
30185 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30198 * @class Roo.bootstrap.FieldLabel
30199 * @extends Roo.bootstrap.Component
30200 * Bootstrap FieldLabel class
30201 * @cfg {String} html contents of the element
30202 * @cfg {String} tag tag of the element default label
30203 * @cfg {String} cls class of the element
30204 * @cfg {String} target label target
30205 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30206 * @cfg {String} invalidClass default "text-warning"
30207 * @cfg {String} validClass default "text-success"
30208 * @cfg {String} iconTooltip default "This field is required"
30209 * @cfg {String} indicatorpos (left|right) default left
30212 * Create a new FieldLabel
30213 * @param {Object} config The config object
30216 Roo.bootstrap.FieldLabel = function(config){
30217 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30222 * Fires after the field has been marked as invalid.
30223 * @param {Roo.form.FieldLabel} this
30224 * @param {String} msg The validation message
30229 * Fires after the field has been validated with no errors.
30230 * @param {Roo.form.FieldLabel} this
30236 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30243 invalidClass : 'has-warning',
30244 validClass : 'has-success',
30245 iconTooltip : 'This field is required',
30246 indicatorpos : 'left',
30248 getAutoCreate : function(){
30251 if (!this.allowBlank) {
30257 cls : 'roo-bootstrap-field-label ' + this.cls,
30262 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30263 tooltip : this.iconTooltip
30272 if(this.indicatorpos == 'right'){
30275 cls : 'roo-bootstrap-field-label ' + this.cls,
30284 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30285 tooltip : this.iconTooltip
30294 initEvents: function()
30296 Roo.bootstrap.Element.superclass.initEvents.call(this);
30298 this.indicator = this.indicatorEl();
30300 if(this.indicator){
30301 this.indicator.removeClass('visible');
30302 this.indicator.addClass('invisible');
30305 Roo.bootstrap.FieldLabel.register(this);
30308 indicatorEl : function()
30310 var indicator = this.el.select('i.roo-required-indicator',true).first();
30321 * Mark this field as valid
30323 markValid : function()
30325 if(this.indicator){
30326 this.indicator.removeClass('visible');
30327 this.indicator.addClass('invisible');
30330 this.el.removeClass(this.invalidClass);
30332 this.el.addClass(this.validClass);
30334 this.fireEvent('valid', this);
30338 * Mark this field as invalid
30339 * @param {String} msg The validation message
30341 markInvalid : function(msg)
30343 if(this.indicator){
30344 this.indicator.removeClass('invisible');
30345 this.indicator.addClass('visible');
30348 this.el.removeClass(this.validClass);
30350 this.el.addClass(this.invalidClass);
30352 this.fireEvent('invalid', this, msg);
30358 Roo.apply(Roo.bootstrap.FieldLabel, {
30363 * register a FieldLabel Group
30364 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30366 register : function(label)
30368 if(this.groups.hasOwnProperty(label.target)){
30372 this.groups[label.target] = label;
30376 * fetch a FieldLabel Group based on the target
30377 * @param {string} target
30378 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30380 get: function(target) {
30381 if (typeof(this.groups[target]) == 'undefined') {
30385 return this.groups[target] ;
30394 * page DateSplitField.
30400 * @class Roo.bootstrap.DateSplitField
30401 * @extends Roo.bootstrap.Component
30402 * Bootstrap DateSplitField class
30403 * @cfg {string} fieldLabel - the label associated
30404 * @cfg {Number} labelWidth set the width of label (0-12)
30405 * @cfg {String} labelAlign (top|left)
30406 * @cfg {Boolean} dayAllowBlank (true|false) default false
30407 * @cfg {Boolean} monthAllowBlank (true|false) default false
30408 * @cfg {Boolean} yearAllowBlank (true|false) default false
30409 * @cfg {string} dayPlaceholder
30410 * @cfg {string} monthPlaceholder
30411 * @cfg {string} yearPlaceholder
30412 * @cfg {string} dayFormat default 'd'
30413 * @cfg {string} monthFormat default 'm'
30414 * @cfg {string} yearFormat default 'Y'
30415 * @cfg {Number} labellg set the width of label (1-12)
30416 * @cfg {Number} labelmd set the width of label (1-12)
30417 * @cfg {Number} labelsm set the width of label (1-12)
30418 * @cfg {Number} labelxs set the width of label (1-12)
30422 * Create a new DateSplitField
30423 * @param {Object} config The config object
30426 Roo.bootstrap.DateSplitField = function(config){
30427 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30433 * getting the data of years
30434 * @param {Roo.bootstrap.DateSplitField} this
30435 * @param {Object} years
30440 * getting the data of days
30441 * @param {Roo.bootstrap.DateSplitField} this
30442 * @param {Object} days
30447 * Fires after the field has been marked as invalid.
30448 * @param {Roo.form.Field} this
30449 * @param {String} msg The validation message
30454 * Fires after the field has been validated with no errors.
30455 * @param {Roo.form.Field} this
30461 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30464 labelAlign : 'top',
30466 dayAllowBlank : false,
30467 monthAllowBlank : false,
30468 yearAllowBlank : false,
30469 dayPlaceholder : '',
30470 monthPlaceholder : '',
30471 yearPlaceholder : '',
30475 isFormField : true,
30481 getAutoCreate : function()
30485 cls : 'row roo-date-split-field-group',
30490 cls : 'form-hidden-field roo-date-split-field-group-value',
30496 var labelCls = 'col-md-12';
30497 var contentCls = 'col-md-4';
30499 if(this.fieldLabel){
30503 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30507 html : this.fieldLabel
30512 if(this.labelAlign == 'left'){
30514 if(this.labelWidth > 12){
30515 label.style = "width: " + this.labelWidth + 'px';
30518 if(this.labelWidth < 13 && this.labelmd == 0){
30519 this.labelmd = this.labelWidth;
30522 if(this.labellg > 0){
30523 labelCls = ' col-lg-' + this.labellg;
30524 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30527 if(this.labelmd > 0){
30528 labelCls = ' col-md-' + this.labelmd;
30529 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30532 if(this.labelsm > 0){
30533 labelCls = ' col-sm-' + this.labelsm;
30534 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30537 if(this.labelxs > 0){
30538 labelCls = ' col-xs-' + this.labelxs;
30539 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30543 label.cls += ' ' + labelCls;
30545 cfg.cn.push(label);
30548 Roo.each(['day', 'month', 'year'], function(t){
30551 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30558 inputEl: function ()
30560 return this.el.select('.roo-date-split-field-group-value', true).first();
30563 onRender : function(ct, position)
30567 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30569 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30571 this.dayField = new Roo.bootstrap.ComboBox({
30572 allowBlank : this.dayAllowBlank,
30573 alwaysQuery : true,
30574 displayField : 'value',
30577 forceSelection : true,
30579 placeholder : this.dayPlaceholder,
30580 selectOnFocus : true,
30581 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30582 triggerAction : 'all',
30584 valueField : 'value',
30585 store : new Roo.data.SimpleStore({
30586 data : (function() {
30588 _this.fireEvent('days', _this, days);
30591 fields : [ 'value' ]
30594 select : function (_self, record, index)
30596 _this.setValue(_this.getValue());
30601 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30603 this.monthField = new Roo.bootstrap.MonthField({
30604 after : '<i class=\"fa fa-calendar\"></i>',
30605 allowBlank : this.monthAllowBlank,
30606 placeholder : this.monthPlaceholder,
30609 render : function (_self)
30611 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30612 e.preventDefault();
30616 select : function (_self, oldvalue, newvalue)
30618 _this.setValue(_this.getValue());
30623 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30625 this.yearField = new Roo.bootstrap.ComboBox({
30626 allowBlank : this.yearAllowBlank,
30627 alwaysQuery : true,
30628 displayField : 'value',
30631 forceSelection : true,
30633 placeholder : this.yearPlaceholder,
30634 selectOnFocus : true,
30635 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30636 triggerAction : 'all',
30638 valueField : 'value',
30639 store : new Roo.data.SimpleStore({
30640 data : (function() {
30642 _this.fireEvent('years', _this, years);
30645 fields : [ 'value' ]
30648 select : function (_self, record, index)
30650 _this.setValue(_this.getValue());
30655 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30658 setValue : function(v, format)
30660 this.inputEl.dom.value = v;
30662 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30664 var d = Date.parseDate(v, f);
30671 this.setDay(d.format(this.dayFormat));
30672 this.setMonth(d.format(this.monthFormat));
30673 this.setYear(d.format(this.yearFormat));
30680 setDay : function(v)
30682 this.dayField.setValue(v);
30683 this.inputEl.dom.value = this.getValue();
30688 setMonth : function(v)
30690 this.monthField.setValue(v, true);
30691 this.inputEl.dom.value = this.getValue();
30696 setYear : function(v)
30698 this.yearField.setValue(v);
30699 this.inputEl.dom.value = this.getValue();
30704 getDay : function()
30706 return this.dayField.getValue();
30709 getMonth : function()
30711 return this.monthField.getValue();
30714 getYear : function()
30716 return this.yearField.getValue();
30719 getValue : function()
30721 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30723 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30733 this.inputEl.dom.value = '';
30738 validate : function()
30740 var d = this.dayField.validate();
30741 var m = this.monthField.validate();
30742 var y = this.yearField.validate();
30747 (!this.dayAllowBlank && !d) ||
30748 (!this.monthAllowBlank && !m) ||
30749 (!this.yearAllowBlank && !y)
30754 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30763 this.markInvalid();
30768 markValid : function()
30771 var label = this.el.select('label', true).first();
30772 var icon = this.el.select('i.fa-star', true).first();
30778 this.fireEvent('valid', this);
30782 * Mark this field as invalid
30783 * @param {String} msg The validation message
30785 markInvalid : function(msg)
30788 var label = this.el.select('label', true).first();
30789 var icon = this.el.select('i.fa-star', true).first();
30791 if(label && !icon){
30792 this.el.select('.roo-date-split-field-label', true).createChild({
30794 cls : 'text-danger fa fa-lg fa-star',
30795 tooltip : 'This field is required',
30796 style : 'margin-right:5px;'
30800 this.fireEvent('invalid', this, msg);
30803 clearInvalid : function()
30805 var label = this.el.select('label', true).first();
30806 var icon = this.el.select('i.fa-star', true).first();
30812 this.fireEvent('valid', this);
30815 getName: function()
30825 * http://masonry.desandro.com
30827 * The idea is to render all the bricks based on vertical width...
30829 * The original code extends 'outlayer' - we might need to use that....
30835 * @class Roo.bootstrap.LayoutMasonry
30836 * @extends Roo.bootstrap.Component
30837 * Bootstrap Layout Masonry class
30840 * Create a new Element
30841 * @param {Object} config The config object
30844 Roo.bootstrap.LayoutMasonry = function(config){
30846 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30850 Roo.bootstrap.LayoutMasonry.register(this);
30856 * Fire after layout the items
30857 * @param {Roo.bootstrap.LayoutMasonry} this
30858 * @param {Roo.EventObject} e
30865 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30868 * @cfg {Boolean} isLayoutInstant = no animation?
30870 isLayoutInstant : false, // needed?
30873 * @cfg {Number} boxWidth width of the columns
30878 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30883 * @cfg {Number} padWidth padding below box..
30888 * @cfg {Number} gutter gutter width..
30893 * @cfg {Number} maxCols maximum number of columns
30899 * @cfg {Boolean} isAutoInitial defalut true
30901 isAutoInitial : true,
30906 * @cfg {Boolean} isHorizontal defalut false
30908 isHorizontal : false,
30910 currentSize : null,
30916 bricks: null, //CompositeElement
30920 _isLayoutInited : false,
30922 // isAlternative : false, // only use for vertical layout...
30925 * @cfg {Number} alternativePadWidth padding below box..
30927 alternativePadWidth : 50,
30929 selectedBrick : [],
30931 getAutoCreate : function(){
30933 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30937 cls: 'blog-masonary-wrapper ' + this.cls,
30939 cls : 'mas-boxes masonary'
30946 getChildContainer: function( )
30948 if (this.boxesEl) {
30949 return this.boxesEl;
30952 this.boxesEl = this.el.select('.mas-boxes').first();
30954 return this.boxesEl;
30958 initEvents : function()
30962 if(this.isAutoInitial){
30963 Roo.log('hook children rendered');
30964 this.on('childrenrendered', function() {
30965 Roo.log('children rendered');
30971 initial : function()
30973 this.selectedBrick = [];
30975 this.currentSize = this.el.getBox(true);
30977 Roo.EventManager.onWindowResize(this.resize, this);
30979 if(!this.isAutoInitial){
30987 //this.layout.defer(500,this);
30991 resize : function()
30993 var cs = this.el.getBox(true);
30996 this.currentSize.width == cs.width &&
30997 this.currentSize.x == cs.x &&
30998 this.currentSize.height == cs.height &&
30999 this.currentSize.y == cs.y
31001 Roo.log("no change in with or X or Y");
31005 this.currentSize = cs;
31011 layout : function()
31013 this._resetLayout();
31015 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31017 this.layoutItems( isInstant );
31019 this._isLayoutInited = true;
31021 this.fireEvent('layout', this);
31025 _resetLayout : function()
31027 if(this.isHorizontal){
31028 this.horizontalMeasureColumns();
31032 this.verticalMeasureColumns();
31036 verticalMeasureColumns : function()
31038 this.getContainerWidth();
31040 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31041 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31045 var boxWidth = this.boxWidth + this.padWidth;
31047 if(this.containerWidth < this.boxWidth){
31048 boxWidth = this.containerWidth
31051 var containerWidth = this.containerWidth;
31053 var cols = Math.floor(containerWidth / boxWidth);
31055 this.cols = Math.max( cols, 1 );
31057 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31059 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31061 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31063 this.colWidth = boxWidth + avail - this.padWidth;
31065 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31066 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31069 horizontalMeasureColumns : function()
31071 this.getContainerWidth();
31073 var boxWidth = this.boxWidth;
31075 if(this.containerWidth < boxWidth){
31076 boxWidth = this.containerWidth;
31079 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31081 this.el.setHeight(boxWidth);
31085 getContainerWidth : function()
31087 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31090 layoutItems : function( isInstant )
31092 Roo.log(this.bricks);
31094 var items = Roo.apply([], this.bricks);
31096 if(this.isHorizontal){
31097 this._horizontalLayoutItems( items , isInstant );
31101 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31102 // this._verticalAlternativeLayoutItems( items , isInstant );
31106 this._verticalLayoutItems( items , isInstant );
31110 _verticalLayoutItems : function ( items , isInstant)
31112 if ( !items || !items.length ) {
31117 ['xs', 'xs', 'xs', 'tall'],
31118 ['xs', 'xs', 'tall'],
31119 ['xs', 'xs', 'sm'],
31120 ['xs', 'xs', 'xs'],
31126 ['sm', 'xs', 'xs'],
31130 ['tall', 'xs', 'xs', 'xs'],
31131 ['tall', 'xs', 'xs'],
31143 Roo.each(items, function(item, k){
31145 switch (item.size) {
31146 // these layouts take up a full box,
31157 boxes.push([item]);
31180 var filterPattern = function(box, length)
31188 var pattern = box.slice(0, length);
31192 Roo.each(pattern, function(i){
31193 format.push(i.size);
31196 Roo.each(standard, function(s){
31198 if(String(s) != String(format)){
31207 if(!match && length == 1){
31212 filterPattern(box, length - 1);
31216 queue.push(pattern);
31218 box = box.slice(length, box.length);
31220 filterPattern(box, 4);
31226 Roo.each(boxes, function(box, k){
31232 if(box.length == 1){
31237 filterPattern(box, 4);
31241 this._processVerticalLayoutQueue( queue, isInstant );
31245 // _verticalAlternativeLayoutItems : function( items , isInstant )
31247 // if ( !items || !items.length ) {
31251 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31255 _horizontalLayoutItems : function ( items , isInstant)
31257 if ( !items || !items.length || items.length < 3) {
31263 var eItems = items.slice(0, 3);
31265 items = items.slice(3, items.length);
31268 ['xs', 'xs', 'xs', 'wide'],
31269 ['xs', 'xs', 'wide'],
31270 ['xs', 'xs', 'sm'],
31271 ['xs', 'xs', 'xs'],
31277 ['sm', 'xs', 'xs'],
31281 ['wide', 'xs', 'xs', 'xs'],
31282 ['wide', 'xs', 'xs'],
31295 Roo.each(items, function(item, k){
31297 switch (item.size) {
31308 boxes.push([item]);
31332 var filterPattern = function(box, length)
31340 var pattern = box.slice(0, length);
31344 Roo.each(pattern, function(i){
31345 format.push(i.size);
31348 Roo.each(standard, function(s){
31350 if(String(s) != String(format)){
31359 if(!match && length == 1){
31364 filterPattern(box, length - 1);
31368 queue.push(pattern);
31370 box = box.slice(length, box.length);
31372 filterPattern(box, 4);
31378 Roo.each(boxes, function(box, k){
31384 if(box.length == 1){
31389 filterPattern(box, 4);
31396 var pos = this.el.getBox(true);
31400 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31402 var hit_end = false;
31404 Roo.each(queue, function(box){
31408 Roo.each(box, function(b){
31410 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31420 Roo.each(box, function(b){
31422 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31425 mx = Math.max(mx, b.x);
31429 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31433 Roo.each(box, function(b){
31435 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31449 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31452 /** Sets position of item in DOM
31453 * @param {Element} item
31454 * @param {Number} x - horizontal position
31455 * @param {Number} y - vertical position
31456 * @param {Boolean} isInstant - disables transitions
31458 _processVerticalLayoutQueue : function( queue, isInstant )
31460 var pos = this.el.getBox(true);
31465 for (var i = 0; i < this.cols; i++){
31469 Roo.each(queue, function(box, k){
31471 var col = k % this.cols;
31473 Roo.each(box, function(b,kk){
31475 b.el.position('absolute');
31477 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31478 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31480 if(b.size == 'md-left' || b.size == 'md-right'){
31481 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31482 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31485 b.el.setWidth(width);
31486 b.el.setHeight(height);
31488 b.el.select('iframe',true).setSize(width,height);
31492 for (var i = 0; i < this.cols; i++){
31494 if(maxY[i] < maxY[col]){
31499 col = Math.min(col, i);
31503 x = pos.x + col * (this.colWidth + this.padWidth);
31507 var positions = [];
31509 switch (box.length){
31511 positions = this.getVerticalOneBoxColPositions(x, y, box);
31514 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31517 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31520 positions = this.getVerticalFourBoxColPositions(x, y, box);
31526 Roo.each(box, function(b,kk){
31528 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31530 var sz = b.el.getSize();
31532 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31540 for (var i = 0; i < this.cols; i++){
31541 mY = Math.max(mY, maxY[i]);
31544 this.el.setHeight(mY - pos.y);
31548 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31550 // var pos = this.el.getBox(true);
31553 // var maxX = pos.right;
31555 // var maxHeight = 0;
31557 // Roo.each(items, function(item, k){
31561 // item.el.position('absolute');
31563 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31565 // item.el.setWidth(width);
31567 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31569 // item.el.setHeight(height);
31572 // item.el.setXY([x, y], isInstant ? false : true);
31574 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31577 // y = y + height + this.alternativePadWidth;
31579 // maxHeight = maxHeight + height + this.alternativePadWidth;
31583 // this.el.setHeight(maxHeight);
31587 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31589 var pos = this.el.getBox(true);
31594 var maxX = pos.right;
31596 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31598 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31600 Roo.each(queue, function(box, k){
31602 Roo.each(box, function(b, kk){
31604 b.el.position('absolute');
31606 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31607 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31609 if(b.size == 'md-left' || b.size == 'md-right'){
31610 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31611 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31614 b.el.setWidth(width);
31615 b.el.setHeight(height);
31623 var positions = [];
31625 switch (box.length){
31627 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31630 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31633 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31636 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31642 Roo.each(box, function(b,kk){
31644 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31646 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31654 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31656 Roo.each(eItems, function(b,k){
31658 b.size = (k == 0) ? 'sm' : 'xs';
31659 b.x = (k == 0) ? 2 : 1;
31660 b.y = (k == 0) ? 2 : 1;
31662 b.el.position('absolute');
31664 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31666 b.el.setWidth(width);
31668 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31670 b.el.setHeight(height);
31674 var positions = [];
31677 x : maxX - this.unitWidth * 2 - this.gutter,
31682 x : maxX - this.unitWidth,
31683 y : minY + (this.unitWidth + this.gutter) * 2
31687 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31691 Roo.each(eItems, function(b,k){
31693 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31699 getVerticalOneBoxColPositions : function(x, y, box)
31703 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31705 if(box[0].size == 'md-left'){
31709 if(box[0].size == 'md-right'){
31714 x : x + (this.unitWidth + this.gutter) * rand,
31721 getVerticalTwoBoxColPositions : function(x, y, box)
31725 if(box[0].size == 'xs'){
31729 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31733 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31747 x : x + (this.unitWidth + this.gutter) * 2,
31748 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31755 getVerticalThreeBoxColPositions : function(x, y, box)
31759 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31767 x : x + (this.unitWidth + this.gutter) * 1,
31772 x : x + (this.unitWidth + this.gutter) * 2,
31780 if(box[0].size == 'xs' && box[1].size == 'xs'){
31789 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31793 x : x + (this.unitWidth + this.gutter) * 1,
31807 x : x + (this.unitWidth + this.gutter) * 2,
31812 x : x + (this.unitWidth + this.gutter) * 2,
31813 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31820 getVerticalFourBoxColPositions : function(x, y, box)
31824 if(box[0].size == 'xs'){
31833 y : y + (this.unitHeight + this.gutter) * 1
31838 y : y + (this.unitHeight + this.gutter) * 2
31842 x : x + (this.unitWidth + this.gutter) * 1,
31856 x : x + (this.unitWidth + this.gutter) * 2,
31861 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31862 y : y + (this.unitHeight + this.gutter) * 1
31866 x : x + (this.unitWidth + this.gutter) * 2,
31867 y : y + (this.unitWidth + this.gutter) * 2
31874 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31878 if(box[0].size == 'md-left'){
31880 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31887 if(box[0].size == 'md-right'){
31889 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31890 y : minY + (this.unitWidth + this.gutter) * 1
31896 var rand = Math.floor(Math.random() * (4 - box[0].y));
31899 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31900 y : minY + (this.unitWidth + this.gutter) * rand
31907 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31911 if(box[0].size == 'xs'){
31914 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31919 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31920 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31928 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31933 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31934 y : minY + (this.unitWidth + this.gutter) * 2
31941 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31945 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31948 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31953 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31954 y : minY + (this.unitWidth + this.gutter) * 1
31958 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31959 y : minY + (this.unitWidth + this.gutter) * 2
31966 if(box[0].size == 'xs' && box[1].size == 'xs'){
31969 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31974 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31979 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31980 y : minY + (this.unitWidth + this.gutter) * 1
31988 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31993 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31994 y : minY + (this.unitWidth + this.gutter) * 2
31998 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31999 y : minY + (this.unitWidth + this.gutter) * 2
32006 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32010 if(box[0].size == 'xs'){
32013 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32018 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32023 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),
32028 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32029 y : minY + (this.unitWidth + this.gutter) * 1
32037 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32042 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32043 y : minY + (this.unitWidth + this.gutter) * 2
32047 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32048 y : minY + (this.unitWidth + this.gutter) * 2
32052 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),
32053 y : minY + (this.unitWidth + this.gutter) * 2
32061 * remove a Masonry Brick
32062 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32064 removeBrick : function(brick_id)
32070 for (var i = 0; i<this.bricks.length; i++) {
32071 if (this.bricks[i].id == brick_id) {
32072 this.bricks.splice(i,1);
32073 this.el.dom.removeChild(Roo.get(brick_id).dom);
32080 * adds a Masonry Brick
32081 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32083 addBrick : function(cfg)
32085 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32086 //this.register(cn);
32087 cn.parentId = this.id;
32088 cn.render(this.el);
32093 * register a Masonry Brick
32094 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32097 register : function(brick)
32099 this.bricks.push(brick);
32100 brick.masonryId = this.id;
32104 * clear all the Masonry Brick
32106 clearAll : function()
32109 //this.getChildContainer().dom.innerHTML = "";
32110 this.el.dom.innerHTML = '';
32113 getSelected : function()
32115 if (!this.selectedBrick) {
32119 return this.selectedBrick;
32123 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32127 * register a Masonry Layout
32128 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32131 register : function(layout)
32133 this.groups[layout.id] = layout;
32136 * fetch a Masonry Layout based on the masonry layout ID
32137 * @param {string} the masonry layout to add
32138 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32141 get: function(layout_id) {
32142 if (typeof(this.groups[layout_id]) == 'undefined') {
32145 return this.groups[layout_id] ;
32157 * http://masonry.desandro.com
32159 * The idea is to render all the bricks based on vertical width...
32161 * The original code extends 'outlayer' - we might need to use that....
32167 * @class Roo.bootstrap.LayoutMasonryAuto
32168 * @extends Roo.bootstrap.Component
32169 * Bootstrap Layout Masonry class
32172 * Create a new Element
32173 * @param {Object} config The config object
32176 Roo.bootstrap.LayoutMasonryAuto = function(config){
32177 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32180 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32183 * @cfg {Boolean} isFitWidth - resize the width..
32185 isFitWidth : false, // options..
32187 * @cfg {Boolean} isOriginLeft = left align?
32189 isOriginLeft : true,
32191 * @cfg {Boolean} isOriginTop = top align?
32193 isOriginTop : false,
32195 * @cfg {Boolean} isLayoutInstant = no animation?
32197 isLayoutInstant : false, // needed?
32199 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32201 isResizingContainer : true,
32203 * @cfg {Number} columnWidth width of the columns
32209 * @cfg {Number} maxCols maximum number of columns
32214 * @cfg {Number} padHeight padding below box..
32220 * @cfg {Boolean} isAutoInitial defalut true
32223 isAutoInitial : true,
32229 initialColumnWidth : 0,
32230 currentSize : null,
32232 colYs : null, // array.
32239 bricks: null, //CompositeElement
32240 cols : 0, // array?
32241 // element : null, // wrapped now this.el
32242 _isLayoutInited : null,
32245 getAutoCreate : function(){
32249 cls: 'blog-masonary-wrapper ' + this.cls,
32251 cls : 'mas-boxes masonary'
32258 getChildContainer: function( )
32260 if (this.boxesEl) {
32261 return this.boxesEl;
32264 this.boxesEl = this.el.select('.mas-boxes').first();
32266 return this.boxesEl;
32270 initEvents : function()
32274 if(this.isAutoInitial){
32275 Roo.log('hook children rendered');
32276 this.on('childrenrendered', function() {
32277 Roo.log('children rendered');
32284 initial : function()
32286 this.reloadItems();
32288 this.currentSize = this.el.getBox(true);
32290 /// was window resize... - let's see if this works..
32291 Roo.EventManager.onWindowResize(this.resize, this);
32293 if(!this.isAutoInitial){
32298 this.layout.defer(500,this);
32301 reloadItems: function()
32303 this.bricks = this.el.select('.masonry-brick', true);
32305 this.bricks.each(function(b) {
32306 //Roo.log(b.getSize());
32307 if (!b.attr('originalwidth')) {
32308 b.attr('originalwidth', b.getSize().width);
32313 Roo.log(this.bricks.elements.length);
32316 resize : function()
32319 var cs = this.el.getBox(true);
32321 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32322 Roo.log("no change in with or X");
32325 this.currentSize = cs;
32329 layout : function()
32332 this._resetLayout();
32333 //this._manageStamps();
32335 // don't animate first layout
32336 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32337 this.layoutItems( isInstant );
32339 // flag for initalized
32340 this._isLayoutInited = true;
32343 layoutItems : function( isInstant )
32345 //var items = this._getItemsForLayout( this.items );
32346 // original code supports filtering layout items.. we just ignore it..
32348 this._layoutItems( this.bricks , isInstant );
32350 this._postLayout();
32352 _layoutItems : function ( items , isInstant)
32354 //this.fireEvent( 'layout', this, items );
32357 if ( !items || !items.elements.length ) {
32358 // no items, emit event with empty array
32363 items.each(function(item) {
32364 Roo.log("layout item");
32366 // get x/y object from method
32367 var position = this._getItemLayoutPosition( item );
32369 position.item = item;
32370 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32371 queue.push( position );
32374 this._processLayoutQueue( queue );
32376 /** Sets position of item in DOM
32377 * @param {Element} item
32378 * @param {Number} x - horizontal position
32379 * @param {Number} y - vertical position
32380 * @param {Boolean} isInstant - disables transitions
32382 _processLayoutQueue : function( queue )
32384 for ( var i=0, len = queue.length; i < len; i++ ) {
32385 var obj = queue[i];
32386 obj.item.position('absolute');
32387 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32393 * Any logic you want to do after each layout,
32394 * i.e. size the container
32396 _postLayout : function()
32398 this.resizeContainer();
32401 resizeContainer : function()
32403 if ( !this.isResizingContainer ) {
32406 var size = this._getContainerSize();
32408 this.el.setSize(size.width,size.height);
32409 this.boxesEl.setSize(size.width,size.height);
32415 _resetLayout : function()
32417 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32418 this.colWidth = this.el.getWidth();
32419 //this.gutter = this.el.getWidth();
32421 this.measureColumns();
32427 this.colYs.push( 0 );
32433 measureColumns : function()
32435 this.getContainerWidth();
32436 // if columnWidth is 0, default to outerWidth of first item
32437 if ( !this.columnWidth ) {
32438 var firstItem = this.bricks.first();
32439 Roo.log(firstItem);
32440 this.columnWidth = this.containerWidth;
32441 if (firstItem && firstItem.attr('originalwidth') ) {
32442 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32444 // columnWidth fall back to item of first element
32445 Roo.log("set column width?");
32446 this.initialColumnWidth = this.columnWidth ;
32448 // if first elem has no width, default to size of container
32453 if (this.initialColumnWidth) {
32454 this.columnWidth = this.initialColumnWidth;
32459 // column width is fixed at the top - however if container width get's smaller we should
32462 // this bit calcs how man columns..
32464 var columnWidth = this.columnWidth += this.gutter;
32466 // calculate columns
32467 var containerWidth = this.containerWidth + this.gutter;
32469 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32470 // fix rounding errors, typically with gutters
32471 var excess = columnWidth - containerWidth % columnWidth;
32474 // if overshoot is less than a pixel, round up, otherwise floor it
32475 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32476 cols = Math[ mathMethod ]( cols );
32477 this.cols = Math.max( cols, 1 );
32478 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32480 // padding positioning..
32481 var totalColWidth = this.cols * this.columnWidth;
32482 var padavail = this.containerWidth - totalColWidth;
32483 // so for 2 columns - we need 3 'pads'
32485 var padNeeded = (1+this.cols) * this.padWidth;
32487 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32489 this.columnWidth += padExtra
32490 //this.padWidth = Math.floor(padavail / ( this.cols));
32492 // adjust colum width so that padding is fixed??
32494 // we have 3 columns ... total = width * 3
32495 // we have X left over... that should be used by
32497 //if (this.expandC) {
32505 getContainerWidth : function()
32507 /* // container is parent if fit width
32508 var container = this.isFitWidth ? this.element.parentNode : this.element;
32509 // check that this.size and size are there
32510 // IE8 triggers resize on body size change, so they might not be
32512 var size = getSize( container ); //FIXME
32513 this.containerWidth = size && size.innerWidth; //FIXME
32516 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32520 _getItemLayoutPosition : function( item ) // what is item?
32522 // we resize the item to our columnWidth..
32524 item.setWidth(this.columnWidth);
32525 item.autoBoxAdjust = false;
32527 var sz = item.getSize();
32529 // how many columns does this brick span
32530 var remainder = this.containerWidth % this.columnWidth;
32532 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32533 // round if off by 1 pixel, otherwise use ceil
32534 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32535 colSpan = Math.min( colSpan, this.cols );
32537 // normally this should be '1' as we dont' currently allow multi width columns..
32539 var colGroup = this._getColGroup( colSpan );
32540 // get the minimum Y value from the columns
32541 var minimumY = Math.min.apply( Math, colGroup );
32542 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32544 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32546 // position the brick
32548 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32549 y: this.currentSize.y + minimumY + this.padHeight
32553 // apply setHeight to necessary columns
32554 var setHeight = minimumY + sz.height + this.padHeight;
32555 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32557 var setSpan = this.cols + 1 - colGroup.length;
32558 for ( var i = 0; i < setSpan; i++ ) {
32559 this.colYs[ shortColIndex + i ] = setHeight ;
32566 * @param {Number} colSpan - number of columns the element spans
32567 * @returns {Array} colGroup
32569 _getColGroup : function( colSpan )
32571 if ( colSpan < 2 ) {
32572 // if brick spans only one column, use all the column Ys
32577 // how many different places could this brick fit horizontally
32578 var groupCount = this.cols + 1 - colSpan;
32579 // for each group potential horizontal position
32580 for ( var i = 0; i < groupCount; i++ ) {
32581 // make an array of colY values for that one group
32582 var groupColYs = this.colYs.slice( i, i + colSpan );
32583 // and get the max value of the array
32584 colGroup[i] = Math.max.apply( Math, groupColYs );
32589 _manageStamp : function( stamp )
32591 var stampSize = stamp.getSize();
32592 var offset = stamp.getBox();
32593 // get the columns that this stamp affects
32594 var firstX = this.isOriginLeft ? offset.x : offset.right;
32595 var lastX = firstX + stampSize.width;
32596 var firstCol = Math.floor( firstX / this.columnWidth );
32597 firstCol = Math.max( 0, firstCol );
32599 var lastCol = Math.floor( lastX / this.columnWidth );
32600 // lastCol should not go over if multiple of columnWidth #425
32601 lastCol -= lastX % this.columnWidth ? 0 : 1;
32602 lastCol = Math.min( this.cols - 1, lastCol );
32604 // set colYs to bottom of the stamp
32605 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32608 for ( var i = firstCol; i <= lastCol; i++ ) {
32609 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32614 _getContainerSize : function()
32616 this.maxY = Math.max.apply( Math, this.colYs );
32621 if ( this.isFitWidth ) {
32622 size.width = this._getContainerFitWidth();
32628 _getContainerFitWidth : function()
32630 var unusedCols = 0;
32631 // count unused columns
32634 if ( this.colYs[i] !== 0 ) {
32639 // fit container to columns that have been used
32640 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32643 needsResizeLayout : function()
32645 var previousWidth = this.containerWidth;
32646 this.getContainerWidth();
32647 return previousWidth !== this.containerWidth;
32662 * @class Roo.bootstrap.MasonryBrick
32663 * @extends Roo.bootstrap.Component
32664 * Bootstrap MasonryBrick class
32667 * Create a new MasonryBrick
32668 * @param {Object} config The config object
32671 Roo.bootstrap.MasonryBrick = function(config){
32673 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32675 Roo.bootstrap.MasonryBrick.register(this);
32681 * When a MasonryBrick is clcik
32682 * @param {Roo.bootstrap.MasonryBrick} this
32683 * @param {Roo.EventObject} e
32689 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32692 * @cfg {String} title
32696 * @cfg {String} html
32700 * @cfg {String} bgimage
32704 * @cfg {String} videourl
32708 * @cfg {String} cls
32712 * @cfg {String} href
32716 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32721 * @cfg {String} placetitle (center|bottom)
32726 * @cfg {Boolean} isFitContainer defalut true
32728 isFitContainer : true,
32731 * @cfg {Boolean} preventDefault defalut false
32733 preventDefault : false,
32736 * @cfg {Boolean} inverse defalut false
32738 maskInverse : false,
32740 getAutoCreate : function()
32742 if(!this.isFitContainer){
32743 return this.getSplitAutoCreate();
32746 var cls = 'masonry-brick masonry-brick-full';
32748 if(this.href.length){
32749 cls += ' masonry-brick-link';
32752 if(this.bgimage.length){
32753 cls += ' masonry-brick-image';
32756 if(this.maskInverse){
32757 cls += ' mask-inverse';
32760 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32761 cls += ' enable-mask';
32765 cls += ' masonry-' + this.size + '-brick';
32768 if(this.placetitle.length){
32770 switch (this.placetitle) {
32772 cls += ' masonry-center-title';
32775 cls += ' masonry-bottom-title';
32782 if(!this.html.length && !this.bgimage.length){
32783 cls += ' masonry-center-title';
32786 if(!this.html.length && this.bgimage.length){
32787 cls += ' masonry-bottom-title';
32792 cls += ' ' + this.cls;
32796 tag: (this.href.length) ? 'a' : 'div',
32801 cls: 'masonry-brick-mask'
32805 cls: 'masonry-brick-paragraph',
32811 if(this.href.length){
32812 cfg.href = this.href;
32815 var cn = cfg.cn[1].cn;
32817 if(this.title.length){
32820 cls: 'masonry-brick-title',
32825 if(this.html.length){
32828 cls: 'masonry-brick-text',
32833 if (!this.title.length && !this.html.length) {
32834 cfg.cn[1].cls += ' hide';
32837 if(this.bgimage.length){
32840 cls: 'masonry-brick-image-view',
32845 if(this.videourl.length){
32846 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32847 // youtube support only?
32850 cls: 'masonry-brick-image-view',
32853 allowfullscreen : true
32861 getSplitAutoCreate : function()
32863 var cls = 'masonry-brick masonry-brick-split';
32865 if(this.href.length){
32866 cls += ' masonry-brick-link';
32869 if(this.bgimage.length){
32870 cls += ' masonry-brick-image';
32874 cls += ' masonry-' + this.size + '-brick';
32877 switch (this.placetitle) {
32879 cls += ' masonry-center-title';
32882 cls += ' masonry-bottom-title';
32885 if(!this.bgimage.length){
32886 cls += ' masonry-center-title';
32889 if(this.bgimage.length){
32890 cls += ' masonry-bottom-title';
32896 cls += ' ' + this.cls;
32900 tag: (this.href.length) ? 'a' : 'div',
32905 cls: 'masonry-brick-split-head',
32909 cls: 'masonry-brick-paragraph',
32916 cls: 'masonry-brick-split-body',
32922 if(this.href.length){
32923 cfg.href = this.href;
32926 if(this.title.length){
32927 cfg.cn[0].cn[0].cn.push({
32929 cls: 'masonry-brick-title',
32934 if(this.html.length){
32935 cfg.cn[1].cn.push({
32937 cls: 'masonry-brick-text',
32942 if(this.bgimage.length){
32943 cfg.cn[0].cn.push({
32945 cls: 'masonry-brick-image-view',
32950 if(this.videourl.length){
32951 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32952 // youtube support only?
32953 cfg.cn[0].cn.cn.push({
32955 cls: 'masonry-brick-image-view',
32958 allowfullscreen : true
32965 initEvents: function()
32967 switch (this.size) {
33000 this.el.on('touchstart', this.onTouchStart, this);
33001 this.el.on('touchmove', this.onTouchMove, this);
33002 this.el.on('touchend', this.onTouchEnd, this);
33003 this.el.on('contextmenu', this.onContextMenu, this);
33005 this.el.on('mouseenter' ,this.enter, this);
33006 this.el.on('mouseleave', this.leave, this);
33007 this.el.on('click', this.onClick, this);
33010 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33011 this.parent().bricks.push(this);
33016 onClick: function(e, el)
33018 var time = this.endTimer - this.startTimer;
33019 // Roo.log(e.preventDefault());
33022 e.preventDefault();
33027 if(!this.preventDefault){
33031 e.preventDefault();
33033 if (this.activeClass != '') {
33034 this.selectBrick();
33037 this.fireEvent('click', this, e);
33040 enter: function(e, el)
33042 e.preventDefault();
33044 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33048 if(this.bgimage.length && this.html.length){
33049 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33053 leave: function(e, el)
33055 e.preventDefault();
33057 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33061 if(this.bgimage.length && this.html.length){
33062 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33066 onTouchStart: function(e, el)
33068 // e.preventDefault();
33070 this.touchmoved = false;
33072 if(!this.isFitContainer){
33076 if(!this.bgimage.length || !this.html.length){
33080 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33082 this.timer = new Date().getTime();
33086 onTouchMove: function(e, el)
33088 this.touchmoved = true;
33091 onContextMenu : function(e,el)
33093 e.preventDefault();
33094 e.stopPropagation();
33098 onTouchEnd: function(e, el)
33100 // e.preventDefault();
33102 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33109 if(!this.bgimage.length || !this.html.length){
33111 if(this.href.length){
33112 window.location.href = this.href;
33118 if(!this.isFitContainer){
33122 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33124 window.location.href = this.href;
33127 //selection on single brick only
33128 selectBrick : function() {
33130 if (!this.parentId) {
33134 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33135 var index = m.selectedBrick.indexOf(this.id);
33138 m.selectedBrick.splice(index,1);
33139 this.el.removeClass(this.activeClass);
33143 for(var i = 0; i < m.selectedBrick.length; i++) {
33144 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33145 b.el.removeClass(b.activeClass);
33148 m.selectedBrick = [];
33150 m.selectedBrick.push(this.id);
33151 this.el.addClass(this.activeClass);
33155 isSelected : function(){
33156 return this.el.hasClass(this.activeClass);
33161 Roo.apply(Roo.bootstrap.MasonryBrick, {
33164 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33166 * register a Masonry Brick
33167 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33170 register : function(brick)
33172 //this.groups[brick.id] = brick;
33173 this.groups.add(brick.id, brick);
33176 * fetch a masonry brick based on the masonry brick ID
33177 * @param {string} the masonry brick to add
33178 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33181 get: function(brick_id)
33183 // if (typeof(this.groups[brick_id]) == 'undefined') {
33186 // return this.groups[brick_id] ;
33188 if(this.groups.key(brick_id)) {
33189 return this.groups.key(brick_id);
33207 * @class Roo.bootstrap.Brick
33208 * @extends Roo.bootstrap.Component
33209 * Bootstrap Brick class
33212 * Create a new Brick
33213 * @param {Object} config The config object
33216 Roo.bootstrap.Brick = function(config){
33217 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33223 * When a Brick is click
33224 * @param {Roo.bootstrap.Brick} this
33225 * @param {Roo.EventObject} e
33231 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33234 * @cfg {String} title
33238 * @cfg {String} html
33242 * @cfg {String} bgimage
33246 * @cfg {String} cls
33250 * @cfg {String} href
33254 * @cfg {String} video
33258 * @cfg {Boolean} square
33262 getAutoCreate : function()
33264 var cls = 'roo-brick';
33266 if(this.href.length){
33267 cls += ' roo-brick-link';
33270 if(this.bgimage.length){
33271 cls += ' roo-brick-image';
33274 if(!this.html.length && !this.bgimage.length){
33275 cls += ' roo-brick-center-title';
33278 if(!this.html.length && this.bgimage.length){
33279 cls += ' roo-brick-bottom-title';
33283 cls += ' ' + this.cls;
33287 tag: (this.href.length) ? 'a' : 'div',
33292 cls: 'roo-brick-paragraph',
33298 if(this.href.length){
33299 cfg.href = this.href;
33302 var cn = cfg.cn[0].cn;
33304 if(this.title.length){
33307 cls: 'roo-brick-title',
33312 if(this.html.length){
33315 cls: 'roo-brick-text',
33322 if(this.bgimage.length){
33325 cls: 'roo-brick-image-view',
33333 initEvents: function()
33335 if(this.title.length || this.html.length){
33336 this.el.on('mouseenter' ,this.enter, this);
33337 this.el.on('mouseleave', this.leave, this);
33340 Roo.EventManager.onWindowResize(this.resize, this);
33342 if(this.bgimage.length){
33343 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33344 this.imageEl.on('load', this.onImageLoad, this);
33351 onImageLoad : function()
33356 resize : function()
33358 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33360 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33362 if(this.bgimage.length){
33363 var image = this.el.select('.roo-brick-image-view', true).first();
33365 image.setWidth(paragraph.getWidth());
33368 image.setHeight(paragraph.getWidth());
33371 this.el.setHeight(image.getHeight());
33372 paragraph.setHeight(image.getHeight());
33378 enter: function(e, el)
33380 e.preventDefault();
33382 if(this.bgimage.length){
33383 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33384 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33388 leave: function(e, el)
33390 e.preventDefault();
33392 if(this.bgimage.length){
33393 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33394 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33409 * @class Roo.bootstrap.NumberField
33410 * @extends Roo.bootstrap.Input
33411 * Bootstrap NumberField class
33417 * Create a new NumberField
33418 * @param {Object} config The config object
33421 Roo.bootstrap.NumberField = function(config){
33422 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33425 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33428 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33430 allowDecimals : true,
33432 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33434 decimalSeparator : ".",
33436 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33438 decimalPrecision : 2,
33440 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33442 allowNegative : true,
33445 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33449 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33451 minValue : Number.NEGATIVE_INFINITY,
33453 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33455 maxValue : Number.MAX_VALUE,
33457 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33459 minText : "The minimum value for this field is {0}",
33461 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33463 maxText : "The maximum value for this field is {0}",
33465 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33466 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33468 nanText : "{0} is not a valid number",
33470 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33472 thousandsDelimiter : false,
33474 * @cfg {String} valueAlign alignment of value
33476 valueAlign : "left",
33478 getAutoCreate : function()
33480 var hiddenInput = {
33484 cls: 'hidden-number-input'
33488 hiddenInput.name = this.name;
33493 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33495 this.name = hiddenInput.name;
33497 if(cfg.cn.length > 0) {
33498 cfg.cn.push(hiddenInput);
33505 initEvents : function()
33507 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33509 var allowed = "0123456789";
33511 if(this.allowDecimals){
33512 allowed += this.decimalSeparator;
33515 if(this.allowNegative){
33519 if(this.thousandsDelimiter) {
33523 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33525 var keyPress = function(e){
33527 var k = e.getKey();
33529 var c = e.getCharCode();
33532 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33533 allowed.indexOf(String.fromCharCode(c)) === -1
33539 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33543 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33548 this.el.on("keypress", keyPress, this);
33551 validateValue : function(value)
33554 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33558 var num = this.parseValue(value);
33561 this.markInvalid(String.format(this.nanText, value));
33565 if(num < this.minValue){
33566 this.markInvalid(String.format(this.minText, this.minValue));
33570 if(num > this.maxValue){
33571 this.markInvalid(String.format(this.maxText, this.maxValue));
33578 getValue : function()
33580 var v = this.hiddenEl().getValue();
33582 return this.fixPrecision(this.parseValue(v));
33585 parseValue : function(value)
33587 if(this.thousandsDelimiter) {
33589 r = new RegExp(",", "g");
33590 value = value.replace(r, "");
33593 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33594 return isNaN(value) ? '' : value;
33597 fixPrecision : function(value)
33599 if(this.thousandsDelimiter) {
33601 r = new RegExp(",", "g");
33602 value = value.replace(r, "");
33605 var nan = isNaN(value);
33607 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33608 return nan ? '' : value;
33610 return parseFloat(value).toFixed(this.decimalPrecision);
33613 setValue : function(v)
33615 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33621 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33623 this.inputEl().dom.value = (v == '') ? '' :
33624 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33626 if(!this.allowZero && v === '0') {
33627 this.hiddenEl().dom.value = '';
33628 this.inputEl().dom.value = '';
33635 decimalPrecisionFcn : function(v)
33637 return Math.floor(v);
33640 beforeBlur : function()
33642 var v = this.parseValue(this.getRawValue());
33644 if(v || v === 0 || v === ''){
33649 hiddenEl : function()
33651 return this.el.select('input.hidden-number-input',true).first();
33663 * @class Roo.bootstrap.DocumentSlider
33664 * @extends Roo.bootstrap.Component
33665 * Bootstrap DocumentSlider class
33668 * Create a new DocumentViewer
33669 * @param {Object} config The config object
33672 Roo.bootstrap.DocumentSlider = function(config){
33673 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33680 * Fire after initEvent
33681 * @param {Roo.bootstrap.DocumentSlider} this
33686 * Fire after update
33687 * @param {Roo.bootstrap.DocumentSlider} this
33693 * @param {Roo.bootstrap.DocumentSlider} this
33699 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33705 getAutoCreate : function()
33709 cls : 'roo-document-slider',
33713 cls : 'roo-document-slider-header',
33717 cls : 'roo-document-slider-header-title'
33723 cls : 'roo-document-slider-body',
33727 cls : 'roo-document-slider-prev',
33731 cls : 'fa fa-chevron-left'
33737 cls : 'roo-document-slider-thumb',
33741 cls : 'roo-document-slider-image'
33747 cls : 'roo-document-slider-next',
33751 cls : 'fa fa-chevron-right'
33763 initEvents : function()
33765 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33766 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33768 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33769 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33771 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33772 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33774 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33775 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33777 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33778 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33780 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33781 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33783 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33784 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33786 this.thumbEl.on('click', this.onClick, this);
33788 this.prevIndicator.on('click', this.prev, this);
33790 this.nextIndicator.on('click', this.next, this);
33794 initial : function()
33796 if(this.files.length){
33797 this.indicator = 1;
33801 this.fireEvent('initial', this);
33804 update : function()
33806 this.imageEl.attr('src', this.files[this.indicator - 1]);
33808 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33810 this.prevIndicator.show();
33812 if(this.indicator == 1){
33813 this.prevIndicator.hide();
33816 this.nextIndicator.show();
33818 if(this.indicator == this.files.length){
33819 this.nextIndicator.hide();
33822 this.thumbEl.scrollTo('top');
33824 this.fireEvent('update', this);
33827 onClick : function(e)
33829 e.preventDefault();
33831 this.fireEvent('click', this);
33836 e.preventDefault();
33838 this.indicator = Math.max(1, this.indicator - 1);
33845 e.preventDefault();
33847 this.indicator = Math.min(this.files.length, this.indicator + 1);
33861 * @class Roo.bootstrap.RadioSet
33862 * @extends Roo.bootstrap.Input
33863 * Bootstrap RadioSet class
33864 * @cfg {String} indicatorpos (left|right) default left
33865 * @cfg {Boolean} inline (true|false) inline the element (default true)
33866 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33868 * Create a new RadioSet
33869 * @param {Object} config The config object
33872 Roo.bootstrap.RadioSet = function(config){
33874 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33878 Roo.bootstrap.RadioSet.register(this);
33883 * Fires when the element is checked or unchecked.
33884 * @param {Roo.bootstrap.RadioSet} this This radio
33885 * @param {Roo.bootstrap.Radio} item The checked item
33890 * Fires when the element is click.
33891 * @param {Roo.bootstrap.RadioSet} this This radio set
33892 * @param {Roo.bootstrap.Radio} item The checked item
33893 * @param {Roo.EventObject} e The event object
33900 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33908 indicatorpos : 'left',
33910 getAutoCreate : function()
33914 cls : 'roo-radio-set-label',
33918 html : this.fieldLabel
33923 if(this.indicatorpos == 'left'){
33926 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33927 tooltip : 'This field is required'
33932 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33933 tooltip : 'This field is required'
33939 cls : 'roo-radio-set-items'
33942 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33944 if (align === 'left' && this.fieldLabel.length) {
33947 cls : "roo-radio-set-right",
33953 if(this.labelWidth > 12){
33954 label.style = "width: " + this.labelWidth + 'px';
33957 if(this.labelWidth < 13 && this.labelmd == 0){
33958 this.labelmd = this.labelWidth;
33961 if(this.labellg > 0){
33962 label.cls += ' col-lg-' + this.labellg;
33963 items.cls += ' col-lg-' + (12 - this.labellg);
33966 if(this.labelmd > 0){
33967 label.cls += ' col-md-' + this.labelmd;
33968 items.cls += ' col-md-' + (12 - this.labelmd);
33971 if(this.labelsm > 0){
33972 label.cls += ' col-sm-' + this.labelsm;
33973 items.cls += ' col-sm-' + (12 - this.labelsm);
33976 if(this.labelxs > 0){
33977 label.cls += ' col-xs-' + this.labelxs;
33978 items.cls += ' col-xs-' + (12 - this.labelxs);
33984 cls : 'roo-radio-set',
33988 cls : 'roo-radio-set-input',
33991 value : this.value ? this.value : ''
33998 if(this.weight.length){
33999 cfg.cls += ' roo-radio-' + this.weight;
34003 cfg.cls += ' roo-radio-set-inline';
34007 ['xs','sm','md','lg'].map(function(size){
34008 if (settings[size]) {
34009 cfg.cls += ' col-' + size + '-' + settings[size];
34017 initEvents : function()
34019 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34020 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34022 if(!this.fieldLabel.length){
34023 this.labelEl.hide();
34026 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34027 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34029 this.indicator = this.indicatorEl();
34031 if(this.indicator){
34032 this.indicator.addClass('invisible');
34035 this.originalValue = this.getValue();
34039 inputEl: function ()
34041 return this.el.select('.roo-radio-set-input', true).first();
34044 getChildContainer : function()
34046 return this.itemsEl;
34049 register : function(item)
34051 this.radioes.push(item);
34055 validate : function()
34057 if(this.getVisibilityEl().hasClass('hidden')){
34063 Roo.each(this.radioes, function(i){
34072 if(this.allowBlank) {
34076 if(this.disabled || valid){
34081 this.markInvalid();
34086 markValid : function()
34088 if(this.labelEl.isVisible(true)){
34089 this.indicatorEl().removeClass('visible');
34090 this.indicatorEl().addClass('invisible');
34093 this.el.removeClass([this.invalidClass, this.validClass]);
34094 this.el.addClass(this.validClass);
34096 this.fireEvent('valid', this);
34099 markInvalid : function(msg)
34101 if(this.allowBlank || this.disabled){
34105 if(this.labelEl.isVisible(true)){
34106 this.indicatorEl().removeClass('invisible');
34107 this.indicatorEl().addClass('visible');
34110 this.el.removeClass([this.invalidClass, this.validClass]);
34111 this.el.addClass(this.invalidClass);
34113 this.fireEvent('invalid', this, msg);
34117 setValue : function(v, suppressEvent)
34119 if(this.value === v){
34126 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34129 Roo.each(this.radioes, function(i){
34131 i.el.removeClass('checked');
34134 Roo.each(this.radioes, function(i){
34136 if(i.value === v || i.value.toString() === v.toString()){
34138 i.el.addClass('checked');
34140 if(suppressEvent !== true){
34141 this.fireEvent('check', this, i);
34152 clearInvalid : function(){
34154 if(!this.el || this.preventMark){
34158 this.el.removeClass([this.invalidClass]);
34160 this.fireEvent('valid', this);
34165 Roo.apply(Roo.bootstrap.RadioSet, {
34169 register : function(set)
34171 this.groups[set.name] = set;
34174 get: function(name)
34176 if (typeof(this.groups[name]) == 'undefined') {
34180 return this.groups[name] ;
34186 * Ext JS Library 1.1.1
34187 * Copyright(c) 2006-2007, Ext JS, LLC.
34189 * Originally Released Under LGPL - original licence link has changed is not relivant.
34192 * <script type="text/javascript">
34197 * @class Roo.bootstrap.SplitBar
34198 * @extends Roo.util.Observable
34199 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34203 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34204 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34205 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34206 split.minSize = 100;
34207 split.maxSize = 600;
34208 split.animate = true;
34209 split.on('moved', splitterMoved);
34212 * Create a new SplitBar
34213 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34214 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34215 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34216 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34217 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34218 position of the SplitBar).
34220 Roo.bootstrap.SplitBar = function(cfg){
34225 // dragElement : elm
34226 // resizingElement: el,
34228 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34229 // placement : Roo.bootstrap.SplitBar.LEFT ,
34230 // existingProxy ???
34233 this.el = Roo.get(cfg.dragElement, true);
34234 this.el.dom.unselectable = "on";
34236 this.resizingEl = Roo.get(cfg.resizingElement, true);
34240 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34241 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34244 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34247 * The minimum size of the resizing element. (Defaults to 0)
34253 * The maximum size of the resizing element. (Defaults to 2000)
34256 this.maxSize = 2000;
34259 * Whether to animate the transition to the new size
34262 this.animate = false;
34265 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34268 this.useShim = false;
34273 if(!cfg.existingProxy){
34275 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34277 this.proxy = Roo.get(cfg.existingProxy).dom;
34280 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34283 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34286 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34289 this.dragSpecs = {};
34292 * @private The adapter to use to positon and resize elements
34294 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34295 this.adapter.init(this);
34297 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34299 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34300 this.el.addClass("roo-splitbar-h");
34303 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34304 this.el.addClass("roo-splitbar-v");
34310 * Fires when the splitter is moved (alias for {@link #event-moved})
34311 * @param {Roo.bootstrap.SplitBar} this
34312 * @param {Number} newSize the new width or height
34317 * Fires when the splitter is moved
34318 * @param {Roo.bootstrap.SplitBar} this
34319 * @param {Number} newSize the new width or height
34323 * @event beforeresize
34324 * Fires before the splitter is dragged
34325 * @param {Roo.bootstrap.SplitBar} this
34327 "beforeresize" : true,
34329 "beforeapply" : true
34332 Roo.util.Observable.call(this);
34335 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34336 onStartProxyDrag : function(x, y){
34337 this.fireEvent("beforeresize", this);
34339 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34341 o.enableDisplayMode("block");
34342 // all splitbars share the same overlay
34343 Roo.bootstrap.SplitBar.prototype.overlay = o;
34345 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34346 this.overlay.show();
34347 Roo.get(this.proxy).setDisplayed("block");
34348 var size = this.adapter.getElementSize(this);
34349 this.activeMinSize = this.getMinimumSize();;
34350 this.activeMaxSize = this.getMaximumSize();;
34351 var c1 = size - this.activeMinSize;
34352 var c2 = Math.max(this.activeMaxSize - size, 0);
34353 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34354 this.dd.resetConstraints();
34355 this.dd.setXConstraint(
34356 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34357 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34359 this.dd.setYConstraint(0, 0);
34361 this.dd.resetConstraints();
34362 this.dd.setXConstraint(0, 0);
34363 this.dd.setYConstraint(
34364 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34365 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34368 this.dragSpecs.startSize = size;
34369 this.dragSpecs.startPoint = [x, y];
34370 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34374 * @private Called after the drag operation by the DDProxy
34376 onEndProxyDrag : function(e){
34377 Roo.get(this.proxy).setDisplayed(false);
34378 var endPoint = Roo.lib.Event.getXY(e);
34380 this.overlay.hide();
34383 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34384 newSize = this.dragSpecs.startSize +
34385 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34386 endPoint[0] - this.dragSpecs.startPoint[0] :
34387 this.dragSpecs.startPoint[0] - endPoint[0]
34390 newSize = this.dragSpecs.startSize +
34391 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34392 endPoint[1] - this.dragSpecs.startPoint[1] :
34393 this.dragSpecs.startPoint[1] - endPoint[1]
34396 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34397 if(newSize != this.dragSpecs.startSize){
34398 if(this.fireEvent('beforeapply', this, newSize) !== false){
34399 this.adapter.setElementSize(this, newSize);
34400 this.fireEvent("moved", this, newSize);
34401 this.fireEvent("resize", this, newSize);
34407 * Get the adapter this SplitBar uses
34408 * @return The adapter object
34410 getAdapter : function(){
34411 return this.adapter;
34415 * Set the adapter this SplitBar uses
34416 * @param {Object} adapter A SplitBar adapter object
34418 setAdapter : function(adapter){
34419 this.adapter = adapter;
34420 this.adapter.init(this);
34424 * Gets the minimum size for the resizing element
34425 * @return {Number} The minimum size
34427 getMinimumSize : function(){
34428 return this.minSize;
34432 * Sets the minimum size for the resizing element
34433 * @param {Number} minSize The minimum size
34435 setMinimumSize : function(minSize){
34436 this.minSize = minSize;
34440 * Gets the maximum size for the resizing element
34441 * @return {Number} The maximum size
34443 getMaximumSize : function(){
34444 return this.maxSize;
34448 * Sets the maximum size for the resizing element
34449 * @param {Number} maxSize The maximum size
34451 setMaximumSize : function(maxSize){
34452 this.maxSize = maxSize;
34456 * Sets the initialize size for the resizing element
34457 * @param {Number} size The initial size
34459 setCurrentSize : function(size){
34460 var oldAnimate = this.animate;
34461 this.animate = false;
34462 this.adapter.setElementSize(this, size);
34463 this.animate = oldAnimate;
34467 * Destroy this splitbar.
34468 * @param {Boolean} removeEl True to remove the element
34470 destroy : function(removeEl){
34472 this.shim.remove();
34475 this.proxy.parentNode.removeChild(this.proxy);
34483 * @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.
34485 Roo.bootstrap.SplitBar.createProxy = function(dir){
34486 var proxy = new Roo.Element(document.createElement("div"));
34487 proxy.unselectable();
34488 var cls = 'roo-splitbar-proxy';
34489 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34490 document.body.appendChild(proxy.dom);
34495 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34496 * Default Adapter. It assumes the splitter and resizing element are not positioned
34497 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34499 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34502 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34503 // do nothing for now
34504 init : function(s){
34508 * Called before drag operations to get the current size of the resizing element.
34509 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34511 getElementSize : function(s){
34512 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34513 return s.resizingEl.getWidth();
34515 return s.resizingEl.getHeight();
34520 * Called after drag operations to set the size of the resizing element.
34521 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34522 * @param {Number} newSize The new size to set
34523 * @param {Function} onComplete A function to be invoked when resizing is complete
34525 setElementSize : function(s, newSize, onComplete){
34526 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34528 s.resizingEl.setWidth(newSize);
34530 onComplete(s, newSize);
34533 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34538 s.resizingEl.setHeight(newSize);
34540 onComplete(s, newSize);
34543 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34550 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34551 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34552 * Adapter that moves the splitter element to align with the resized sizing element.
34553 * Used with an absolute positioned SplitBar.
34554 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34555 * document.body, make sure you assign an id to the body element.
34557 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34558 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34559 this.container = Roo.get(container);
34562 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34563 init : function(s){
34564 this.basic.init(s);
34567 getElementSize : function(s){
34568 return this.basic.getElementSize(s);
34571 setElementSize : function(s, newSize, onComplete){
34572 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34575 moveSplitter : function(s){
34576 var yes = Roo.bootstrap.SplitBar;
34577 switch(s.placement){
34579 s.el.setX(s.resizingEl.getRight());
34582 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34585 s.el.setY(s.resizingEl.getBottom());
34588 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34595 * Orientation constant - Create a vertical SplitBar
34599 Roo.bootstrap.SplitBar.VERTICAL = 1;
34602 * Orientation constant - Create a horizontal SplitBar
34606 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34609 * Placement constant - The resizing element is to the left of the splitter element
34613 Roo.bootstrap.SplitBar.LEFT = 1;
34616 * Placement constant - The resizing element is to the right of the splitter element
34620 Roo.bootstrap.SplitBar.RIGHT = 2;
34623 * Placement constant - The resizing element is positioned above the splitter element
34627 Roo.bootstrap.SplitBar.TOP = 3;
34630 * Placement constant - The resizing element is positioned under splitter element
34634 Roo.bootstrap.SplitBar.BOTTOM = 4;
34635 Roo.namespace("Roo.bootstrap.layout");/*
34637 * Ext JS Library 1.1.1
34638 * Copyright(c) 2006-2007, Ext JS, LLC.
34640 * Originally Released Under LGPL - original licence link has changed is not relivant.
34643 * <script type="text/javascript">
34647 * @class Roo.bootstrap.layout.Manager
34648 * @extends Roo.bootstrap.Component
34649 * Base class for layout managers.
34651 Roo.bootstrap.layout.Manager = function(config)
34653 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34659 /** false to disable window resize monitoring @type Boolean */
34660 this.monitorWindowResize = true;
34665 * Fires when a layout is performed.
34666 * @param {Roo.LayoutManager} this
34670 * @event regionresized
34671 * Fires when the user resizes a region.
34672 * @param {Roo.LayoutRegion} region The resized region
34673 * @param {Number} newSize The new size (width for east/west, height for north/south)
34675 "regionresized" : true,
34677 * @event regioncollapsed
34678 * Fires when a region is collapsed.
34679 * @param {Roo.LayoutRegion} region The collapsed region
34681 "regioncollapsed" : true,
34683 * @event regionexpanded
34684 * Fires when a region is expanded.
34685 * @param {Roo.LayoutRegion} region The expanded region
34687 "regionexpanded" : true
34689 this.updating = false;
34692 this.el = Roo.get(config.el);
34698 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34703 monitorWindowResize : true,
34709 onRender : function(ct, position)
34712 this.el = Roo.get(ct);
34715 //this.fireEvent('render',this);
34719 initEvents: function()
34723 // ie scrollbar fix
34724 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34725 document.body.scroll = "no";
34726 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34727 this.el.position('relative');
34729 this.id = this.el.id;
34730 this.el.addClass("roo-layout-container");
34731 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34732 if(this.el.dom != document.body ) {
34733 this.el.on('resize', this.layout,this);
34734 this.el.on('show', this.layout,this);
34740 * Returns true if this layout is currently being updated
34741 * @return {Boolean}
34743 isUpdating : function(){
34744 return this.updating;
34748 * Suspend the LayoutManager from doing auto-layouts while
34749 * making multiple add or remove calls
34751 beginUpdate : function(){
34752 this.updating = true;
34756 * Restore auto-layouts and optionally disable the manager from performing a layout
34757 * @param {Boolean} noLayout true to disable a layout update
34759 endUpdate : function(noLayout){
34760 this.updating = false;
34766 layout: function(){
34770 onRegionResized : function(region, newSize){
34771 this.fireEvent("regionresized", region, newSize);
34775 onRegionCollapsed : function(region){
34776 this.fireEvent("regioncollapsed", region);
34779 onRegionExpanded : function(region){
34780 this.fireEvent("regionexpanded", region);
34784 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34785 * performs box-model adjustments.
34786 * @return {Object} The size as an object {width: (the width), height: (the height)}
34788 getViewSize : function()
34791 if(this.el.dom != document.body){
34792 size = this.el.getSize();
34794 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34796 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34797 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34802 * Returns the Element this layout is bound to.
34803 * @return {Roo.Element}
34805 getEl : function(){
34810 * Returns the specified region.
34811 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34812 * @return {Roo.LayoutRegion}
34814 getRegion : function(target){
34815 return this.regions[target.toLowerCase()];
34818 onWindowResize : function(){
34819 if(this.monitorWindowResize){
34826 * Ext JS Library 1.1.1
34827 * Copyright(c) 2006-2007, Ext JS, LLC.
34829 * Originally Released Under LGPL - original licence link has changed is not relivant.
34832 * <script type="text/javascript">
34835 * @class Roo.bootstrap.layout.Border
34836 * @extends Roo.bootstrap.layout.Manager
34837 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34838 * please see: examples/bootstrap/nested.html<br><br>
34840 <b>The container the layout is rendered into can be either the body element or any other element.
34841 If it is not the body element, the container needs to either be an absolute positioned element,
34842 or you will need to add "position:relative" to the css of the container. You will also need to specify
34843 the container size if it is not the body element.</b>
34846 * Create a new Border
34847 * @param {Object} config Configuration options
34849 Roo.bootstrap.layout.Border = function(config){
34850 config = config || {};
34851 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34855 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34856 if(config[region]){
34857 config[region].region = region;
34858 this.addRegion(config[region]);
34864 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34866 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34868 * Creates and adds a new region if it doesn't already exist.
34869 * @param {String} target The target region key (north, south, east, west or center).
34870 * @param {Object} config The regions config object
34871 * @return {BorderLayoutRegion} The new region
34873 addRegion : function(config)
34875 if(!this.regions[config.region]){
34876 var r = this.factory(config);
34877 this.bindRegion(r);
34879 return this.regions[config.region];
34883 bindRegion : function(r){
34884 this.regions[r.config.region] = r;
34886 r.on("visibilitychange", this.layout, this);
34887 r.on("paneladded", this.layout, this);
34888 r.on("panelremoved", this.layout, this);
34889 r.on("invalidated", this.layout, this);
34890 r.on("resized", this.onRegionResized, this);
34891 r.on("collapsed", this.onRegionCollapsed, this);
34892 r.on("expanded", this.onRegionExpanded, this);
34896 * Performs a layout update.
34898 layout : function()
34900 if(this.updating) {
34904 // render all the rebions if they have not been done alreayd?
34905 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34906 if(this.regions[region] && !this.regions[region].bodyEl){
34907 this.regions[region].onRender(this.el)
34911 var size = this.getViewSize();
34912 var w = size.width;
34913 var h = size.height;
34918 //var x = 0, y = 0;
34920 var rs = this.regions;
34921 var north = rs["north"];
34922 var south = rs["south"];
34923 var west = rs["west"];
34924 var east = rs["east"];
34925 var center = rs["center"];
34926 //if(this.hideOnLayout){ // not supported anymore
34927 //c.el.setStyle("display", "none");
34929 if(north && north.isVisible()){
34930 var b = north.getBox();
34931 var m = north.getMargins();
34932 b.width = w - (m.left+m.right);
34935 centerY = b.height + b.y + m.bottom;
34936 centerH -= centerY;
34937 north.updateBox(this.safeBox(b));
34939 if(south && south.isVisible()){
34940 var b = south.getBox();
34941 var m = south.getMargins();
34942 b.width = w - (m.left+m.right);
34944 var totalHeight = (b.height + m.top + m.bottom);
34945 b.y = h - totalHeight + m.top;
34946 centerH -= totalHeight;
34947 south.updateBox(this.safeBox(b));
34949 if(west && west.isVisible()){
34950 var b = west.getBox();
34951 var m = west.getMargins();
34952 b.height = centerH - (m.top+m.bottom);
34954 b.y = centerY + m.top;
34955 var totalWidth = (b.width + m.left + m.right);
34956 centerX += totalWidth;
34957 centerW -= totalWidth;
34958 west.updateBox(this.safeBox(b));
34960 if(east && east.isVisible()){
34961 var b = east.getBox();
34962 var m = east.getMargins();
34963 b.height = centerH - (m.top+m.bottom);
34964 var totalWidth = (b.width + m.left + m.right);
34965 b.x = w - totalWidth + m.left;
34966 b.y = centerY + m.top;
34967 centerW -= totalWidth;
34968 east.updateBox(this.safeBox(b));
34971 var m = center.getMargins();
34973 x: centerX + m.left,
34974 y: centerY + m.top,
34975 width: centerW - (m.left+m.right),
34976 height: centerH - (m.top+m.bottom)
34978 //if(this.hideOnLayout){
34979 //center.el.setStyle("display", "block");
34981 center.updateBox(this.safeBox(centerBox));
34984 this.fireEvent("layout", this);
34988 safeBox : function(box){
34989 box.width = Math.max(0, box.width);
34990 box.height = Math.max(0, box.height);
34995 * Adds a ContentPanel (or subclass) to this layout.
34996 * @param {String} target The target region key (north, south, east, west or center).
34997 * @param {Roo.ContentPanel} panel The panel to add
34998 * @return {Roo.ContentPanel} The added panel
35000 add : function(target, panel){
35002 target = target.toLowerCase();
35003 return this.regions[target].add(panel);
35007 * Remove a ContentPanel (or subclass) to this layout.
35008 * @param {String} target The target region key (north, south, east, west or center).
35009 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35010 * @return {Roo.ContentPanel} The removed panel
35012 remove : function(target, panel){
35013 target = target.toLowerCase();
35014 return this.regions[target].remove(panel);
35018 * Searches all regions for a panel with the specified id
35019 * @param {String} panelId
35020 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35022 findPanel : function(panelId){
35023 var rs = this.regions;
35024 for(var target in rs){
35025 if(typeof rs[target] != "function"){
35026 var p = rs[target].getPanel(panelId);
35036 * Searches all regions for a panel with the specified id and activates (shows) it.
35037 * @param {String/ContentPanel} panelId The panels id or the panel itself
35038 * @return {Roo.ContentPanel} The shown panel or null
35040 showPanel : function(panelId) {
35041 var rs = this.regions;
35042 for(var target in rs){
35043 var r = rs[target];
35044 if(typeof r != "function"){
35045 if(r.hasPanel(panelId)){
35046 return r.showPanel(panelId);
35054 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35055 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35058 restoreState : function(provider){
35060 provider = Roo.state.Manager;
35062 var sm = new Roo.LayoutStateManager();
35063 sm.init(this, provider);
35069 * Adds a xtype elements to the layout.
35073 xtype : 'ContentPanel',
35080 xtype : 'NestedLayoutPanel',
35086 items : [ ... list of content panels or nested layout panels.. ]
35090 * @param {Object} cfg Xtype definition of item to add.
35092 addxtype : function(cfg)
35094 // basically accepts a pannel...
35095 // can accept a layout region..!?!?
35096 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35099 // theory? children can only be panels??
35101 //if (!cfg.xtype.match(/Panel$/)) {
35106 if (typeof(cfg.region) == 'undefined') {
35107 Roo.log("Failed to add Panel, region was not set");
35111 var region = cfg.region;
35117 xitems = cfg.items;
35124 case 'Content': // ContentPanel (el, cfg)
35125 case 'Scroll': // ContentPanel (el, cfg)
35127 cfg.autoCreate = true;
35128 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35130 // var el = this.el.createChild();
35131 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35134 this.add(region, ret);
35138 case 'TreePanel': // our new panel!
35139 cfg.el = this.el.createChild();
35140 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35141 this.add(region, ret);
35146 // create a new Layout (which is a Border Layout...
35148 var clayout = cfg.layout;
35149 clayout.el = this.el.createChild();
35150 clayout.items = clayout.items || [];
35154 // replace this exitems with the clayout ones..
35155 xitems = clayout.items;
35157 // force background off if it's in center...
35158 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35159 cfg.background = false;
35161 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35164 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35165 //console.log('adding nested layout panel ' + cfg.toSource());
35166 this.add(region, ret);
35167 nb = {}; /// find first...
35172 // needs grid and region
35174 //var el = this.getRegion(region).el.createChild();
35176 *var el = this.el.createChild();
35177 // create the grid first...
35178 cfg.grid.container = el;
35179 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35182 if (region == 'center' && this.active ) {
35183 cfg.background = false;
35186 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35188 this.add(region, ret);
35190 if (cfg.background) {
35191 // render grid on panel activation (if panel background)
35192 ret.on('activate', function(gp) {
35193 if (!gp.grid.rendered) {
35194 // gp.grid.render(el);
35198 // cfg.grid.render(el);
35204 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35205 // it was the old xcomponent building that caused this before.
35206 // espeically if border is the top element in the tree.
35216 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35218 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35219 this.add(region, ret);
35223 throw "Can not add '" + cfg.xtype + "' to Border";
35229 this.beginUpdate();
35233 Roo.each(xitems, function(i) {
35234 region = nb && i.region ? i.region : false;
35236 var add = ret.addxtype(i);
35239 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35240 if (!i.background) {
35241 abn[region] = nb[region] ;
35248 // make the last non-background panel active..
35249 //if (nb) { Roo.log(abn); }
35252 for(var r in abn) {
35253 region = this.getRegion(r);
35255 // tried using nb[r], but it does not work..
35257 region.showPanel(abn[r]);
35268 factory : function(cfg)
35271 var validRegions = Roo.bootstrap.layout.Border.regions;
35273 var target = cfg.region;
35276 var r = Roo.bootstrap.layout;
35280 return new r.North(cfg);
35282 return new r.South(cfg);
35284 return new r.East(cfg);
35286 return new r.West(cfg);
35288 return new r.Center(cfg);
35290 throw 'Layout region "'+target+'" not supported.';
35297 * Ext JS Library 1.1.1
35298 * Copyright(c) 2006-2007, Ext JS, LLC.
35300 * Originally Released Under LGPL - original licence link has changed is not relivant.
35303 * <script type="text/javascript">
35307 * @class Roo.bootstrap.layout.Basic
35308 * @extends Roo.util.Observable
35309 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35310 * and does not have a titlebar, tabs or any other features. All it does is size and position
35311 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35312 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35313 * @cfg {string} region the region that it inhabits..
35314 * @cfg {bool} skipConfig skip config?
35318 Roo.bootstrap.layout.Basic = function(config){
35320 this.mgr = config.mgr;
35322 this.position = config.region;
35324 var skipConfig = config.skipConfig;
35328 * @scope Roo.BasicLayoutRegion
35332 * @event beforeremove
35333 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35334 * @param {Roo.LayoutRegion} this
35335 * @param {Roo.ContentPanel} panel The panel
35336 * @param {Object} e The cancel event object
35338 "beforeremove" : true,
35340 * @event invalidated
35341 * Fires when the layout for this region is changed.
35342 * @param {Roo.LayoutRegion} this
35344 "invalidated" : true,
35346 * @event visibilitychange
35347 * Fires when this region is shown or hidden
35348 * @param {Roo.LayoutRegion} this
35349 * @param {Boolean} visibility true or false
35351 "visibilitychange" : true,
35353 * @event paneladded
35354 * Fires when a panel is added.
35355 * @param {Roo.LayoutRegion} this
35356 * @param {Roo.ContentPanel} panel The panel
35358 "paneladded" : true,
35360 * @event panelremoved
35361 * Fires when a panel is removed.
35362 * @param {Roo.LayoutRegion} this
35363 * @param {Roo.ContentPanel} panel The panel
35365 "panelremoved" : true,
35367 * @event beforecollapse
35368 * Fires when this region before collapse.
35369 * @param {Roo.LayoutRegion} this
35371 "beforecollapse" : true,
35374 * Fires when this region is collapsed.
35375 * @param {Roo.LayoutRegion} this
35377 "collapsed" : true,
35380 * Fires when this region is expanded.
35381 * @param {Roo.LayoutRegion} this
35386 * Fires when this region is slid into view.
35387 * @param {Roo.LayoutRegion} this
35389 "slideshow" : true,
35392 * Fires when this region slides out of view.
35393 * @param {Roo.LayoutRegion} this
35395 "slidehide" : true,
35397 * @event panelactivated
35398 * Fires when a panel is activated.
35399 * @param {Roo.LayoutRegion} this
35400 * @param {Roo.ContentPanel} panel The activated panel
35402 "panelactivated" : true,
35405 * Fires when the user resizes this region.
35406 * @param {Roo.LayoutRegion} this
35407 * @param {Number} newSize The new size (width for east/west, height for north/south)
35411 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35412 this.panels = new Roo.util.MixedCollection();
35413 this.panels.getKey = this.getPanelId.createDelegate(this);
35415 this.activePanel = null;
35416 // ensure listeners are added...
35418 if (config.listeners || config.events) {
35419 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35420 listeners : config.listeners || {},
35421 events : config.events || {}
35425 if(skipConfig !== true){
35426 this.applyConfig(config);
35430 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35432 getPanelId : function(p){
35436 applyConfig : function(config){
35437 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35438 this.config = config;
35443 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35444 * the width, for horizontal (north, south) the height.
35445 * @param {Number} newSize The new width or height
35447 resizeTo : function(newSize){
35448 var el = this.el ? this.el :
35449 (this.activePanel ? this.activePanel.getEl() : null);
35451 switch(this.position){
35454 el.setWidth(newSize);
35455 this.fireEvent("resized", this, newSize);
35459 el.setHeight(newSize);
35460 this.fireEvent("resized", this, newSize);
35466 getBox : function(){
35467 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35470 getMargins : function(){
35471 return this.margins;
35474 updateBox : function(box){
35476 var el = this.activePanel.getEl();
35477 el.dom.style.left = box.x + "px";
35478 el.dom.style.top = box.y + "px";
35479 this.activePanel.setSize(box.width, box.height);
35483 * Returns the container element for this region.
35484 * @return {Roo.Element}
35486 getEl : function(){
35487 return this.activePanel;
35491 * Returns true if this region is currently visible.
35492 * @return {Boolean}
35494 isVisible : function(){
35495 return this.activePanel ? true : false;
35498 setActivePanel : function(panel){
35499 panel = this.getPanel(panel);
35500 if(this.activePanel && this.activePanel != panel){
35501 this.activePanel.setActiveState(false);
35502 this.activePanel.getEl().setLeftTop(-10000,-10000);
35504 this.activePanel = panel;
35505 panel.setActiveState(true);
35507 panel.setSize(this.box.width, this.box.height);
35509 this.fireEvent("panelactivated", this, panel);
35510 this.fireEvent("invalidated");
35514 * Show the specified panel.
35515 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35516 * @return {Roo.ContentPanel} The shown panel or null
35518 showPanel : function(panel){
35519 panel = this.getPanel(panel);
35521 this.setActivePanel(panel);
35527 * Get the active panel for this region.
35528 * @return {Roo.ContentPanel} The active panel or null
35530 getActivePanel : function(){
35531 return this.activePanel;
35535 * Add the passed ContentPanel(s)
35536 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35537 * @return {Roo.ContentPanel} The panel added (if only one was added)
35539 add : function(panel){
35540 if(arguments.length > 1){
35541 for(var i = 0, len = arguments.length; i < len; i++) {
35542 this.add(arguments[i]);
35546 if(this.hasPanel(panel)){
35547 this.showPanel(panel);
35550 var el = panel.getEl();
35551 if(el.dom.parentNode != this.mgr.el.dom){
35552 this.mgr.el.dom.appendChild(el.dom);
35554 if(panel.setRegion){
35555 panel.setRegion(this);
35557 this.panels.add(panel);
35558 el.setStyle("position", "absolute");
35559 if(!panel.background){
35560 this.setActivePanel(panel);
35561 if(this.config.initialSize && this.panels.getCount()==1){
35562 this.resizeTo(this.config.initialSize);
35565 this.fireEvent("paneladded", this, panel);
35570 * Returns true if the panel is in this region.
35571 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35572 * @return {Boolean}
35574 hasPanel : function(panel){
35575 if(typeof panel == "object"){ // must be panel obj
35576 panel = panel.getId();
35578 return this.getPanel(panel) ? true : false;
35582 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35583 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35584 * @param {Boolean} preservePanel Overrides the config preservePanel option
35585 * @return {Roo.ContentPanel} The panel that was removed
35587 remove : function(panel, preservePanel){
35588 panel = this.getPanel(panel);
35593 this.fireEvent("beforeremove", this, panel, e);
35594 if(e.cancel === true){
35597 var panelId = panel.getId();
35598 this.panels.removeKey(panelId);
35603 * Returns the panel specified or null if it's not in this region.
35604 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35605 * @return {Roo.ContentPanel}
35607 getPanel : function(id){
35608 if(typeof id == "object"){ // must be panel obj
35611 return this.panels.get(id);
35615 * Returns this regions position (north/south/east/west/center).
35618 getPosition: function(){
35619 return this.position;
35623 * Ext JS Library 1.1.1
35624 * Copyright(c) 2006-2007, Ext JS, LLC.
35626 * Originally Released Under LGPL - original licence link has changed is not relivant.
35629 * <script type="text/javascript">
35633 * @class Roo.bootstrap.layout.Region
35634 * @extends Roo.bootstrap.layout.Basic
35635 * This class represents a region in a layout manager.
35637 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35638 * @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})
35639 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35640 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35641 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35642 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35643 * @cfg {String} title The title for the region (overrides panel titles)
35644 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35645 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35646 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35647 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35648 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35649 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35650 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35651 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35652 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35653 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35655 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35656 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35657 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35658 * @cfg {Number} width For East/West panels
35659 * @cfg {Number} height For North/South panels
35660 * @cfg {Boolean} split To show the splitter
35661 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35663 * @cfg {string} cls Extra CSS classes to add to region
35665 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35666 * @cfg {string} region the region that it inhabits..
35669 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35670 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35672 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35673 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35674 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35676 Roo.bootstrap.layout.Region = function(config)
35678 this.applyConfig(config);
35680 var mgr = config.mgr;
35681 var pos = config.region;
35682 config.skipConfig = true;
35683 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35686 this.onRender(mgr.el);
35689 this.visible = true;
35690 this.collapsed = false;
35691 this.unrendered_panels = [];
35694 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35696 position: '', // set by wrapper (eg. north/south etc..)
35697 unrendered_panels : null, // unrendered panels.
35698 createBody : function(){
35699 /** This region's body element
35700 * @type Roo.Element */
35701 this.bodyEl = this.el.createChild({
35703 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35707 onRender: function(ctr, pos)
35709 var dh = Roo.DomHelper;
35710 /** This region's container element
35711 * @type Roo.Element */
35712 this.el = dh.append(ctr.dom, {
35714 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35716 /** This region's title element
35717 * @type Roo.Element */
35719 this.titleEl = dh.append(this.el.dom,
35722 unselectable: "on",
35723 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35725 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35726 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35729 this.titleEl.enableDisplayMode();
35730 /** This region's title text element
35731 * @type HTMLElement */
35732 this.titleTextEl = this.titleEl.dom.firstChild;
35733 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35735 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35736 this.closeBtn.enableDisplayMode();
35737 this.closeBtn.on("click", this.closeClicked, this);
35738 this.closeBtn.hide();
35740 this.createBody(this.config);
35741 if(this.config.hideWhenEmpty){
35743 this.on("paneladded", this.validateVisibility, this);
35744 this.on("panelremoved", this.validateVisibility, this);
35746 if(this.autoScroll){
35747 this.bodyEl.setStyle("overflow", "auto");
35749 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35751 //if(c.titlebar !== false){
35752 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35753 this.titleEl.hide();
35755 this.titleEl.show();
35756 if(this.config.title){
35757 this.titleTextEl.innerHTML = this.config.title;
35761 if(this.config.collapsed){
35762 this.collapse(true);
35764 if(this.config.hidden){
35768 if (this.unrendered_panels && this.unrendered_panels.length) {
35769 for (var i =0;i< this.unrendered_panels.length; i++) {
35770 this.add(this.unrendered_panels[i]);
35772 this.unrendered_panels = null;
35778 applyConfig : function(c)
35781 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35782 var dh = Roo.DomHelper;
35783 if(c.titlebar !== false){
35784 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35785 this.collapseBtn.on("click", this.collapse, this);
35786 this.collapseBtn.enableDisplayMode();
35788 if(c.showPin === true || this.showPin){
35789 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35790 this.stickBtn.enableDisplayMode();
35791 this.stickBtn.on("click", this.expand, this);
35792 this.stickBtn.hide();
35797 /** This region's collapsed element
35798 * @type Roo.Element */
35801 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35802 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35805 if(c.floatable !== false){
35806 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35807 this.collapsedEl.on("click", this.collapseClick, this);
35810 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35811 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35812 id: "message", unselectable: "on", style:{"float":"left"}});
35813 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35815 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35816 this.expandBtn.on("click", this.expand, this);
35820 if(this.collapseBtn){
35821 this.collapseBtn.setVisible(c.collapsible == true);
35824 this.cmargins = c.cmargins || this.cmargins ||
35825 (this.position == "west" || this.position == "east" ?
35826 {top: 0, left: 2, right:2, bottom: 0} :
35827 {top: 2, left: 0, right:0, bottom: 2});
35829 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35832 this.bottomTabs = c.tabPosition != "top";
35834 this.autoScroll = c.autoScroll || false;
35839 this.duration = c.duration || .30;
35840 this.slideDuration = c.slideDuration || .45;
35845 * Returns true if this region is currently visible.
35846 * @return {Boolean}
35848 isVisible : function(){
35849 return this.visible;
35853 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35854 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35856 //setCollapsedTitle : function(title){
35857 // title = title || " ";
35858 // if(this.collapsedTitleTextEl){
35859 // this.collapsedTitleTextEl.innerHTML = title;
35863 getBox : function(){
35865 // if(!this.collapsed){
35866 b = this.el.getBox(false, true);
35868 // b = this.collapsedEl.getBox(false, true);
35873 getMargins : function(){
35874 return this.margins;
35875 //return this.collapsed ? this.cmargins : this.margins;
35878 highlight : function(){
35879 this.el.addClass("x-layout-panel-dragover");
35882 unhighlight : function(){
35883 this.el.removeClass("x-layout-panel-dragover");
35886 updateBox : function(box)
35888 if (!this.bodyEl) {
35889 return; // not rendered yet..
35893 if(!this.collapsed){
35894 this.el.dom.style.left = box.x + "px";
35895 this.el.dom.style.top = box.y + "px";
35896 this.updateBody(box.width, box.height);
35898 this.collapsedEl.dom.style.left = box.x + "px";
35899 this.collapsedEl.dom.style.top = box.y + "px";
35900 this.collapsedEl.setSize(box.width, box.height);
35903 this.tabs.autoSizeTabs();
35907 updateBody : function(w, h)
35910 this.el.setWidth(w);
35911 w -= this.el.getBorderWidth("rl");
35912 if(this.config.adjustments){
35913 w += this.config.adjustments[0];
35916 if(h !== null && h > 0){
35917 this.el.setHeight(h);
35918 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35919 h -= this.el.getBorderWidth("tb");
35920 if(this.config.adjustments){
35921 h += this.config.adjustments[1];
35923 this.bodyEl.setHeight(h);
35925 h = this.tabs.syncHeight(h);
35928 if(this.panelSize){
35929 w = w !== null ? w : this.panelSize.width;
35930 h = h !== null ? h : this.panelSize.height;
35932 if(this.activePanel){
35933 var el = this.activePanel.getEl();
35934 w = w !== null ? w : el.getWidth();
35935 h = h !== null ? h : el.getHeight();
35936 this.panelSize = {width: w, height: h};
35937 this.activePanel.setSize(w, h);
35939 if(Roo.isIE && this.tabs){
35940 this.tabs.el.repaint();
35945 * Returns the container element for this region.
35946 * @return {Roo.Element}
35948 getEl : function(){
35953 * Hides this region.
35956 //if(!this.collapsed){
35957 this.el.dom.style.left = "-2000px";
35960 // this.collapsedEl.dom.style.left = "-2000px";
35961 // this.collapsedEl.hide();
35963 this.visible = false;
35964 this.fireEvent("visibilitychange", this, false);
35968 * Shows this region if it was previously hidden.
35971 //if(!this.collapsed){
35974 // this.collapsedEl.show();
35976 this.visible = true;
35977 this.fireEvent("visibilitychange", this, true);
35980 closeClicked : function(){
35981 if(this.activePanel){
35982 this.remove(this.activePanel);
35986 collapseClick : function(e){
35988 e.stopPropagation();
35991 e.stopPropagation();
35997 * Collapses this region.
35998 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36001 collapse : function(skipAnim, skipCheck = false){
36002 if(this.collapsed) {
36006 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36008 this.collapsed = true;
36010 this.split.el.hide();
36012 if(this.config.animate && skipAnim !== true){
36013 this.fireEvent("invalidated", this);
36014 this.animateCollapse();
36016 this.el.setLocation(-20000,-20000);
36018 this.collapsedEl.show();
36019 this.fireEvent("collapsed", this);
36020 this.fireEvent("invalidated", this);
36026 animateCollapse : function(){
36031 * Expands this region if it was previously collapsed.
36032 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36033 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36036 expand : function(e, skipAnim){
36038 e.stopPropagation();
36040 if(!this.collapsed || this.el.hasActiveFx()) {
36044 this.afterSlideIn();
36047 this.collapsed = false;
36048 if(this.config.animate && skipAnim !== true){
36049 this.animateExpand();
36053 this.split.el.show();
36055 this.collapsedEl.setLocation(-2000,-2000);
36056 this.collapsedEl.hide();
36057 this.fireEvent("invalidated", this);
36058 this.fireEvent("expanded", this);
36062 animateExpand : function(){
36066 initTabs : function()
36068 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36070 var ts = new Roo.bootstrap.panel.Tabs({
36071 el: this.bodyEl.dom,
36072 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36073 disableTooltips: this.config.disableTabTips,
36074 toolbar : this.config.toolbar
36077 if(this.config.hideTabs){
36078 ts.stripWrap.setDisplayed(false);
36081 ts.resizeTabs = this.config.resizeTabs === true;
36082 ts.minTabWidth = this.config.minTabWidth || 40;
36083 ts.maxTabWidth = this.config.maxTabWidth || 250;
36084 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36085 ts.monitorResize = false;
36086 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36087 ts.bodyEl.addClass('roo-layout-tabs-body');
36088 this.panels.each(this.initPanelAsTab, this);
36091 initPanelAsTab : function(panel){
36092 var ti = this.tabs.addTab(
36096 this.config.closeOnTab && panel.isClosable(),
36099 if(panel.tabTip !== undefined){
36100 ti.setTooltip(panel.tabTip);
36102 ti.on("activate", function(){
36103 this.setActivePanel(panel);
36106 if(this.config.closeOnTab){
36107 ti.on("beforeclose", function(t, e){
36109 this.remove(panel);
36113 panel.tabItem = ti;
36118 updatePanelTitle : function(panel, title)
36120 if(this.activePanel == panel){
36121 this.updateTitle(title);
36124 var ti = this.tabs.getTab(panel.getEl().id);
36126 if(panel.tabTip !== undefined){
36127 ti.setTooltip(panel.tabTip);
36132 updateTitle : function(title){
36133 if(this.titleTextEl && !this.config.title){
36134 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36138 setActivePanel : function(panel)
36140 panel = this.getPanel(panel);
36141 if(this.activePanel && this.activePanel != panel){
36142 if(this.activePanel.setActiveState(false) === false){
36146 this.activePanel = panel;
36147 panel.setActiveState(true);
36148 if(this.panelSize){
36149 panel.setSize(this.panelSize.width, this.panelSize.height);
36152 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36154 this.updateTitle(panel.getTitle());
36156 this.fireEvent("invalidated", this);
36158 this.fireEvent("panelactivated", this, panel);
36162 * Shows the specified panel.
36163 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36164 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36166 showPanel : function(panel)
36168 panel = this.getPanel(panel);
36171 var tab = this.tabs.getTab(panel.getEl().id);
36172 if(tab.isHidden()){
36173 this.tabs.unhideTab(tab.id);
36177 this.setActivePanel(panel);
36184 * Get the active panel for this region.
36185 * @return {Roo.ContentPanel} The active panel or null
36187 getActivePanel : function(){
36188 return this.activePanel;
36191 validateVisibility : function(){
36192 if(this.panels.getCount() < 1){
36193 this.updateTitle(" ");
36194 this.closeBtn.hide();
36197 if(!this.isVisible()){
36204 * Adds the passed ContentPanel(s) to this region.
36205 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36206 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36208 add : function(panel)
36210 if(arguments.length > 1){
36211 for(var i = 0, len = arguments.length; i < len; i++) {
36212 this.add(arguments[i]);
36217 // if we have not been rendered yet, then we can not really do much of this..
36218 if (!this.bodyEl) {
36219 this.unrendered_panels.push(panel);
36226 if(this.hasPanel(panel)){
36227 this.showPanel(panel);
36230 panel.setRegion(this);
36231 this.panels.add(panel);
36232 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36233 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36234 // and hide them... ???
36235 this.bodyEl.dom.appendChild(panel.getEl().dom);
36236 if(panel.background !== true){
36237 this.setActivePanel(panel);
36239 this.fireEvent("paneladded", this, panel);
36246 this.initPanelAsTab(panel);
36250 if(panel.background !== true){
36251 this.tabs.activate(panel.getEl().id);
36253 this.fireEvent("paneladded", this, panel);
36258 * Hides the tab for the specified panel.
36259 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36261 hidePanel : function(panel){
36262 if(this.tabs && (panel = this.getPanel(panel))){
36263 this.tabs.hideTab(panel.getEl().id);
36268 * Unhides the tab for a previously hidden panel.
36269 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36271 unhidePanel : function(panel){
36272 if(this.tabs && (panel = this.getPanel(panel))){
36273 this.tabs.unhideTab(panel.getEl().id);
36277 clearPanels : function(){
36278 while(this.panels.getCount() > 0){
36279 this.remove(this.panels.first());
36284 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36285 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36286 * @param {Boolean} preservePanel Overrides the config preservePanel option
36287 * @return {Roo.ContentPanel} The panel that was removed
36289 remove : function(panel, preservePanel)
36291 panel = this.getPanel(panel);
36296 this.fireEvent("beforeremove", this, panel, e);
36297 if(e.cancel === true){
36300 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36301 var panelId = panel.getId();
36302 this.panels.removeKey(panelId);
36304 document.body.appendChild(panel.getEl().dom);
36307 this.tabs.removeTab(panel.getEl().id);
36308 }else if (!preservePanel){
36309 this.bodyEl.dom.removeChild(panel.getEl().dom);
36311 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36312 var p = this.panels.first();
36313 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36314 tempEl.appendChild(p.getEl().dom);
36315 this.bodyEl.update("");
36316 this.bodyEl.dom.appendChild(p.getEl().dom);
36318 this.updateTitle(p.getTitle());
36320 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36321 this.setActivePanel(p);
36323 panel.setRegion(null);
36324 if(this.activePanel == panel){
36325 this.activePanel = null;
36327 if(this.config.autoDestroy !== false && preservePanel !== true){
36328 try{panel.destroy();}catch(e){}
36330 this.fireEvent("panelremoved", this, panel);
36335 * Returns the TabPanel component used by this region
36336 * @return {Roo.TabPanel}
36338 getTabs : function(){
36342 createTool : function(parentEl, className){
36343 var btn = Roo.DomHelper.append(parentEl, {
36345 cls: "x-layout-tools-button",
36348 cls: "roo-layout-tools-button-inner " + className,
36352 btn.addClassOnOver("roo-layout-tools-button-over");
36357 * Ext JS Library 1.1.1
36358 * Copyright(c) 2006-2007, Ext JS, LLC.
36360 * Originally Released Under LGPL - original licence link has changed is not relivant.
36363 * <script type="text/javascript">
36369 * @class Roo.SplitLayoutRegion
36370 * @extends Roo.LayoutRegion
36371 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36373 Roo.bootstrap.layout.Split = function(config){
36374 this.cursor = config.cursor;
36375 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36378 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36380 splitTip : "Drag to resize.",
36381 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36382 useSplitTips : false,
36384 applyConfig : function(config){
36385 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36388 onRender : function(ctr,pos) {
36390 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36391 if(!this.config.split){
36396 var splitEl = Roo.DomHelper.append(ctr.dom, {
36398 id: this.el.id + "-split",
36399 cls: "roo-layout-split roo-layout-split-"+this.position,
36402 /** The SplitBar for this region
36403 * @type Roo.SplitBar */
36404 // does not exist yet...
36405 Roo.log([this.position, this.orientation]);
36407 this.split = new Roo.bootstrap.SplitBar({
36408 dragElement : splitEl,
36409 resizingElement: this.el,
36410 orientation : this.orientation
36413 this.split.on("moved", this.onSplitMove, this);
36414 this.split.useShim = this.config.useShim === true;
36415 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36416 if(this.useSplitTips){
36417 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36419 //if(config.collapsible){
36420 // this.split.el.on("dblclick", this.collapse, this);
36423 if(typeof this.config.minSize != "undefined"){
36424 this.split.minSize = this.config.minSize;
36426 if(typeof this.config.maxSize != "undefined"){
36427 this.split.maxSize = this.config.maxSize;
36429 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36430 this.hideSplitter();
36435 getHMaxSize : function(){
36436 var cmax = this.config.maxSize || 10000;
36437 var center = this.mgr.getRegion("center");
36438 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36441 getVMaxSize : function(){
36442 var cmax = this.config.maxSize || 10000;
36443 var center = this.mgr.getRegion("center");
36444 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36447 onSplitMove : function(split, newSize){
36448 this.fireEvent("resized", this, newSize);
36452 * Returns the {@link Roo.SplitBar} for this region.
36453 * @return {Roo.SplitBar}
36455 getSplitBar : function(){
36460 this.hideSplitter();
36461 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36464 hideSplitter : function(){
36466 this.split.el.setLocation(-2000,-2000);
36467 this.split.el.hide();
36473 this.split.el.show();
36475 Roo.bootstrap.layout.Split.superclass.show.call(this);
36478 beforeSlide: function(){
36479 if(Roo.isGecko){// firefox overflow auto bug workaround
36480 this.bodyEl.clip();
36482 this.tabs.bodyEl.clip();
36484 if(this.activePanel){
36485 this.activePanel.getEl().clip();
36487 if(this.activePanel.beforeSlide){
36488 this.activePanel.beforeSlide();
36494 afterSlide : function(){
36495 if(Roo.isGecko){// firefox overflow auto bug workaround
36496 this.bodyEl.unclip();
36498 this.tabs.bodyEl.unclip();
36500 if(this.activePanel){
36501 this.activePanel.getEl().unclip();
36502 if(this.activePanel.afterSlide){
36503 this.activePanel.afterSlide();
36509 initAutoHide : function(){
36510 if(this.autoHide !== false){
36511 if(!this.autoHideHd){
36512 var st = new Roo.util.DelayedTask(this.slideIn, this);
36513 this.autoHideHd = {
36514 "mouseout": function(e){
36515 if(!e.within(this.el, true)){
36519 "mouseover" : function(e){
36525 this.el.on(this.autoHideHd);
36529 clearAutoHide : function(){
36530 if(this.autoHide !== false){
36531 this.el.un("mouseout", this.autoHideHd.mouseout);
36532 this.el.un("mouseover", this.autoHideHd.mouseover);
36536 clearMonitor : function(){
36537 Roo.get(document).un("click", this.slideInIf, this);
36540 // these names are backwards but not changed for compat
36541 slideOut : function(){
36542 if(this.isSlid || this.el.hasActiveFx()){
36545 this.isSlid = true;
36546 if(this.collapseBtn){
36547 this.collapseBtn.hide();
36549 this.closeBtnState = this.closeBtn.getStyle('display');
36550 this.closeBtn.hide();
36552 this.stickBtn.show();
36555 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36556 this.beforeSlide();
36557 this.el.setStyle("z-index", 10001);
36558 this.el.slideIn(this.getSlideAnchor(), {
36559 callback: function(){
36561 this.initAutoHide();
36562 Roo.get(document).on("click", this.slideInIf, this);
36563 this.fireEvent("slideshow", this);
36570 afterSlideIn : function(){
36571 this.clearAutoHide();
36572 this.isSlid = false;
36573 this.clearMonitor();
36574 this.el.setStyle("z-index", "");
36575 if(this.collapseBtn){
36576 this.collapseBtn.show();
36578 this.closeBtn.setStyle('display', this.closeBtnState);
36580 this.stickBtn.hide();
36582 this.fireEvent("slidehide", this);
36585 slideIn : function(cb){
36586 if(!this.isSlid || this.el.hasActiveFx()){
36590 this.isSlid = false;
36591 this.beforeSlide();
36592 this.el.slideOut(this.getSlideAnchor(), {
36593 callback: function(){
36594 this.el.setLeftTop(-10000, -10000);
36596 this.afterSlideIn();
36604 slideInIf : function(e){
36605 if(!e.within(this.el)){
36610 animateCollapse : function(){
36611 this.beforeSlide();
36612 this.el.setStyle("z-index", 20000);
36613 var anchor = this.getSlideAnchor();
36614 this.el.slideOut(anchor, {
36615 callback : function(){
36616 this.el.setStyle("z-index", "");
36617 this.collapsedEl.slideIn(anchor, {duration:.3});
36619 this.el.setLocation(-10000,-10000);
36621 this.fireEvent("collapsed", this);
36628 animateExpand : function(){
36629 this.beforeSlide();
36630 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36631 this.el.setStyle("z-index", 20000);
36632 this.collapsedEl.hide({
36635 this.el.slideIn(this.getSlideAnchor(), {
36636 callback : function(){
36637 this.el.setStyle("z-index", "");
36640 this.split.el.show();
36642 this.fireEvent("invalidated", this);
36643 this.fireEvent("expanded", this);
36671 getAnchor : function(){
36672 return this.anchors[this.position];
36675 getCollapseAnchor : function(){
36676 return this.canchors[this.position];
36679 getSlideAnchor : function(){
36680 return this.sanchors[this.position];
36683 getAlignAdj : function(){
36684 var cm = this.cmargins;
36685 switch(this.position){
36701 getExpandAdj : function(){
36702 var c = this.collapsedEl, cm = this.cmargins;
36703 switch(this.position){
36705 return [-(cm.right+c.getWidth()+cm.left), 0];
36708 return [cm.right+c.getWidth()+cm.left, 0];
36711 return [0, -(cm.top+cm.bottom+c.getHeight())];
36714 return [0, cm.top+cm.bottom+c.getHeight()];
36720 * Ext JS Library 1.1.1
36721 * Copyright(c) 2006-2007, Ext JS, LLC.
36723 * Originally Released Under LGPL - original licence link has changed is not relivant.
36726 * <script type="text/javascript">
36729 * These classes are private internal classes
36731 Roo.bootstrap.layout.Center = function(config){
36732 config.region = "center";
36733 Roo.bootstrap.layout.Region.call(this, config);
36734 this.visible = true;
36735 this.minWidth = config.minWidth || 20;
36736 this.minHeight = config.minHeight || 20;
36739 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36741 // center panel can't be hidden
36745 // center panel can't be hidden
36748 getMinWidth: function(){
36749 return this.minWidth;
36752 getMinHeight: function(){
36753 return this.minHeight;
36766 Roo.bootstrap.layout.North = function(config)
36768 config.region = 'north';
36769 config.cursor = 'n-resize';
36771 Roo.bootstrap.layout.Split.call(this, config);
36775 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36776 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36777 this.split.el.addClass("roo-layout-split-v");
36779 var size = config.initialSize || config.height;
36780 if(typeof size != "undefined"){
36781 this.el.setHeight(size);
36784 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36786 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36790 getBox : function(){
36791 if(this.collapsed){
36792 return this.collapsedEl.getBox();
36794 var box = this.el.getBox();
36796 box.height += this.split.el.getHeight();
36801 updateBox : function(box){
36802 if(this.split && !this.collapsed){
36803 box.height -= this.split.el.getHeight();
36804 this.split.el.setLeft(box.x);
36805 this.split.el.setTop(box.y+box.height);
36806 this.split.el.setWidth(box.width);
36808 if(this.collapsed){
36809 this.updateBody(box.width, null);
36811 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36819 Roo.bootstrap.layout.South = function(config){
36820 config.region = 'south';
36821 config.cursor = 's-resize';
36822 Roo.bootstrap.layout.Split.call(this, config);
36824 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36825 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36826 this.split.el.addClass("roo-layout-split-v");
36828 var size = config.initialSize || config.height;
36829 if(typeof size != "undefined"){
36830 this.el.setHeight(size);
36834 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36835 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36836 getBox : function(){
36837 if(this.collapsed){
36838 return this.collapsedEl.getBox();
36840 var box = this.el.getBox();
36842 var sh = this.split.el.getHeight();
36849 updateBox : function(box){
36850 if(this.split && !this.collapsed){
36851 var sh = this.split.el.getHeight();
36854 this.split.el.setLeft(box.x);
36855 this.split.el.setTop(box.y-sh);
36856 this.split.el.setWidth(box.width);
36858 if(this.collapsed){
36859 this.updateBody(box.width, null);
36861 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36865 Roo.bootstrap.layout.East = function(config){
36866 config.region = "east";
36867 config.cursor = "e-resize";
36868 Roo.bootstrap.layout.Split.call(this, config);
36870 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36871 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36872 this.split.el.addClass("roo-layout-split-h");
36874 var size = config.initialSize || config.width;
36875 if(typeof size != "undefined"){
36876 this.el.setWidth(size);
36879 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36880 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36881 getBox : function(){
36882 if(this.collapsed){
36883 return this.collapsedEl.getBox();
36885 var box = this.el.getBox();
36887 var sw = this.split.el.getWidth();
36894 updateBox : function(box){
36895 if(this.split && !this.collapsed){
36896 var sw = this.split.el.getWidth();
36898 this.split.el.setLeft(box.x);
36899 this.split.el.setTop(box.y);
36900 this.split.el.setHeight(box.height);
36903 if(this.collapsed){
36904 this.updateBody(null, box.height);
36906 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36910 Roo.bootstrap.layout.West = function(config){
36911 config.region = "west";
36912 config.cursor = "w-resize";
36914 Roo.bootstrap.layout.Split.call(this, config);
36916 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36917 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36918 this.split.el.addClass("roo-layout-split-h");
36922 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36923 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36925 onRender: function(ctr, pos)
36927 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36928 var size = this.config.initialSize || this.config.width;
36929 if(typeof size != "undefined"){
36930 this.el.setWidth(size);
36934 getBox : function(){
36935 if(this.collapsed){
36936 return this.collapsedEl.getBox();
36938 var box = this.el.getBox();
36940 box.width += this.split.el.getWidth();
36945 updateBox : function(box){
36946 if(this.split && !this.collapsed){
36947 var sw = this.split.el.getWidth();
36949 this.split.el.setLeft(box.x+box.width);
36950 this.split.el.setTop(box.y);
36951 this.split.el.setHeight(box.height);
36953 if(this.collapsed){
36954 this.updateBody(null, box.height);
36956 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36959 Roo.namespace("Roo.bootstrap.panel");/*
36961 * Ext JS Library 1.1.1
36962 * Copyright(c) 2006-2007, Ext JS, LLC.
36964 * Originally Released Under LGPL - original licence link has changed is not relivant.
36967 * <script type="text/javascript">
36970 * @class Roo.ContentPanel
36971 * @extends Roo.util.Observable
36972 * A basic ContentPanel element.
36973 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36974 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36975 * @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
36976 * @cfg {Boolean} closable True if the panel can be closed/removed
36977 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36978 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36979 * @cfg {Toolbar} toolbar A toolbar for this panel
36980 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36981 * @cfg {String} title The title for this panel
36982 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36983 * @cfg {String} url Calls {@link #setUrl} with this value
36984 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36985 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36986 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36987 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36988 * @cfg {Boolean} badges render the badges
36991 * Create a new ContentPanel.
36992 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36993 * @param {String/Object} config A string to set only the title or a config object
36994 * @param {String} content (optional) Set the HTML content for this panel
36995 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36997 Roo.bootstrap.panel.Content = function( config){
36999 this.tpl = config.tpl || false;
37001 var el = config.el;
37002 var content = config.content;
37004 if(config.autoCreate){ // xtype is available if this is called from factory
37007 this.el = Roo.get(el);
37008 if(!this.el && config && config.autoCreate){
37009 if(typeof config.autoCreate == "object"){
37010 if(!config.autoCreate.id){
37011 config.autoCreate.id = config.id||el;
37013 this.el = Roo.DomHelper.append(document.body,
37014 config.autoCreate, true);
37016 var elcfg = { tag: "div",
37017 cls: "roo-layout-inactive-content",
37021 elcfg.html = config.html;
37025 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37028 this.closable = false;
37029 this.loaded = false;
37030 this.active = false;
37033 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37035 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37037 this.wrapEl = this.el; //this.el.wrap();
37039 if (config.toolbar.items) {
37040 ti = config.toolbar.items ;
37041 delete config.toolbar.items ;
37045 this.toolbar.render(this.wrapEl, 'before');
37046 for(var i =0;i < ti.length;i++) {
37047 // Roo.log(['add child', items[i]]);
37048 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37050 this.toolbar.items = nitems;
37051 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37052 delete config.toolbar;
37056 // xtype created footer. - not sure if will work as we normally have to render first..
37057 if (this.footer && !this.footer.el && this.footer.xtype) {
37058 if (!this.wrapEl) {
37059 this.wrapEl = this.el.wrap();
37062 this.footer.container = this.wrapEl.createChild();
37064 this.footer = Roo.factory(this.footer, Roo);
37069 if(typeof config == "string"){
37070 this.title = config;
37072 Roo.apply(this, config);
37076 this.resizeEl = Roo.get(this.resizeEl, true);
37078 this.resizeEl = this.el;
37080 // handle view.xtype
37088 * Fires when this panel is activated.
37089 * @param {Roo.ContentPanel} this
37093 * @event deactivate
37094 * Fires when this panel is activated.
37095 * @param {Roo.ContentPanel} this
37097 "deactivate" : true,
37101 * Fires when this panel is resized if fitToFrame is true.
37102 * @param {Roo.ContentPanel} this
37103 * @param {Number} width The width after any component adjustments
37104 * @param {Number} height The height after any component adjustments
37110 * Fires when this tab is created
37111 * @param {Roo.ContentPanel} this
37122 if(this.autoScroll){
37123 this.resizeEl.setStyle("overflow", "auto");
37125 // fix randome scrolling
37126 //this.el.on('scroll', function() {
37127 // Roo.log('fix random scolling');
37128 // this.scrollTo('top',0);
37131 content = content || this.content;
37133 this.setContent(content);
37135 if(config && config.url){
37136 this.setUrl(this.url, this.params, this.loadOnce);
37141 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37143 if (this.view && typeof(this.view.xtype) != 'undefined') {
37144 this.view.el = this.el.appendChild(document.createElement("div"));
37145 this.view = Roo.factory(this.view);
37146 this.view.render && this.view.render(false, '');
37150 this.fireEvent('render', this);
37153 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37157 setRegion : function(region){
37158 this.region = region;
37159 this.setActiveClass(region && !this.background);
37163 setActiveClass: function(state)
37166 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37167 this.el.setStyle('position','relative');
37169 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37170 this.el.setStyle('position', 'absolute');
37175 * Returns the toolbar for this Panel if one was configured.
37176 * @return {Roo.Toolbar}
37178 getToolbar : function(){
37179 return this.toolbar;
37182 setActiveState : function(active)
37184 this.active = active;
37185 this.setActiveClass(active);
37187 if(this.fireEvent("deactivate", this) === false){
37192 this.fireEvent("activate", this);
37196 * Updates this panel's element
37197 * @param {String} content The new content
37198 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37200 setContent : function(content, loadScripts){
37201 this.el.update(content, loadScripts);
37204 ignoreResize : function(w, h){
37205 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37208 this.lastSize = {width: w, height: h};
37213 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37214 * @return {Roo.UpdateManager} The UpdateManager
37216 getUpdateManager : function(){
37217 return this.el.getUpdateManager();
37220 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37221 * @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:
37224 url: "your-url.php",
37225 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37226 callback: yourFunction,
37227 scope: yourObject, //(optional scope)
37230 text: "Loading...",
37235 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37236 * 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.
37237 * @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}
37238 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37239 * @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.
37240 * @return {Roo.ContentPanel} this
37243 var um = this.el.getUpdateManager();
37244 um.update.apply(um, arguments);
37250 * 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.
37251 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37252 * @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)
37253 * @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)
37254 * @return {Roo.UpdateManager} The UpdateManager
37256 setUrl : function(url, params, loadOnce){
37257 if(this.refreshDelegate){
37258 this.removeListener("activate", this.refreshDelegate);
37260 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37261 this.on("activate", this.refreshDelegate);
37262 return this.el.getUpdateManager();
37265 _handleRefresh : function(url, params, loadOnce){
37266 if(!loadOnce || !this.loaded){
37267 var updater = this.el.getUpdateManager();
37268 updater.update(url, params, this._setLoaded.createDelegate(this));
37272 _setLoaded : function(){
37273 this.loaded = true;
37277 * Returns this panel's id
37280 getId : function(){
37285 * Returns this panel's element - used by regiosn to add.
37286 * @return {Roo.Element}
37288 getEl : function(){
37289 return this.wrapEl || this.el;
37294 adjustForComponents : function(width, height)
37296 //Roo.log('adjustForComponents ');
37297 if(this.resizeEl != this.el){
37298 width -= this.el.getFrameWidth('lr');
37299 height -= this.el.getFrameWidth('tb');
37302 var te = this.toolbar.getEl();
37303 te.setWidth(width);
37304 height -= te.getHeight();
37307 var te = this.footer.getEl();
37308 te.setWidth(width);
37309 height -= te.getHeight();
37313 if(this.adjustments){
37314 width += this.adjustments[0];
37315 height += this.adjustments[1];
37317 return {"width": width, "height": height};
37320 setSize : function(width, height){
37321 if(this.fitToFrame && !this.ignoreResize(width, height)){
37322 if(this.fitContainer && this.resizeEl != this.el){
37323 this.el.setSize(width, height);
37325 var size = this.adjustForComponents(width, height);
37326 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37327 this.fireEvent('resize', this, size.width, size.height);
37332 * Returns this panel's title
37335 getTitle : function(){
37337 if (typeof(this.title) != 'object') {
37342 for (var k in this.title) {
37343 if (!this.title.hasOwnProperty(k)) {
37347 if (k.indexOf('-') >= 0) {
37348 var s = k.split('-');
37349 for (var i = 0; i<s.length; i++) {
37350 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37353 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37360 * Set this panel's title
37361 * @param {String} title
37363 setTitle : function(title){
37364 this.title = title;
37366 this.region.updatePanelTitle(this, title);
37371 * Returns true is this panel was configured to be closable
37372 * @return {Boolean}
37374 isClosable : function(){
37375 return this.closable;
37378 beforeSlide : function(){
37380 this.resizeEl.clip();
37383 afterSlide : function(){
37385 this.resizeEl.unclip();
37389 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37390 * Will fail silently if the {@link #setUrl} method has not been called.
37391 * This does not activate the panel, just updates its content.
37393 refresh : function(){
37394 if(this.refreshDelegate){
37395 this.loaded = false;
37396 this.refreshDelegate();
37401 * Destroys this panel
37403 destroy : function(){
37404 this.el.removeAllListeners();
37405 var tempEl = document.createElement("span");
37406 tempEl.appendChild(this.el.dom);
37407 tempEl.innerHTML = "";
37413 * form - if the content panel contains a form - this is a reference to it.
37414 * @type {Roo.form.Form}
37418 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37419 * This contains a reference to it.
37425 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37435 * @param {Object} cfg Xtype definition of item to add.
37439 getChildContainer: function () {
37440 return this.getEl();
37445 var ret = new Roo.factory(cfg);
37450 if (cfg.xtype.match(/^Form$/)) {
37453 //if (this.footer) {
37454 // el = this.footer.container.insertSibling(false, 'before');
37456 el = this.el.createChild();
37459 this.form = new Roo.form.Form(cfg);
37462 if ( this.form.allItems.length) {
37463 this.form.render(el.dom);
37467 // should only have one of theses..
37468 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37469 // views.. should not be just added - used named prop 'view''
37471 cfg.el = this.el.appendChild(document.createElement("div"));
37474 var ret = new Roo.factory(cfg);
37476 ret.render && ret.render(false, ''); // render blank..
37486 * @class Roo.bootstrap.panel.Grid
37487 * @extends Roo.bootstrap.panel.Content
37489 * Create a new GridPanel.
37490 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37491 * @param {Object} config A the config object
37497 Roo.bootstrap.panel.Grid = function(config)
37501 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37502 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37504 config.el = this.wrapper;
37505 //this.el = this.wrapper;
37507 if (config.container) {
37508 // ctor'ed from a Border/panel.grid
37511 this.wrapper.setStyle("overflow", "hidden");
37512 this.wrapper.addClass('roo-grid-container');
37517 if(config.toolbar){
37518 var tool_el = this.wrapper.createChild();
37519 this.toolbar = Roo.factory(config.toolbar);
37521 if (config.toolbar.items) {
37522 ti = config.toolbar.items ;
37523 delete config.toolbar.items ;
37527 this.toolbar.render(tool_el);
37528 for(var i =0;i < ti.length;i++) {
37529 // Roo.log(['add child', items[i]]);
37530 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37532 this.toolbar.items = nitems;
37534 delete config.toolbar;
37537 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37538 config.grid.scrollBody = true;;
37539 config.grid.monitorWindowResize = false; // turn off autosizing
37540 config.grid.autoHeight = false;
37541 config.grid.autoWidth = false;
37543 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37545 if (config.background) {
37546 // render grid on panel activation (if panel background)
37547 this.on('activate', function(gp) {
37548 if (!gp.grid.rendered) {
37549 gp.grid.render(this.wrapper);
37550 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37555 this.grid.render(this.wrapper);
37556 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37559 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37560 // ??? needed ??? config.el = this.wrapper;
37565 // xtype created footer. - not sure if will work as we normally have to render first..
37566 if (this.footer && !this.footer.el && this.footer.xtype) {
37568 var ctr = this.grid.getView().getFooterPanel(true);
37569 this.footer.dataSource = this.grid.dataSource;
37570 this.footer = Roo.factory(this.footer, Roo);
37571 this.footer.render(ctr);
37581 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37582 getId : function(){
37583 return this.grid.id;
37587 * Returns the grid for this panel
37588 * @return {Roo.bootstrap.Table}
37590 getGrid : function(){
37594 setSize : function(width, height){
37595 if(!this.ignoreResize(width, height)){
37596 var grid = this.grid;
37597 var size = this.adjustForComponents(width, height);
37598 var gridel = grid.getGridEl();
37599 gridel.setSize(size.width, size.height);
37601 var thd = grid.getGridEl().select('thead',true).first();
37602 var tbd = grid.getGridEl().select('tbody', true).first();
37604 tbd.setSize(width, height - thd.getHeight());
37613 beforeSlide : function(){
37614 this.grid.getView().scroller.clip();
37617 afterSlide : function(){
37618 this.grid.getView().scroller.unclip();
37621 destroy : function(){
37622 this.grid.destroy();
37624 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37629 * @class Roo.bootstrap.panel.Nest
37630 * @extends Roo.bootstrap.panel.Content
37632 * Create a new Panel, that can contain a layout.Border.
37635 * @param {Roo.BorderLayout} layout The layout for this panel
37636 * @param {String/Object} config A string to set only the title or a config object
37638 Roo.bootstrap.panel.Nest = function(config)
37640 // construct with only one argument..
37641 /* FIXME - implement nicer consturctors
37642 if (layout.layout) {
37644 layout = config.layout;
37645 delete config.layout;
37647 if (layout.xtype && !layout.getEl) {
37648 // then layout needs constructing..
37649 layout = Roo.factory(layout, Roo);
37653 config.el = config.layout.getEl();
37655 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37657 config.layout.monitorWindowResize = false; // turn off autosizing
37658 this.layout = config.layout;
37659 this.layout.getEl().addClass("roo-layout-nested-layout");
37666 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37668 setSize : function(width, height){
37669 if(!this.ignoreResize(width, height)){
37670 var size = this.adjustForComponents(width, height);
37671 var el = this.layout.getEl();
37672 if (size.height < 1) {
37673 el.setWidth(size.width);
37675 el.setSize(size.width, size.height);
37677 var touch = el.dom.offsetWidth;
37678 this.layout.layout();
37679 // ie requires a double layout on the first pass
37680 if(Roo.isIE && !this.initialized){
37681 this.initialized = true;
37682 this.layout.layout();
37687 // activate all subpanels if not currently active..
37689 setActiveState : function(active){
37690 this.active = active;
37691 this.setActiveClass(active);
37694 this.fireEvent("deactivate", this);
37698 this.fireEvent("activate", this);
37699 // not sure if this should happen before or after..
37700 if (!this.layout) {
37701 return; // should not happen..
37704 for (var r in this.layout.regions) {
37705 reg = this.layout.getRegion(r);
37706 if (reg.getActivePanel()) {
37707 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37708 reg.setActivePanel(reg.getActivePanel());
37711 if (!reg.panels.length) {
37714 reg.showPanel(reg.getPanel(0));
37723 * Returns the nested BorderLayout for this panel
37724 * @return {Roo.BorderLayout}
37726 getLayout : function(){
37727 return this.layout;
37731 * Adds a xtype elements to the layout of the nested panel
37735 xtype : 'ContentPanel',
37742 xtype : 'NestedLayoutPanel',
37748 items : [ ... list of content panels or nested layout panels.. ]
37752 * @param {Object} cfg Xtype definition of item to add.
37754 addxtype : function(cfg) {
37755 return this.layout.addxtype(cfg);
37760 * Ext JS Library 1.1.1
37761 * Copyright(c) 2006-2007, Ext JS, LLC.
37763 * Originally Released Under LGPL - original licence link has changed is not relivant.
37766 * <script type="text/javascript">
37769 * @class Roo.TabPanel
37770 * @extends Roo.util.Observable
37771 * A lightweight tab container.
37775 // basic tabs 1, built from existing content
37776 var tabs = new Roo.TabPanel("tabs1");
37777 tabs.addTab("script", "View Script");
37778 tabs.addTab("markup", "View Markup");
37779 tabs.activate("script");
37781 // more advanced tabs, built from javascript
37782 var jtabs = new Roo.TabPanel("jtabs");
37783 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37785 // set up the UpdateManager
37786 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37787 var updater = tab2.getUpdateManager();
37788 updater.setDefaultUrl("ajax1.htm");
37789 tab2.on('activate', updater.refresh, updater, true);
37791 // Use setUrl for Ajax loading
37792 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37793 tab3.setUrl("ajax2.htm", null, true);
37796 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37799 jtabs.activate("jtabs-1");
37802 * Create a new TabPanel.
37803 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37804 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37806 Roo.bootstrap.panel.Tabs = function(config){
37808 * The container element for this TabPanel.
37809 * @type Roo.Element
37811 this.el = Roo.get(config.el);
37814 if(typeof config == "boolean"){
37815 this.tabPosition = config ? "bottom" : "top";
37817 Roo.apply(this, config);
37821 if(this.tabPosition == "bottom"){
37822 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37823 this.el.addClass("roo-tabs-bottom");
37825 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37826 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37827 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37829 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37831 if(this.tabPosition != "bottom"){
37832 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37833 * @type Roo.Element
37835 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37836 this.el.addClass("roo-tabs-top");
37840 this.bodyEl.setStyle("position", "relative");
37842 this.active = null;
37843 this.activateDelegate = this.activate.createDelegate(this);
37848 * Fires when the active tab changes
37849 * @param {Roo.TabPanel} this
37850 * @param {Roo.TabPanelItem} activePanel The new active tab
37854 * @event beforetabchange
37855 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37856 * @param {Roo.TabPanel} this
37857 * @param {Object} e Set cancel to true on this object to cancel the tab change
37858 * @param {Roo.TabPanelItem} tab The tab being changed to
37860 "beforetabchange" : true
37863 Roo.EventManager.onWindowResize(this.onResize, this);
37864 this.cpad = this.el.getPadding("lr");
37865 this.hiddenCount = 0;
37868 // toolbar on the tabbar support...
37869 if (this.toolbar) {
37870 alert("no toolbar support yet");
37871 this.toolbar = false;
37873 var tcfg = this.toolbar;
37874 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37875 this.toolbar = new Roo.Toolbar(tcfg);
37876 if (Roo.isSafari) {
37877 var tbl = tcfg.container.child('table', true);
37878 tbl.setAttribute('width', '100%');
37886 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37889 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37891 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37893 tabPosition : "top",
37895 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37897 currentTabWidth : 0,
37899 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37903 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37907 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37909 preferredTabWidth : 175,
37911 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37913 resizeTabs : false,
37915 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37917 monitorResize : true,
37919 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37924 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37925 * @param {String} id The id of the div to use <b>or create</b>
37926 * @param {String} text The text for the tab
37927 * @param {String} content (optional) Content to put in the TabPanelItem body
37928 * @param {Boolean} closable (optional) True to create a close icon on the tab
37929 * @return {Roo.TabPanelItem} The created TabPanelItem
37931 addTab : function(id, text, content, closable, tpl)
37933 var item = new Roo.bootstrap.panel.TabItem({
37937 closable : closable,
37940 this.addTabItem(item);
37942 item.setContent(content);
37948 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37949 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37950 * @return {Roo.TabPanelItem}
37952 getTab : function(id){
37953 return this.items[id];
37957 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37958 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37960 hideTab : function(id){
37961 var t = this.items[id];
37964 this.hiddenCount++;
37965 this.autoSizeTabs();
37970 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37971 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37973 unhideTab : function(id){
37974 var t = this.items[id];
37976 t.setHidden(false);
37977 this.hiddenCount--;
37978 this.autoSizeTabs();
37983 * Adds an existing {@link Roo.TabPanelItem}.
37984 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37986 addTabItem : function(item){
37987 this.items[item.id] = item;
37988 this.items.push(item);
37989 // if(this.resizeTabs){
37990 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37991 // this.autoSizeTabs();
37993 // item.autoSize();
37998 * Removes a {@link Roo.TabPanelItem}.
37999 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38001 removeTab : function(id){
38002 var items = this.items;
38003 var tab = items[id];
38004 if(!tab) { return; }
38005 var index = items.indexOf(tab);
38006 if(this.active == tab && items.length > 1){
38007 var newTab = this.getNextAvailable(index);
38012 this.stripEl.dom.removeChild(tab.pnode.dom);
38013 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38014 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38016 items.splice(index, 1);
38017 delete this.items[tab.id];
38018 tab.fireEvent("close", tab);
38019 tab.purgeListeners();
38020 this.autoSizeTabs();
38023 getNextAvailable : function(start){
38024 var items = this.items;
38026 // look for a next tab that will slide over to
38027 // replace the one being removed
38028 while(index < items.length){
38029 var item = items[++index];
38030 if(item && !item.isHidden()){
38034 // if one isn't found select the previous tab (on the left)
38037 var item = items[--index];
38038 if(item && !item.isHidden()){
38046 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38047 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38049 disableTab : function(id){
38050 var tab = this.items[id];
38051 if(tab && this.active != tab){
38057 * Enables a {@link Roo.TabPanelItem} that is disabled.
38058 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38060 enableTab : function(id){
38061 var tab = this.items[id];
38066 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38067 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38068 * @return {Roo.TabPanelItem} The TabPanelItem.
38070 activate : function(id){
38071 var tab = this.items[id];
38075 if(tab == this.active || tab.disabled){
38079 this.fireEvent("beforetabchange", this, e, tab);
38080 if(e.cancel !== true && !tab.disabled){
38082 this.active.hide();
38084 this.active = this.items[id];
38085 this.active.show();
38086 this.fireEvent("tabchange", this, this.active);
38092 * Gets the active {@link Roo.TabPanelItem}.
38093 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38095 getActiveTab : function(){
38096 return this.active;
38100 * Updates the tab body element to fit the height of the container element
38101 * for overflow scrolling
38102 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38104 syncHeight : function(targetHeight){
38105 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38106 var bm = this.bodyEl.getMargins();
38107 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38108 this.bodyEl.setHeight(newHeight);
38112 onResize : function(){
38113 if(this.monitorResize){
38114 this.autoSizeTabs();
38119 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38121 beginUpdate : function(){
38122 this.updating = true;
38126 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38128 endUpdate : function(){
38129 this.updating = false;
38130 this.autoSizeTabs();
38134 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38136 autoSizeTabs : function(){
38137 var count = this.items.length;
38138 var vcount = count - this.hiddenCount;
38139 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38142 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38143 var availWidth = Math.floor(w / vcount);
38144 var b = this.stripBody;
38145 if(b.getWidth() > w){
38146 var tabs = this.items;
38147 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38148 if(availWidth < this.minTabWidth){
38149 /*if(!this.sleft){ // incomplete scrolling code
38150 this.createScrollButtons();
38153 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38156 if(this.currentTabWidth < this.preferredTabWidth){
38157 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38163 * Returns the number of tabs in this TabPanel.
38166 getCount : function(){
38167 return this.items.length;
38171 * Resizes all the tabs to the passed width
38172 * @param {Number} The new width
38174 setTabWidth : function(width){
38175 this.currentTabWidth = width;
38176 for(var i = 0, len = this.items.length; i < len; i++) {
38177 if(!this.items[i].isHidden()) {
38178 this.items[i].setWidth(width);
38184 * Destroys this TabPanel
38185 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38187 destroy : function(removeEl){
38188 Roo.EventManager.removeResizeListener(this.onResize, this);
38189 for(var i = 0, len = this.items.length; i < len; i++){
38190 this.items[i].purgeListeners();
38192 if(removeEl === true){
38193 this.el.update("");
38198 createStrip : function(container)
38200 var strip = document.createElement("nav");
38201 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38202 container.appendChild(strip);
38206 createStripList : function(strip)
38208 // div wrapper for retard IE
38209 // returns the "tr" element.
38210 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38211 //'<div class="x-tabs-strip-wrap">'+
38212 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38213 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38214 return strip.firstChild; //.firstChild.firstChild.firstChild;
38216 createBody : function(container)
38218 var body = document.createElement("div");
38219 Roo.id(body, "tab-body");
38220 //Roo.fly(body).addClass("x-tabs-body");
38221 Roo.fly(body).addClass("tab-content");
38222 container.appendChild(body);
38225 createItemBody :function(bodyEl, id){
38226 var body = Roo.getDom(id);
38228 body = document.createElement("div");
38231 //Roo.fly(body).addClass("x-tabs-item-body");
38232 Roo.fly(body).addClass("tab-pane");
38233 bodyEl.insertBefore(body, bodyEl.firstChild);
38237 createStripElements : function(stripEl, text, closable, tpl)
38239 var td = document.createElement("li"); // was td..
38242 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38245 stripEl.appendChild(td);
38247 td.className = "x-tabs-closable";
38248 if(!this.closeTpl){
38249 this.closeTpl = new Roo.Template(
38250 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38251 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38252 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38255 var el = this.closeTpl.overwrite(td, {"text": text});
38256 var close = el.getElementsByTagName("div")[0];
38257 var inner = el.getElementsByTagName("em")[0];
38258 return {"el": el, "close": close, "inner": inner};
38261 // not sure what this is..
38262 // if(!this.tabTpl){
38263 //this.tabTpl = new Roo.Template(
38264 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38265 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38267 // this.tabTpl = new Roo.Template(
38268 // '<a href="#">' +
38269 // '<span unselectable="on"' +
38270 // (this.disableTooltips ? '' : ' title="{text}"') +
38271 // ' >{text}</span></a>'
38277 var template = tpl || this.tabTpl || false;
38281 template = new Roo.Template(
38283 '<span unselectable="on"' +
38284 (this.disableTooltips ? '' : ' title="{text}"') +
38285 ' >{text}</span></a>'
38289 switch (typeof(template)) {
38293 template = new Roo.Template(template);
38299 var el = template.overwrite(td, {"text": text});
38301 var inner = el.getElementsByTagName("span")[0];
38303 return {"el": el, "inner": inner};
38311 * @class Roo.TabPanelItem
38312 * @extends Roo.util.Observable
38313 * Represents an individual item (tab plus body) in a TabPanel.
38314 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38315 * @param {String} id The id of this TabPanelItem
38316 * @param {String} text The text for the tab of this TabPanelItem
38317 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38319 Roo.bootstrap.panel.TabItem = function(config){
38321 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38322 * @type Roo.TabPanel
38324 this.tabPanel = config.panel;
38326 * The id for this TabPanelItem
38329 this.id = config.id;
38331 this.disabled = false;
38333 this.text = config.text;
38335 this.loaded = false;
38336 this.closable = config.closable;
38339 * The body element for this TabPanelItem.
38340 * @type Roo.Element
38342 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38343 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38344 this.bodyEl.setStyle("display", "block");
38345 this.bodyEl.setStyle("zoom", "1");
38346 //this.hideAction();
38348 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38350 this.el = Roo.get(els.el);
38351 this.inner = Roo.get(els.inner, true);
38352 this.textEl = Roo.get(this.el.dom.firstChild, true);
38353 this.pnode = Roo.get(els.el.parentNode, true);
38354 // this.el.on("mousedown", this.onTabMouseDown, this);
38355 this.el.on("click", this.onTabClick, this);
38357 if(config.closable){
38358 var c = Roo.get(els.close, true);
38359 c.dom.title = this.closeText;
38360 c.addClassOnOver("close-over");
38361 c.on("click", this.closeClick, this);
38367 * Fires when this tab becomes the active tab.
38368 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38369 * @param {Roo.TabPanelItem} this
38373 * @event beforeclose
38374 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38375 * @param {Roo.TabPanelItem} this
38376 * @param {Object} e Set cancel to true on this object to cancel the close.
38378 "beforeclose": true,
38381 * Fires when this tab is closed.
38382 * @param {Roo.TabPanelItem} this
38386 * @event deactivate
38387 * Fires when this tab is no longer the active tab.
38388 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38389 * @param {Roo.TabPanelItem} this
38391 "deactivate" : true
38393 this.hidden = false;
38395 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38398 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38400 purgeListeners : function(){
38401 Roo.util.Observable.prototype.purgeListeners.call(this);
38402 this.el.removeAllListeners();
38405 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38408 this.pnode.addClass("active");
38411 this.tabPanel.stripWrap.repaint();
38413 this.fireEvent("activate", this.tabPanel, this);
38417 * Returns true if this tab is the active tab.
38418 * @return {Boolean}
38420 isActive : function(){
38421 return this.tabPanel.getActiveTab() == this;
38425 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38428 this.pnode.removeClass("active");
38430 this.fireEvent("deactivate", this.tabPanel, this);
38433 hideAction : function(){
38434 this.bodyEl.hide();
38435 this.bodyEl.setStyle("position", "absolute");
38436 this.bodyEl.setLeft("-20000px");
38437 this.bodyEl.setTop("-20000px");
38440 showAction : function(){
38441 this.bodyEl.setStyle("position", "relative");
38442 this.bodyEl.setTop("");
38443 this.bodyEl.setLeft("");
38444 this.bodyEl.show();
38448 * Set the tooltip for the tab.
38449 * @param {String} tooltip The tab's tooltip
38451 setTooltip : function(text){
38452 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38453 this.textEl.dom.qtip = text;
38454 this.textEl.dom.removeAttribute('title');
38456 this.textEl.dom.title = text;
38460 onTabClick : function(e){
38461 e.preventDefault();
38462 this.tabPanel.activate(this.id);
38465 onTabMouseDown : function(e){
38466 e.preventDefault();
38467 this.tabPanel.activate(this.id);
38470 getWidth : function(){
38471 return this.inner.getWidth();
38474 setWidth : function(width){
38475 var iwidth = width - this.pnode.getPadding("lr");
38476 this.inner.setWidth(iwidth);
38477 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38478 this.pnode.setWidth(width);
38482 * Show or hide the tab
38483 * @param {Boolean} hidden True to hide or false to show.
38485 setHidden : function(hidden){
38486 this.hidden = hidden;
38487 this.pnode.setStyle("display", hidden ? "none" : "");
38491 * Returns true if this tab is "hidden"
38492 * @return {Boolean}
38494 isHidden : function(){
38495 return this.hidden;
38499 * Returns the text for this tab
38502 getText : function(){
38506 autoSize : function(){
38507 //this.el.beginMeasure();
38508 this.textEl.setWidth(1);
38510 * #2804 [new] Tabs in Roojs
38511 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38513 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38514 //this.el.endMeasure();
38518 * Sets the text for the tab (Note: this also sets the tooltip text)
38519 * @param {String} text The tab's text and tooltip
38521 setText : function(text){
38523 this.textEl.update(text);
38524 this.setTooltip(text);
38525 //if(!this.tabPanel.resizeTabs){
38526 // this.autoSize();
38530 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38532 activate : function(){
38533 this.tabPanel.activate(this.id);
38537 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38539 disable : function(){
38540 if(this.tabPanel.active != this){
38541 this.disabled = true;
38542 this.pnode.addClass("disabled");
38547 * Enables this TabPanelItem if it was previously disabled.
38549 enable : function(){
38550 this.disabled = false;
38551 this.pnode.removeClass("disabled");
38555 * Sets the content for this TabPanelItem.
38556 * @param {String} content The content
38557 * @param {Boolean} loadScripts true to look for and load scripts
38559 setContent : function(content, loadScripts){
38560 this.bodyEl.update(content, loadScripts);
38564 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38565 * @return {Roo.UpdateManager} The UpdateManager
38567 getUpdateManager : function(){
38568 return this.bodyEl.getUpdateManager();
38572 * Set a URL to be used to load the content for this TabPanelItem.
38573 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38574 * @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)
38575 * @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)
38576 * @return {Roo.UpdateManager} The UpdateManager
38578 setUrl : function(url, params, loadOnce){
38579 if(this.refreshDelegate){
38580 this.un('activate', this.refreshDelegate);
38582 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38583 this.on("activate", this.refreshDelegate);
38584 return this.bodyEl.getUpdateManager();
38588 _handleRefresh : function(url, params, loadOnce){
38589 if(!loadOnce || !this.loaded){
38590 var updater = this.bodyEl.getUpdateManager();
38591 updater.update(url, params, this._setLoaded.createDelegate(this));
38596 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38597 * Will fail silently if the setUrl method has not been called.
38598 * This does not activate the panel, just updates its content.
38600 refresh : function(){
38601 if(this.refreshDelegate){
38602 this.loaded = false;
38603 this.refreshDelegate();
38608 _setLoaded : function(){
38609 this.loaded = true;
38613 closeClick : function(e){
38616 this.fireEvent("beforeclose", this, o);
38617 if(o.cancel !== true){
38618 this.tabPanel.removeTab(this.id);
38622 * The text displayed in the tooltip for the close icon.
38625 closeText : "Close this tab"
38628 * This script refer to:
38629 * Title: International Telephone Input
38630 * Author: Jack O'Connor
38631 * Code version: v12.1.12
38632 * Availability: https://github.com/jackocnr/intl-tel-input.git
38635 Roo.bootstrap.PhoneInputData = function() {
38638 "Afghanistan (افغانستان)",
38643 "Albania (Shqipëri)",
38648 "Algeria (الجزائر)",
38673 "Antigua and Barbuda",
38683 "Armenia (Հայաստան)",
38699 "Austria (Österreich)",
38704 "Azerbaijan (Azərbaycan)",
38714 "Bahrain (البحرين)",
38719 "Bangladesh (বাংলাদেশ)",
38729 "Belarus (Беларусь)",
38734 "Belgium (België)",
38764 "Bosnia and Herzegovina (Босна и Херцеговина)",
38779 "British Indian Ocean Territory",
38784 "British Virgin Islands",
38794 "Bulgaria (България)",
38804 "Burundi (Uburundi)",
38809 "Cambodia (កម្ពុជា)",
38814 "Cameroon (Cameroun)",
38823 ["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"]
38826 "Cape Verde (Kabu Verdi)",
38831 "Caribbean Netherlands",
38842 "Central African Republic (République centrafricaine)",
38862 "Christmas Island",
38868 "Cocos (Keeling) Islands",
38879 "Comoros (جزر القمر)",
38884 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38889 "Congo (Republic) (Congo-Brazzaville)",
38909 "Croatia (Hrvatska)",
38930 "Czech Republic (Česká republika)",
38935 "Denmark (Danmark)",
38950 "Dominican Republic (República Dominicana)",
38954 ["809", "829", "849"]
38972 "Equatorial Guinea (Guinea Ecuatorial)",
38992 "Falkland Islands (Islas Malvinas)",
38997 "Faroe Islands (Føroyar)",
39018 "French Guiana (Guyane française)",
39023 "French Polynesia (Polynésie française)",
39038 "Georgia (საქართველო)",
39043 "Germany (Deutschland)",
39063 "Greenland (Kalaallit Nunaat)",
39100 "Guinea-Bissau (Guiné Bissau)",
39125 "Hungary (Magyarország)",
39130 "Iceland (Ísland)",
39150 "Iraq (العراق)",
39166 "Israel (ישראל)",
39193 "Jordan (الأردن)",
39198 "Kazakhstan (Казахстан)",
39219 "Kuwait (الكويت)",
39224 "Kyrgyzstan (Кыргызстан)",
39234 "Latvia (Latvija)",
39239 "Lebanon (لبنان)",
39254 "Libya (ليبيا)",
39264 "Lithuania (Lietuva)",
39279 "Macedonia (FYROM) (Македонија)",
39284 "Madagascar (Madagasikara)",
39314 "Marshall Islands",
39324 "Mauritania (موريتانيا)",
39329 "Mauritius (Moris)",
39350 "Moldova (Republica Moldova)",
39360 "Mongolia (Монгол)",
39365 "Montenegro (Crna Gora)",
39375 "Morocco (المغرب)",
39381 "Mozambique (Moçambique)",
39386 "Myanmar (Burma) (မြန်မာ)",
39391 "Namibia (Namibië)",
39406 "Netherlands (Nederland)",
39411 "New Caledonia (Nouvelle-Calédonie)",
39446 "North Korea (조선 민주주의 인민 공화국)",
39451 "Northern Mariana Islands",
39467 "Pakistan (پاکستان)",
39477 "Palestine (فلسطين)",
39487 "Papua New Guinea",
39529 "Réunion (La Réunion)",
39535 "Romania (România)",
39551 "Saint Barthélemy",
39562 "Saint Kitts and Nevis",
39572 "Saint Martin (Saint-Martin (partie française))",
39578 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39583 "Saint Vincent and the Grenadines",
39598 "São Tomé and Príncipe (São Tomé e Príncipe)",
39603 "Saudi Arabia (المملكة العربية السعودية)",
39608 "Senegal (Sénégal)",
39638 "Slovakia (Slovensko)",
39643 "Slovenia (Slovenija)",
39653 "Somalia (Soomaaliya)",
39663 "South Korea (대한민국)",
39668 "South Sudan (جنوب السودان)",
39678 "Sri Lanka (ශ්රී ලංකාව)",
39683 "Sudan (السودان)",
39693 "Svalbard and Jan Mayen",
39704 "Sweden (Sverige)",
39709 "Switzerland (Schweiz)",
39714 "Syria (سوريا)",
39759 "Trinidad and Tobago",
39764 "Tunisia (تونس)",
39769 "Turkey (Türkiye)",
39779 "Turks and Caicos Islands",
39789 "U.S. Virgin Islands",
39799 "Ukraine (Україна)",
39804 "United Arab Emirates (الإمارات العربية المتحدة)",
39826 "Uzbekistan (Oʻzbekiston)",
39836 "Vatican City (Città del Vaticano)",
39847 "Vietnam (Việt Nam)",
39852 "Wallis and Futuna (Wallis-et-Futuna)",
39857 "Western Sahara (الصحراء الغربية)",
39863 "Yemen (اليمن)",
39887 * This script refer to:
39888 * Title: International Telephone Input
39889 * Author: Jack O'Connor
39890 * Code version: v12.1.12
39891 * Availability: https://github.com/jackocnr/intl-tel-input.git
39895 * @class Roo.bootstrap.PhoneInput
39896 * @extends Roo.bootstrap.TriggerField
39897 * An input with International dial-code selection
39899 * @cfg {String} defaultDialCode default '+852'
39900 * @cfg {Array} preferedCountries default []
39903 * Create a new PhoneInput.
39904 * @param {Object} config Configuration options
39907 Roo.bootstrap.PhoneInput = function(config) {
39908 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39911 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39913 listWidth: undefined,
39915 selectedClass: 'active',
39917 invalidClass : "has-warning",
39919 validClass: 'has-success',
39921 allowed: '0123456789',
39926 * @cfg {String} defaultDialCode The default dial code when initializing the input
39928 defaultDialCode: '+852',
39931 * @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
39933 preferedCountries: false,
39935 getAutoCreate : function()
39937 var data = Roo.bootstrap.PhoneInputData();
39938 var align = this.labelAlign || this.parentLabelAlign();
39941 this.allCountries = [];
39942 this.dialCodeMapping = [];
39944 for (var i = 0; i < data.length; i++) {
39946 this.allCountries[i] = {
39950 priority: c[3] || 0,
39951 areaCodes: c[4] || null
39953 this.dialCodeMapping[c[2]] = {
39956 priority: c[3] || 0,
39957 areaCodes: c[4] || null
39969 // type: 'number', -- do not use number - we get the flaky up/down arrows.
39970 maxlength: this.max_length,
39971 cls : 'form-control tel-input',
39972 autocomplete: 'new-password'
39975 var hiddenInput = {
39978 cls: 'hidden-tel-input'
39982 hiddenInput.name = this.name;
39985 if (this.disabled) {
39986 input.disabled = true;
39989 var flag_container = {
40006 cls: this.hasFeedback ? 'has-feedback' : '',
40012 cls: 'dial-code-holder',
40019 cls: 'roo-select2-container input-group',
40026 if (this.fieldLabel.length) {
40029 tooltip: 'This field is required'
40035 cls: 'control-label',
40041 html: this.fieldLabel
40044 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40050 if(this.indicatorpos == 'right') {
40051 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40058 if(align == 'left') {
40066 if(this.labelWidth > 12){
40067 label.style = "width: " + this.labelWidth + 'px';
40069 if(this.labelWidth < 13 && this.labelmd == 0){
40070 this.labelmd = this.labelWidth;
40072 if(this.labellg > 0){
40073 label.cls += ' col-lg-' + this.labellg;
40074 input.cls += ' col-lg-' + (12 - this.labellg);
40076 if(this.labelmd > 0){
40077 label.cls += ' col-md-' + this.labelmd;
40078 container.cls += ' col-md-' + (12 - this.labelmd);
40080 if(this.labelsm > 0){
40081 label.cls += ' col-sm-' + this.labelsm;
40082 container.cls += ' col-sm-' + (12 - this.labelsm);
40084 if(this.labelxs > 0){
40085 label.cls += ' col-xs-' + this.labelxs;
40086 container.cls += ' col-xs-' + (12 - this.labelxs);
40096 var settings = this;
40098 ['xs','sm','md','lg'].map(function(size){
40099 if (settings[size]) {
40100 cfg.cls += ' col-' + size + '-' + settings[size];
40104 this.store = new Roo.data.Store({
40105 proxy : new Roo.data.MemoryProxy({}),
40106 reader : new Roo.data.JsonReader({
40117 'name' : 'dialCode',
40121 'name' : 'priority',
40125 'name' : 'areaCodes',
40132 if(!this.preferedCountries) {
40133 this.preferedCountries = [
40140 var p = this.preferedCountries.reverse();
40143 for (var i = 0; i < p.length; i++) {
40144 for (var j = 0; j < this.allCountries.length; j++) {
40145 if(this.allCountries[j].iso2 == p[i]) {
40146 var t = this.allCountries[j];
40147 this.allCountries.splice(j,1);
40148 this.allCountries.unshift(t);
40154 this.store.proxy.data = {
40156 data: this.allCountries
40162 initEvents : function()
40165 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40167 this.indicator = this.indicatorEl();
40168 this.flag = this.flagEl();
40169 this.dialCodeHolder = this.dialCodeHolderEl();
40171 this.trigger = this.el.select('div.flag-box',true).first();
40172 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40177 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40178 _this.list.setWidth(lw);
40181 this.list.on('mouseover', this.onViewOver, this);
40182 this.list.on('mousemove', this.onViewMove, this);
40183 this.inputEl().on("keyup", this.onKeyUp, this);
40184 this.inputEl().on("keypress", this.onKeyPress, this);
40186 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40188 this.view = new Roo.View(this.list, this.tpl, {
40189 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40192 this.view.on('click', this.onViewClick, this);
40193 this.setValue(this.defaultDialCode);
40196 onTriggerClick : function(e)
40198 Roo.log('trigger click');
40203 if(this.isExpanded()){
40205 this.hasFocus = false;
40207 this.store.load({});
40208 this.hasFocus = true;
40213 isExpanded : function()
40215 return this.list.isVisible();
40218 collapse : function()
40220 if(!this.isExpanded()){
40224 Roo.get(document).un('mousedown', this.collapseIf, this);
40225 Roo.get(document).un('mousewheel', this.collapseIf, this);
40226 this.fireEvent('collapse', this);
40230 expand : function()
40234 if(this.isExpanded() || !this.hasFocus){
40238 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40239 this.list.setWidth(lw);
40242 this.restrictHeight();
40244 Roo.get(document).on('mousedown', this.collapseIf, this);
40245 Roo.get(document).on('mousewheel', this.collapseIf, this);
40247 this.fireEvent('expand', this);
40250 restrictHeight : function()
40252 this.list.alignTo(this.inputEl(), this.listAlign);
40253 this.list.alignTo(this.inputEl(), this.listAlign);
40256 onViewOver : function(e, t)
40258 if(this.inKeyMode){
40261 var item = this.view.findItemFromChild(t);
40264 var index = this.view.indexOf(item);
40265 this.select(index, false);
40270 onViewClick : function(view, doFocus, el, e)
40272 var index = this.view.getSelectedIndexes()[0];
40274 var r = this.store.getAt(index);
40277 this.onSelect(r, index);
40279 if(doFocus !== false && !this.blockFocus){
40280 this.inputEl().focus();
40284 onViewMove : function(e, t)
40286 this.inKeyMode = false;
40289 select : function(index, scrollIntoView)
40291 this.selectedIndex = index;
40292 this.view.select(index);
40293 if(scrollIntoView !== false){
40294 var el = this.view.getNode(index);
40296 this.list.scrollChildIntoView(el, false);
40301 createList : function()
40303 this.list = Roo.get(document.body).createChild({
40305 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40306 style: 'display:none'
40309 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40312 collapseIf : function(e)
40314 var in_combo = e.within(this.el);
40315 var in_list = e.within(this.list);
40316 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40318 if (in_combo || in_list || is_list) {
40324 onSelect : function(record, index)
40326 if(this.fireEvent('beforeselect', this, record, index) !== false){
40328 this.setFlagClass(record.data.iso2);
40329 this.setDialCode(record.data.dialCode);
40330 this.hasFocus = false;
40332 this.fireEvent('select', this, record, index);
40336 flagEl : function()
40338 var flag = this.el.select('div.flag',true).first();
40345 dialCodeHolderEl : function()
40347 var d = this.el.select('input.dial-code-holder',true).first();
40354 setDialCode : function(v)
40356 this.dialCodeHolder.dom.value = '+'+v;
40359 setFlagClass : function(n)
40361 this.flag.dom.className = 'flag '+n;
40364 getValue : function()
40366 var v = this.inputEl().getValue();
40367 if(this.dialCodeHolder) {
40368 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40373 setValue : function(v)
40375 var d = this.getDialCode(v);
40377 //invalid dial code
40378 if(v.length == 0 || !d || d.length == 0) {
40380 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40381 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40387 this.setFlagClass(this.dialCodeMapping[d].iso2);
40388 this.setDialCode(d);
40389 this.inputEl().dom.value = v.replace('+'+d,'');
40390 this.hiddenEl().dom.value = this.getValue();
40395 getDialCode : function(v)
40399 if (v.length == 0) {
40400 return this.dialCodeHolder.dom.value;
40404 if (v.charAt(0) != "+") {
40407 var numericChars = "";
40408 for (var i = 1; i < v.length; i++) {
40409 var c = v.charAt(i);
40412 if (this.dialCodeMapping[numericChars]) {
40413 dialCode = v.substr(1, i);
40415 if (numericChars.length == 4) {
40425 this.setValue(this.defaultDialCode);
40429 hiddenEl : function()
40431 return this.el.select('input.hidden-tel-input',true).first();
40434 // after setting val
40435 onKeyUp : function(e){
40436 this.setValue(this.getValue());
40439 onKeyPress : function(e){
40440 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40447 * @class Roo.bootstrap.MoneyField
40448 * @extends Roo.bootstrap.ComboBox
40449 * Bootstrap MoneyField class
40452 * Create a new MoneyField.
40453 * @param {Object} config Configuration options
40456 Roo.bootstrap.MoneyField = function(config) {
40458 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40462 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40465 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40467 allowDecimals : true,
40469 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40471 decimalSeparator : ".",
40473 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40475 decimalPrecision : 0,
40477 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40479 allowNegative : true,
40481 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40485 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40487 minValue : Number.NEGATIVE_INFINITY,
40489 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40491 maxValue : Number.MAX_VALUE,
40493 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40495 minText : "The minimum value for this field is {0}",
40497 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40499 maxText : "The maximum value for this field is {0}",
40501 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40502 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40504 nanText : "{0} is not a valid number",
40506 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40510 * @cfg {String} defaults currency of the MoneyField
40511 * value should be in lkey
40513 defaultCurrency : false,
40515 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40517 thousandsDelimiter : false,
40519 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40530 getAutoCreate : function()
40532 var align = this.labelAlign || this.parentLabelAlign();
40544 cls : 'form-control roo-money-amount-input',
40545 autocomplete: 'new-password'
40548 var hiddenInput = {
40552 cls: 'hidden-number-input'
40555 if(this.max_length) {
40556 input.maxlength = this.max_length;
40560 hiddenInput.name = this.name;
40563 if (this.disabled) {
40564 input.disabled = true;
40567 var clg = 12 - this.inputlg;
40568 var cmd = 12 - this.inputmd;
40569 var csm = 12 - this.inputsm;
40570 var cxs = 12 - this.inputxs;
40574 cls : 'row roo-money-field',
40578 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40582 cls: 'roo-select2-container input-group',
40586 cls : 'form-control roo-money-currency-input',
40587 autocomplete: 'new-password',
40589 name : this.currencyName
40593 cls : 'input-group-addon',
40607 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40611 cls: this.hasFeedback ? 'has-feedback' : '',
40622 if (this.fieldLabel.length) {
40625 tooltip: 'This field is required'
40631 cls: 'control-label',
40637 html: this.fieldLabel
40640 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40646 if(this.indicatorpos == 'right') {
40647 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40654 if(align == 'left') {
40662 if(this.labelWidth > 12){
40663 label.style = "width: " + this.labelWidth + 'px';
40665 if(this.labelWidth < 13 && this.labelmd == 0){
40666 this.labelmd = this.labelWidth;
40668 if(this.labellg > 0){
40669 label.cls += ' col-lg-' + this.labellg;
40670 input.cls += ' col-lg-' + (12 - this.labellg);
40672 if(this.labelmd > 0){
40673 label.cls += ' col-md-' + this.labelmd;
40674 container.cls += ' col-md-' + (12 - this.labelmd);
40676 if(this.labelsm > 0){
40677 label.cls += ' col-sm-' + this.labelsm;
40678 container.cls += ' col-sm-' + (12 - this.labelsm);
40680 if(this.labelxs > 0){
40681 label.cls += ' col-xs-' + this.labelxs;
40682 container.cls += ' col-xs-' + (12 - this.labelxs);
40693 var settings = this;
40695 ['xs','sm','md','lg'].map(function(size){
40696 if (settings[size]) {
40697 cfg.cls += ' col-' + size + '-' + settings[size];
40704 initEvents : function()
40706 this.indicator = this.indicatorEl();
40708 this.initCurrencyEvent();
40710 this.initNumberEvent();
40713 initCurrencyEvent : function()
40716 throw "can not find store for combo";
40719 this.store = Roo.factory(this.store, Roo.data);
40720 this.store.parent = this;
40724 this.triggerEl = this.el.select('.input-group-addon', true).first();
40726 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40731 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40732 _this.list.setWidth(lw);
40735 this.list.on('mouseover', this.onViewOver, this);
40736 this.list.on('mousemove', this.onViewMove, this);
40737 this.list.on('scroll', this.onViewScroll, this);
40740 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40743 this.view = new Roo.View(this.list, this.tpl, {
40744 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40747 this.view.on('click', this.onViewClick, this);
40749 this.store.on('beforeload', this.onBeforeLoad, this);
40750 this.store.on('load', this.onLoad, this);
40751 this.store.on('loadexception', this.onLoadException, this);
40753 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40754 "up" : function(e){
40755 this.inKeyMode = true;
40759 "down" : function(e){
40760 if(!this.isExpanded()){
40761 this.onTriggerClick();
40763 this.inKeyMode = true;
40768 "enter" : function(e){
40771 if(this.fireEvent("specialkey", this, e)){
40772 this.onViewClick(false);
40778 "esc" : function(e){
40782 "tab" : function(e){
40785 if(this.fireEvent("specialkey", this, e)){
40786 this.onViewClick(false);
40794 doRelay : function(foo, bar, hname){
40795 if(hname == 'down' || this.scope.isExpanded()){
40796 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40804 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40808 initNumberEvent : function(e)
40810 this.inputEl().on("keydown" , this.fireKey, this);
40811 this.inputEl().on("focus", this.onFocus, this);
40812 this.inputEl().on("blur", this.onBlur, this);
40814 this.inputEl().relayEvent('keyup', this);
40816 if(this.indicator){
40817 this.indicator.addClass('invisible');
40820 this.originalValue = this.getValue();
40822 if(this.validationEvent == 'keyup'){
40823 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40824 this.inputEl().on('keyup', this.filterValidation, this);
40826 else if(this.validationEvent !== false){
40827 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40830 if(this.selectOnFocus){
40831 this.on("focus", this.preFocus, this);
40834 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40835 this.inputEl().on("keypress", this.filterKeys, this);
40837 this.inputEl().relayEvent('keypress', this);
40840 var allowed = "0123456789";
40842 if(this.allowDecimals){
40843 allowed += this.decimalSeparator;
40846 if(this.allowNegative){
40850 if(this.thousandsDelimiter) {
40854 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40856 var keyPress = function(e){
40858 var k = e.getKey();
40860 var c = e.getCharCode();
40863 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40864 allowed.indexOf(String.fromCharCode(c)) === -1
40870 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40874 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40879 this.inputEl().on("keypress", keyPress, this);
40883 onTriggerClick : function(e)
40890 this.loadNext = false;
40892 if(this.isExpanded()){
40897 this.hasFocus = true;
40899 if(this.triggerAction == 'all') {
40900 this.doQuery(this.allQuery, true);
40904 this.doQuery(this.getRawValue());
40907 getCurrency : function()
40909 var v = this.currencyEl().getValue();
40914 restrictHeight : function()
40916 this.list.alignTo(this.currencyEl(), this.listAlign);
40917 this.list.alignTo(this.currencyEl(), this.listAlign);
40920 onViewClick : function(view, doFocus, el, e)
40922 var index = this.view.getSelectedIndexes()[0];
40924 var r = this.store.getAt(index);
40927 this.onSelect(r, index);
40931 onSelect : function(record, index){
40933 if(this.fireEvent('beforeselect', this, record, index) !== false){
40935 this.setFromCurrencyData(index > -1 ? record.data : false);
40939 this.fireEvent('select', this, record, index);
40943 setFromCurrencyData : function(o)
40947 this.lastCurrency = o;
40949 if (this.currencyField) {
40950 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40952 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40955 this.lastSelectionText = currency;
40957 //setting default currency
40958 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40959 this.setCurrency(this.defaultCurrency);
40963 this.setCurrency(currency);
40966 setFromData : function(o)
40970 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40972 this.setFromCurrencyData(c);
40977 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40979 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40982 this.setValue(value);
40986 setCurrency : function(v)
40988 this.currencyValue = v;
40991 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40996 setValue : function(v)
40998 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41004 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41006 this.inputEl().dom.value = (v == '') ? '' :
41007 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41009 if(!this.allowZero && v === '0') {
41010 this.hiddenEl().dom.value = '';
41011 this.inputEl().dom.value = '';
41018 getRawValue : function()
41020 var v = this.inputEl().getValue();
41025 getValue : function()
41027 return this.fixPrecision(this.parseValue(this.getRawValue()));
41030 parseValue : function(value)
41032 if(this.thousandsDelimiter) {
41034 r = new RegExp(",", "g");
41035 value = value.replace(r, "");
41038 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41039 return isNaN(value) ? '' : value;
41043 fixPrecision : function(value)
41045 if(this.thousandsDelimiter) {
41047 r = new RegExp(",", "g");
41048 value = value.replace(r, "");
41051 var nan = isNaN(value);
41053 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41054 return nan ? '' : value;
41056 return parseFloat(value).toFixed(this.decimalPrecision);
41059 decimalPrecisionFcn : function(v)
41061 return Math.floor(v);
41064 validateValue : function(value)
41066 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41070 var num = this.parseValue(value);
41073 this.markInvalid(String.format(this.nanText, value));
41077 if(num < this.minValue){
41078 this.markInvalid(String.format(this.minText, this.minValue));
41082 if(num > this.maxValue){
41083 this.markInvalid(String.format(this.maxText, this.maxValue));
41090 validate : function()
41092 if(this.disabled || this.allowBlank){
41097 var currency = this.getCurrency();
41099 if(this.validateValue(this.getRawValue()) && currency.length){
41104 this.markInvalid();
41108 getName: function()
41113 beforeBlur : function()
41119 var v = this.parseValue(this.getRawValue());
41126 onBlur : function()
41130 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41131 //this.el.removeClass(this.focusClass);
41134 this.hasFocus = false;
41136 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41140 var v = this.getValue();
41142 if(String(v) !== String(this.startValue)){
41143 this.fireEvent('change', this, v, this.startValue);
41146 this.fireEvent("blur", this);
41149 inputEl : function()
41151 return this.el.select('.roo-money-amount-input', true).first();
41154 currencyEl : function()
41156 return this.el.select('.roo-money-currency-input', true).first();
41159 hiddenEl : function()
41161 return this.el.select('input.hidden-number-input',true).first();